@@ -333,8 +333,6 @@ static Expr *getMemberChainSubExpr(Expr *expr) {
333333 return SE->getBase ();
334334 } else if (auto *DSE = dyn_cast<DotSelfExpr>(expr)) {
335335 return DSE->getSubExpr ();
336- } else if (auto *PUE = dyn_cast<PostfixUnaryExpr>(expr)) {
337- return PUE->getOperand ();
338336 } else if (auto *CCE = dyn_cast<CodeCompletionExpr>(expr)) {
339337 return CCE->getBase ();
340338 } else {
@@ -1104,6 +1102,9 @@ class PreCheckTarget final : public ASTWalker {
11041102 // / resolution failure, or `nullptr` if transformation is not applicable.
11051103 Expr *simplifyTypeConstructionWithLiteralArg (Expr *E);
11061104
1105+ // / Pull some operator expressions into the optional chain.
1106+ OptionalEvaluationExpr *hoistOptionalEvaluationExprIfNeeded (Expr *E);
1107+
11071108 // / Whether the given expression "looks like" a (possibly sugared) type. For
11081109 // / example, `(foo, bar)` "looks like" a type, but `foo + bar` does not.
11091110 bool exprLooksLikeAType (Expr *expr);
@@ -1469,26 +1470,8 @@ class PreCheckTarget final : public ASTWalker {
14691470 return Action::Continue (result);
14701471 }
14711472
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);
14921475 }
14931476
14941477 auto *parent = Parent.getAsExpr ();
@@ -2651,6 +2634,45 @@ Expr *PreCheckTarget::simplifyTypeConstructionWithLiteralArg(Expr *E) {
26512634 : nullptr ;
26522635}
26532636
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+
26542676bool ConstraintSystem::preCheckTarget (SyntacticElementTarget &target) {
26552677 auto *DC = target.getDeclContext ();
26562678 auto &ctx = DC->getASTContext ();
0 commit comments