It doesn't seem like it's possible.
Here is the compiler code for parsing a key expression:
/// expr-keypath: /// '#keyPath' '(' unqualified-name ('.' unqualified-name) * ')' /// ParserResult<Expr> Parser::parseExprKeyPath() { // Consume '#keyPath'. SourceLoc keywordLoc = consumeToken(tok::pound_keyPath); // Parse the leading '('. if (!Tok.is(tok::l_paren)) { diagnose(Tok, diag::expr_keypath_expected_lparen); return makeParserError(); } SourceLoc lParenLoc = consumeToken(tok::l_paren); // Handle code completion. SmallVector<Identifier, 4> names; SmallVector<SourceLoc, 4> nameLocs; auto handleCodeCompletion = [&](bool hasDot) -> ParserResult<Expr> { ObjCKeyPathExpr *expr = nullptr; if (!names.empty()) { expr = ObjCKeyPathExpr::create(Context, keywordLoc, lParenLoc, names, nameLocs, Tok.getLoc()); } if (CodeCompletion) CodeCompletion->completeExprKeyPath(expr, hasDot); // Eat the code completion token because we handled it. consumeToken(tok::code_complete); return makeParserCodeCompletionResult(expr); }; // Parse the sequence of unqualified-names. ParserStatus status; while (true) { // Handle code completion. if (Tok.is(tok::code_complete)) return handleCodeCompletion(!names.empty()); // Parse the next name. DeclNameLoc nameLoc; bool afterDot = !names.empty(); auto name = parseUnqualifiedDeclName( afterDot, nameLoc, diag::expr_keypath_expected_property_or_type); if (!name) { status.setIsParseError(); break; } // Cannot use compound names here. if (name.isCompoundName()) { diagnose(nameLoc.getBaseNameLoc(), diag::expr_keypath_compound_name, name) .fixItReplace(nameLoc.getSourceRange(), name.getBaseName().str()); } // Record the name we parsed. names.push_back(name.getBaseName()); nameLocs.push_back(nameLoc.getBaseNameLoc()); // Handle code completion. if (Tok.is(tok::code_complete)) return handleCodeCompletion(false); // Parse the next period to continue the path. if (consumeIf(tok::period)) continue; break; } // Parse the closing ')'. SourceLoc rParenLoc; if (status.isError()) { skipUntilDeclStmtRBrace(tok::r_paren); if (Tok.is(tok::r_paren)) rParenLoc = consumeToken(); else rParenLoc = PreviousLoc; } else { parseMatchingToken(tok::r_paren, rParenLoc, diag::expr_keypath_expected_rparen, lParenLoc); } // If we cannot build a useful expression, just return an error // expression. if (names.empty() || status.isError()) { return makeParserResult<Expr>( new (Context) ErrorExpr(SourceRange(keywordLoc, rParenLoc))); } // We're done: create the key-path expression. return makeParserResult<Expr>( ObjCKeyPathExpr::create(Context, keywordLoc, lParenLoc, names, nameLocs, rParenLoc)); }
This code first creates a list of period-separated names inside parentheses, and then tries to parse them as an expression. It takes an expression, not data of any Swift type; It takes a code, not data.
source share