@@ -333,8 +333,6 @@ static Expr *getMemberChainSubExpr(Expr *expr) {
333
333
return SE->getBase ();
334
334
} else if (auto *DSE = dyn_cast<DotSelfExpr>(expr)) {
335
335
return DSE->getSubExpr ();
336
- } else if (auto *PUE = dyn_cast<PostfixUnaryExpr>(expr)) {
337
- return PUE->getOperand ();
338
336
} else if (auto *CCE = dyn_cast<CodeCompletionExpr>(expr)) {
339
337
return CCE->getBase ();
340
338
} else {
@@ -1104,6 +1102,9 @@ class PreCheckTarget final : public ASTWalker {
1104
1102
// / resolution failure, or `nullptr` if transformation is not applicable.
1105
1103
Expr *simplifyTypeConstructionWithLiteralArg (Expr *E);
1106
1104
1105
+ // / Pull some operator expressions into the optional chain.
1106
+ OptionalEvaluationExpr *hoistOptionalEvaluationExprIfNeeded (Expr *E);
1107
+
1107
1108
// / Whether the given expression "looks like" a (possibly sugared) type. For
1108
1109
// / example, `(foo, bar)` "looks like" a type, but `foo + bar` does not.
1109
1110
bool exprLooksLikeAType (Expr *expr);
@@ -1469,26 +1470,8 @@ class PreCheckTarget final : public ASTWalker {
1469
1470
return Action::Continue (result);
1470
1471
}
1471
1472
1472
- // If this is an assignment operator, and the left operand is an optional
1473
- // evaluation, pull the operator into the chain.
1474
- if (auto *binExpr = dyn_cast<BinaryExpr>(expr)) {
1475
- if (auto *OEE = dyn_cast<OptionalEvaluationExpr>(binExpr->getLHS ())) {
1476
- if (auto *precedence =
1477
- TypeChecker::lookupPrecedenceGroupForInfixOperator (
1478
- DC, binExpr, /* diagnose=*/ false )) {
1479
- if (precedence->isAssignment ()) {
1480
- binExpr->getArgs ()->setExpr (0 , OEE->getSubExpr ());
1481
- OEE->setSubExpr (binExpr);
1482
- return Action::Continue (OEE);
1483
- }
1484
- }
1485
- }
1486
- } else if (auto *assignExpr = dyn_cast<AssignExpr>(expr)) {
1487
- if (auto *OEE = dyn_cast<OptionalEvaluationExpr>(assignExpr->getDest ())) {
1488
- assignExpr->setDest (OEE->getSubExpr ());
1489
- OEE->setSubExpr (assignExpr);
1490
- return Action::Continue (OEE);
1491
- }
1473
+ if (auto *OEE = hoistOptionalEvaluationExprIfNeeded (expr)) {
1474
+ return Action::Continue (OEE);
1492
1475
}
1493
1476
1494
1477
auto *parent = Parent.getAsExpr ();
@@ -2651,6 +2634,45 @@ Expr *PreCheckTarget::simplifyTypeConstructionWithLiteralArg(Expr *E) {
2651
2634
: nullptr ;
2652
2635
}
2653
2636
2637
+ // / Pull some operator expressions into the optional chain if needed.
2638
+ // /
2639
+ // / foo? = newFoo // LHS of the assignment operator
2640
+ // / foo?.bar += value // LHS of 'assignment: true' precedence group operators.
2641
+ // / for?.bar++ // Postfix operator.
2642
+ // /
2643
+ // / In such cases, the operand is constructed to be an 'OperatorEvaluationExpr'
2644
+ // / wrapping the actual operand. This function hoist it and wraps the entire
2645
+ // / expression with it. Returns the result 'OperatorEvaluationExpr', or nullptr
2646
+ // / if 'expr' didn't match the condition.
2647
+ OptionalEvaluationExpr *
2648
+ PreCheckTarget::hoistOptionalEvaluationExprIfNeeded (Expr *expr) {
2649
+ if (auto *assignE = dyn_cast<AssignExpr>(expr)) {
2650
+ if (auto *OEE = dyn_cast<OptionalEvaluationExpr>(assignE->getDest ())) {
2651
+ assignE->setDest (OEE->getSubExpr ());
2652
+ OEE->setSubExpr (assignE);
2653
+ return OEE;
2654
+ }
2655
+ } else if (auto *binaryE = dyn_cast<BinaryExpr>(expr)) {
2656
+ if (auto *OEE = dyn_cast<OptionalEvaluationExpr>(binaryE->getLHS ())) {
2657
+ if (auto *precedence = TypeChecker::lookupPrecedenceGroupForInfixOperator (
2658
+ DC, binaryE, /* diagnose=*/ false )) {
2659
+ if (precedence->isAssignment ()) {
2660
+ binaryE->getArgs ()->setExpr (0 , OEE->getSubExpr ());
2661
+ OEE->setSubExpr (binaryE);
2662
+ return OEE;
2663
+ }
2664
+ }
2665
+ }
2666
+ } else if (auto *postfixE = dyn_cast<PostfixUnaryExpr>(expr)) {
2667
+ if (auto *OEE = dyn_cast<OptionalEvaluationExpr>(postfixE->getOperand ())) {
2668
+ postfixE->setOperand (OEE->getSubExpr ());
2669
+ OEE->setSubExpr (postfixE);
2670
+ return OEE;
2671
+ }
2672
+ }
2673
+ return nullptr ;
2674
+ }
2675
+
2654
2676
bool ConstraintSystem::preCheckTarget (SyntacticElementTarget &target) {
2655
2677
auto *DC = target.getDeclContext ();
2656
2678
auto &ctx = DC->getASTContext ();
0 commit comments