@@ -317,54 +317,78 @@ static bool findNonMembers(ArrayRef<LookupResultEntry> lookupResults,
317317 return AllDeclRefs;
318318}
319319
320+ namespace {
321+ enum class MemberChainKind {
322+ OptionalBind, // A 'x?.y' optional binding chain
323+ UnresolvedMember, // A '.foo.bar' chain
324+ };
325+ } // end anonymous namespace
326+
320327// / Find the next element in a chain of members. If this expression is (or
321328// / could be) the base of such a chain, this will return \c nullptr.
322- static Expr *getMemberChainSubExpr (Expr *expr) {
329+ static Expr *getMemberChainSubExpr (Expr *expr, MemberChainKind kind ) {
323330 assert (expr && " getMemberChainSubExpr called with null expr!" );
324- if (auto *UDE = dyn_cast<UnresolvedDotExpr>(expr)) {
331+ if (auto *UDE = dyn_cast<UnresolvedDotExpr>(expr))
325332 return UDE->getBase ();
326- } else if (auto *CE = dyn_cast<CallExpr>(expr)) {
333+ if (auto *CE = dyn_cast<CallExpr>(expr))
327334 return CE->getFn ();
328- } else if (auto *BOE = dyn_cast<BindOptionalExpr>(expr)) {
335+ if (auto *BOE = dyn_cast<BindOptionalExpr>(expr))
329336 return BOE->getSubExpr ();
330- } else if (auto *FVE = dyn_cast<ForceValueExpr>(expr)) {
337+ if (auto *FVE = dyn_cast<ForceValueExpr>(expr))
331338 return FVE->getSubExpr ();
332- } else if (auto *SE = dyn_cast<SubscriptExpr>(expr)) {
339+ if (auto *SE = dyn_cast<SubscriptExpr>(expr))
333340 return SE->getBase ();
334- } else if (auto *DSE = dyn_cast<DotSelfExpr>(expr)) {
341+ if (auto *DSE = dyn_cast<DotSelfExpr>(expr))
335342 return DSE->getSubExpr ();
336- } else if (auto *USE = dyn_cast<UnresolvedSpecializeExpr>(expr)) {
343+ if (auto *USE = dyn_cast<UnresolvedSpecializeExpr>(expr))
337344 return USE->getSubExpr ();
338- } else if (auto *CCE = dyn_cast<CodeCompletionExpr>(expr)) {
345+ if (auto *CCE = dyn_cast<CodeCompletionExpr>(expr))
339346 return CCE->getBase ();
340- } else {
341- return nullptr ;
347+
348+ if (kind == MemberChainKind::OptionalBind) {
349+ // We allow postfix operators to be part of the optional member chain, e.g:
350+ //
351+ // for?.bar++
352+ // x.y?^.foo()
353+ //
354+ // Note this behavior is specific to optional chains, we treat e.g
355+ // `.foo^` as `(.foo)^`.
356+ if (auto *PO = dyn_cast<PostfixUnaryExpr>(expr))
357+ return PO->getOperand ();
358+
359+ // Unresolved member chains can themselves be nested in optional chains
360+ // since optional chains can include postfix operators.
361+ if (auto *UME = dyn_cast<UnresolvedMemberChainResultExpr>(expr))
362+ return UME->getSubExpr ();
342363 }
364+
365+ return nullptr ;
343366}
344367
345368UnresolvedMemberExpr *TypeChecker::getUnresolvedMemberChainBase (Expr *expr) {
346- if (auto *subExpr = getMemberChainSubExpr (expr))
369+ if (auto *subExpr =
370+ getMemberChainSubExpr (expr, MemberChainKind::UnresolvedMember)) {
347371 return getUnresolvedMemberChainBase (subExpr);
348- else
349- return dyn_cast<UnresolvedMemberExpr>(expr);
372+ }
373+ return dyn_cast<UnresolvedMemberExpr>(expr);
350374}
351375
352376static bool isBindOptionalMemberChain (Expr *expr) {
353- if (isa<BindOptionalExpr>(expr)) {
377+ if (isa<BindOptionalExpr>(expr))
354378 return true ;
355- } else if (auto *base = getMemberChainSubExpr (expr)) {
379+
380+ if (auto *base = getMemberChainSubExpr (expr, MemberChainKind::OptionalBind))
356381 return isBindOptionalMemberChain (base);
357- } else {
358- return false ;
359- }
382+
383+ return false ;
360384}
361385
362386// / Whether this expression sits at the end of a chain of member accesses.
363- static bool isMemberChainTail (Expr *expr, Expr *parent) {
387+ static bool isMemberChainTail (Expr *expr, Expr *parent, MemberChainKind kind ) {
364388 assert (expr && " isMemberChainTail called with null expr!" );
365389 // If this expression's parent is not itself part of a chain (or, this expr
366390 // has no parent expr), this must be the tail of the chain.
367- return !parent || getMemberChainSubExpr (parent) != expr;
391+ return !parent || getMemberChainSubExpr (parent, kind ) != expr;
368392}
369393
370394static bool isValidForwardReference (ValueDecl *D, DeclContext *DC,
@@ -1092,6 +1116,10 @@ class PreCheckTarget final : public ASTWalker {
10921116 // / Pull some operator expressions into the optional chain.
10931117 OptionalEvaluationExpr *hoistOptionalEvaluationExprIfNeeded (Expr *E);
10941118
1119+ // / Wrap an unresolved member or optional bind chain in an
1120+ // / UnresolvedMemberChainResultExpr or OptionalEvaluationExpr respectively.
1121+ Expr *wrapMemberChainIfNeeded (Expr *E);
1122+
10951123 // / Whether the given expression "looks like" a (possibly sugared) type. For
10961124 // / example, `(foo, bar)` "looks like" a type, but `foo + bar` does not.
10971125 bool exprLooksLikeAType (Expr *expr);
@@ -1464,24 +1492,8 @@ class PreCheckTarget final : public ASTWalker {
14641492 return Action::Continue (OEE);
14651493 }
14661494
1467- auto *parent = Parent.getAsExpr ();
1468- if (isMemberChainTail (expr, parent)) {
1469- Expr *wrapped = expr;
1470- // If we find an unresolved member chain, wrap it in an
1471- // UnresolvedMemberChainResultExpr (unless this has already been done).
1472- if (auto *UME = TypeChecker::getUnresolvedMemberChainBase (expr)) {
1473- if (!parent || !isa<UnresolvedMemberChainResultExpr>(parent)) {
1474- wrapped = new (ctx) UnresolvedMemberChainResultExpr (expr, UME);
1475- }
1476- }
1477- // Wrap optional chain in an OptionalEvaluationExpr.
1478- if (isBindOptionalMemberChain (expr)) {
1479- if (!parent || !isa<OptionalEvaluationExpr>(parent)) {
1480- wrapped = new (ctx) OptionalEvaluationExpr (wrapped);
1481- }
1482- }
1483- expr = wrapped;
1484- }
1495+ expr = wrapMemberChainIfNeeded (expr);
1496+
14851497 return Action::Continue (expr);
14861498 }
14871499
@@ -2653,7 +2665,6 @@ Expr *PreCheckTarget::simplifyTypeConstructionWithLiteralArg(Expr *E) {
26532665// /
26542666// / foo? = newFoo // LHS of the assignment operator
26552667// / foo?.bar += value // LHS of 'assignment: true' precedence group operators.
2656- // / for?.bar++ // Postfix operator.
26572668// /
26582669// / In such cases, the operand is constructed to be an 'OperatorEvaluationExpr'
26592670// / wrapping the actual operand. This function hoist it and wraps the entire
@@ -2678,16 +2689,34 @@ PreCheckTarget::hoistOptionalEvaluationExprIfNeeded(Expr *expr) {
26782689 }
26792690 }
26802691 }
2681- } else if (auto *postfixE = dyn_cast<PostfixUnaryExpr>(expr)) {
2682- if (auto *OEE = dyn_cast<OptionalEvaluationExpr>(postfixE->getOperand ())) {
2683- postfixE->setOperand (OEE->getSubExpr ());
2684- OEE->setSubExpr (postfixE);
2685- return OEE;
2686- }
26872692 }
26882693 return nullptr ;
26892694}
26902695
2696+ Expr *PreCheckTarget::wrapMemberChainIfNeeded (Expr *E) {
2697+ auto *parent = Parent.getAsExpr ();
2698+ Expr *wrapped = E;
2699+
2700+ // If the parent is already wrapped, we've already formed the member chain.
2701+ if (parent && (isa<OptionalEvaluationExpr>(parent) ||
2702+ isa<UnresolvedMemberChainResultExpr>(parent))) {
2703+ return E;
2704+ }
2705+
2706+ // If we find an unresolved member chain, wrap it in an
2707+ // UnresolvedMemberChainResultExpr.
2708+ if (isMemberChainTail (E, parent, MemberChainKind::UnresolvedMember)) {
2709+ if (auto *UME = TypeChecker::getUnresolvedMemberChainBase (E))
2710+ wrapped = new (Ctx) UnresolvedMemberChainResultExpr (E, UME);
2711+ }
2712+ // Wrap optional chain in an OptionalEvaluationExpr.
2713+ if (isMemberChainTail (E, parent, MemberChainKind::OptionalBind)) {
2714+ if (isBindOptionalMemberChain (E))
2715+ wrapped = new (Ctx) OptionalEvaluationExpr (wrapped);
2716+ }
2717+ return wrapped;
2718+ }
2719+
26912720bool ConstraintSystem::preCheckTarget (SyntacticElementTarget &target) {
26922721 auto *DC = target.getDeclContext ();
26932722 auto &ctx = DC->getASTContext ();
0 commit comments