@@ -1087,6 +1087,9 @@ Parser::parseExprPostfixSuffix(ParserResult<Expr> Result, bool isExprBasic,
1087
1087
if (Result.isNull ())
1088
1088
return Result;
1089
1089
1090
+ if (InPoundIfEnvironment && Tok.isAtStartOfLine ())
1091
+ return Result;
1092
+
1090
1093
if (Result.hasCodeCompletion () &&
1091
1094
SourceMgr.getCodeCompletionLoc () == PreviousLoc) {
1092
1095
// Don't parse suffixes if the expression ended with code completion
@@ -1305,6 +1308,95 @@ Parser::parseExprPostfixSuffix(ParserResult<Expr> Result, bool isExprBasic,
1305
1308
continue ;
1306
1309
}
1307
1310
1311
+ if (Tok.is (tok::pound_if)) {
1312
+
1313
+ // Helper function to see if we can parse member reference like suffixes
1314
+ // inside '#if'.
1315
+ auto isAtStartOfPostfixExprSuffix = [&]() {
1316
+ if (!Tok.isAny (tok::period, tok::period_prefix)) {
1317
+ return false ;
1318
+ }
1319
+ if (!peekToken ().isAny (tok::identifier, tok::kw_Self, tok::kw_self,
1320
+ tok::integer_literal, tok::code_complete) &&
1321
+ !peekToken ().isKeyword ()) {
1322
+ return false ;
1323
+ }
1324
+ return true ;
1325
+ };
1326
+
1327
+ // Check if the first '#if' body starts with '.' <identifier>, and parse
1328
+ // it as a "postfix ifconfig expression".
1329
+ bool isPostfixIfConfigExpr = false ;
1330
+ {
1331
+ llvm::SaveAndRestore<Optional<StableHasher>> H (CurrentTokenHash, None);
1332
+ Parser::BacktrackingScope Backtrack (*this );
1333
+ // Skip to the first body. We may need to skip multiple '#if' directives
1334
+ // since we support nested '#if's. e.g.
1335
+ // baseExpr
1336
+ // #if CONDITION_1
1337
+ // #if CONDITION_2
1338
+ // .someMember
1339
+ do {
1340
+ consumeToken (tok::pound_if);
1341
+ skipUntilTokenOrEndOfLine (tok::NUM_TOKENS);
1342
+ } while (Tok.is (tok::pound_if));
1343
+ isPostfixIfConfigExpr = isAtStartOfPostfixExprSuffix ();
1344
+ }
1345
+ if (!isPostfixIfConfigExpr)
1346
+ break ;
1347
+
1348
+ if (!Tok.isAtStartOfLine ()) {
1349
+ diagnose (Tok, diag::statement_same_line_without_newline)
1350
+ .fixItInsert (getEndOfPreviousLoc (), " \n " );
1351
+ }
1352
+
1353
+ llvm::SmallPtrSet<Expr *, 4 > exprsWithBindOptional;
1354
+ auto ICD =
1355
+ parseIfConfig ([&](SmallVectorImpl<ASTNode> &elements, bool isActive) {
1356
+ SyntaxParsingContext postfixCtx (SyntaxContext,
1357
+ SyntaxContextKind::Expr);
1358
+ // Although we know the '#if' body starts with period,
1359
+ // '#elseif'/'#else' bodies might start with invalid tokens.
1360
+ if (isAtStartOfPostfixExprSuffix () || Tok.is (tok::pound_if)) {
1361
+ bool exprHasBindOptional = false ;
1362
+ auto expr = parseExprPostfixSuffix (Result, isExprBasic,
1363
+ periodHasKeyPathBehavior,
1364
+ exprHasBindOptional);
1365
+ if (exprHasBindOptional)
1366
+ exprsWithBindOptional.insert (expr.get ());
1367
+ elements.push_back (expr.get ());
1368
+ }
1369
+
1370
+ // Don't allow any character other than the postfix expression.
1371
+ if (!Tok.isAny (tok::pound_elseif, tok::pound_else, tok::pound_endif,
1372
+ tok::eof)) {
1373
+ diagnose (Tok, diag::expr_postfix_ifconfig_unexpectedtoken);
1374
+ skipUntilConditionalBlockClose ();
1375
+ }
1376
+ });
1377
+ if (ICD.isNull ())
1378
+ break ;
1379
+
1380
+ SyntaxContext->createNodeInPlace (SyntaxKind::PostfixIfConfigExpr);
1381
+
1382
+ auto activeElements = ICD.get ()->getActiveClauseElements ();
1383
+ if (activeElements.empty ())
1384
+ // There's no active clause, or it was empty. Keep the current result.
1385
+ continue ;
1386
+
1387
+ // Extract the parsed expression as the result.
1388
+ assert (activeElements.size () == 1 && activeElements[0 ].is <Expr *>());
1389
+ auto expr = activeElements[0 ].get <Expr *>();
1390
+ ParserStatus status (ICD);
1391
+ if (SourceMgr.getCodeCompletionLoc ().isValid () &&
1392
+ SourceMgr.rangeContainsTokenLoc (expr->getSourceRange (),
1393
+ SourceMgr.getCodeCompletionLoc ()))
1394
+ status.setHasCodeCompletion ();
1395
+ hasBindOptional |= exprsWithBindOptional.contains (expr);
1396
+ Result = makeParserResult (status, expr);
1397
+ continue ;
1398
+ }
1399
+
1308
1400
if (Tok.is (tok::code_complete)) {
1309
1401
if (InSwiftKeyPath)
1310
1402
return Result;
0 commit comments