@@ -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,
@@ -2641,7 +2665,6 @@ Expr *PreCheckTarget::simplifyTypeConstructionWithLiteralArg(Expr *E) {
26412665// /
26422666// / foo? = newFoo // LHS of the assignment operator
26432667// / foo?.bar += value // LHS of 'assignment: true' precedence group operators.
2644- // / for?.bar++ // Postfix operator.
26452668// /
26462669// / In such cases, the operand is constructed to be an 'OperatorEvaluationExpr'
26472670// / wrapping the actual operand. This function hoist it and wraps the entire
@@ -2666,12 +2689,6 @@ PreCheckTarget::hoistOptionalEvaluationExprIfNeeded(Expr *expr) {
26662689 }
26672690 }
26682691 }
2669- } else if (auto *postfixE = dyn_cast<PostfixUnaryExpr>(expr)) {
2670- if (auto *OEE = dyn_cast<OptionalEvaluationExpr>(postfixE->getOperand ())) {
2671- postfixE->setOperand (OEE->getSubExpr ());
2672- OEE->setSubExpr (postfixE);
2673- return OEE;
2674- }
26752692 }
26762693 return nullptr ;
26772694}
@@ -2680,18 +2697,21 @@ Expr *PreCheckTarget::wrapMemberChainIfNeeded(Expr *E) {
26802697 auto *parent = Parent.getAsExpr ();
26812698 Expr *wrapped = E;
26822699
2683- if (!isMemberChainTail (E, parent))
2700+ // If the parent is already wrapped, we've already formed the member chain.
2701+ if (parent && (isa<OptionalEvaluationExpr>(parent) ||
2702+ isa<UnresolvedMemberChainResultExpr>(parent))) {
26842703 return E;
2704+ }
26852705
26862706 // If we find an unresolved member chain, wrap it in an
2687- // UnresolvedMemberChainResultExpr (unless this has already been done) .
2688- if (auto *UME = TypeChecker::getUnresolvedMemberChainBase (E )) {
2689- if (!parent || !isa<UnresolvedMemberChainResultExpr>(parent ))
2707+ // UnresolvedMemberChainResultExpr.
2708+ if (isMemberChainTail (E, parent, MemberChainKind::UnresolvedMember )) {
2709+ if (auto *UME = TypeChecker::getUnresolvedMemberChainBase (E ))
26902710 wrapped = new (Ctx) UnresolvedMemberChainResultExpr (E, UME);
26912711 }
26922712 // Wrap optional chain in an OptionalEvaluationExpr.
2693- if (isBindOptionalMemberChain (E )) {
2694- if (!parent || !isa<OptionalEvaluationExpr>(parent ))
2713+ if (isMemberChainTail (E, parent, MemberChainKind::OptionalBind )) {
2714+ if (isBindOptionalMemberChain (E ))
26952715 wrapped = new (Ctx) OptionalEvaluationExpr (wrapped);
26962716 }
26972717 return wrapped;
0 commit comments