@@ -331,6 +331,8 @@ static Expr *getMemberChainSubExpr(Expr *expr) {
331331 return FVE->getSubExpr ();
332332 } else if (auto *SE = dyn_cast<SubscriptExpr>(expr)) {
333333 return SE->getBase ();
334+ } else if (auto *DSE = dyn_cast<DotSelfExpr>(expr)) {
335+ return DSE->getSubExpr ();
334336 } else if (auto *CCE = dyn_cast<CodeCompletionExpr>(expr)) {
335337 return CCE->getBase ();
336338 } else {
@@ -345,6 +347,16 @@ UnresolvedMemberExpr *TypeChecker::getUnresolvedMemberChainBase(Expr *expr) {
345347 return dyn_cast<UnresolvedMemberExpr>(expr);
346348}
347349
350+ static bool isBindOptionalMemberChain (Expr *expr) {
351+ if (isa<BindOptionalExpr>(expr)) {
352+ return true ;
353+ } else if (auto *base = getMemberChainSubExpr (expr)) {
354+ return isBindOptionalMemberChain (base);
355+ } else {
356+ return false ;
357+ }
358+ }
359+
348360// / Whether this expression sits at the end of a chain of member accesses.
349361static bool isMemberChainTail (Expr *expr, Expr *parent) {
350362 assert (expr && " isMemberChainTail called with null expr!" );
@@ -1090,6 +1102,9 @@ class PreCheckTarget final : public ASTWalker {
10901102 // / resolution failure, or `nullptr` if transformation is not applicable.
10911103 Expr *simplifyTypeConstructionWithLiteralArg (Expr *E);
10921104
1105+ // / Pull some operator expressions into the optional chain.
1106+ OptionalEvaluationExpr *hoistOptionalEvaluationExprIfNeeded (Expr *E);
1107+
10931108 // / Whether the given expression "looks like" a (possibly sugared) type. For
10941109 // / example, `(foo, bar)` "looks like" a type, but `foo + bar` does not.
10951110 bool exprLooksLikeAType (Expr *expr);
@@ -1416,22 +1431,6 @@ class PreCheckTarget final : public ASTWalker {
14161431 return Action::Continue (expr);
14171432 }
14181433
1419- // Double check if there are any BindOptionalExpr remaining in the
1420- // tree (see comment below for more details), if there are no BOE
1421- // expressions remaining remove OptionalEvaluationExpr from the tree.
1422- if (auto OEE = dyn_cast<OptionalEvaluationExpr>(expr)) {
1423- bool hasBindOptional = false ;
1424- OEE->forEachChildExpr ([&](Expr *expr) -> Expr * {
1425- if (isa<BindOptionalExpr>(expr))
1426- hasBindOptional = true ;
1427- // If at least a single BOE was found, no reason
1428- // to walk any further in the tree.
1429- return hasBindOptional ? nullptr : expr;
1430- });
1431-
1432- return Action::Continue (hasBindOptional ? OEE : OEE->getSubExpr ());
1433- }
1434-
14351434 // Check if there are any BindOptionalExpr in the tree which
14361435 // wrap DiscardAssignmentExpr, such situation corresponds to syntax
14371436 // like - `_? = <value>`, since it doesn't really make
@@ -1471,16 +1470,27 @@ class PreCheckTarget final : public ASTWalker {
14711470 return Action::Continue (result);
14721471 }
14731472
1474- // If we find an unresolved member chain, wrap it in an
1475- // UnresolvedMemberChainResultExpr (unless this has already been done).
1473+ if (auto *OEE = hoistOptionalEvaluationExprIfNeeded (expr)) {
1474+ return Action::Continue (OEE);
1475+ }
1476+
14761477 auto *parent = Parent.getAsExpr ();
14771478 if (isMemberChainTail (expr, parent)) {
1479+ Expr *wrapped = expr;
1480+ // If we find an unresolved member chain, wrap it in an
1481+ // UnresolvedMemberChainResultExpr (unless this has already been done).
14781482 if (auto *UME = TypeChecker::getUnresolvedMemberChainBase (expr)) {
14791483 if (!parent || !isa<UnresolvedMemberChainResultExpr>(parent)) {
1480- auto *chain = new (ctx) UnresolvedMemberChainResultExpr (expr, UME);
1481- return Action::Continue (chain);
1484+ wrapped = new (ctx) UnresolvedMemberChainResultExpr (expr, UME);
14821485 }
14831486 }
1487+ // Wrap optional chain in an OptionalEvaluationExpr.
1488+ if (isBindOptionalMemberChain (expr)) {
1489+ if (!parent || !isa<OptionalEvaluationExpr>(parent)) {
1490+ wrapped = new (ctx) OptionalEvaluationExpr (wrapped);
1491+ }
1492+ }
1493+ expr = wrapped;
14841494 }
14851495 return Action::Continue (expr);
14861496 }
@@ -2624,6 +2634,45 @@ Expr *PreCheckTarget::simplifyTypeConstructionWithLiteralArg(Expr *E) {
26242634 : nullptr ;
26252635}
26262636
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+
26272676bool ConstraintSystem::preCheckTarget (SyntacticElementTarget &target) {
26282677 auto *DC = target.getDeclContext ();
26292678 auto &ctx = DC->getASTContext ();
0 commit comments