@@ -317,54 +317,78 @@ static bool findNonMembers(ArrayRef<LookupResultEntry> lookupResults,
317
317
return AllDeclRefs;
318
318
}
319
319
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
+
320
327
// / Find the next element in a chain of members. If this expression is (or
321
328
// / 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 ) {
323
330
assert (expr && " getMemberChainSubExpr called with null expr!" );
324
- if (auto *UDE = dyn_cast<UnresolvedDotExpr>(expr)) {
331
+ if (auto *UDE = dyn_cast<UnresolvedDotExpr>(expr))
325
332
return UDE->getBase ();
326
- } else if (auto *CE = dyn_cast<CallExpr>(expr)) {
333
+ if (auto *CE = dyn_cast<CallExpr>(expr))
327
334
return CE->getFn ();
328
- } else if (auto *BOE = dyn_cast<BindOptionalExpr>(expr)) {
335
+ if (auto *BOE = dyn_cast<BindOptionalExpr>(expr))
329
336
return BOE->getSubExpr ();
330
- } else if (auto *FVE = dyn_cast<ForceValueExpr>(expr)) {
337
+ if (auto *FVE = dyn_cast<ForceValueExpr>(expr))
331
338
return FVE->getSubExpr ();
332
- } else if (auto *SE = dyn_cast<SubscriptExpr>(expr)) {
339
+ if (auto *SE = dyn_cast<SubscriptExpr>(expr))
333
340
return SE->getBase ();
334
- } else if (auto *DSE = dyn_cast<DotSelfExpr>(expr)) {
341
+ if (auto *DSE = dyn_cast<DotSelfExpr>(expr))
335
342
return DSE->getSubExpr ();
336
- } else if (auto *USE = dyn_cast<UnresolvedSpecializeExpr>(expr)) {
343
+ if (auto *USE = dyn_cast<UnresolvedSpecializeExpr>(expr))
337
344
return USE->getSubExpr ();
338
- } else if (auto *CCE = dyn_cast<CodeCompletionExpr>(expr)) {
345
+ if (auto *CCE = dyn_cast<CodeCompletionExpr>(expr))
339
346
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 ();
342
363
}
364
+
365
+ return nullptr ;
343
366
}
344
367
345
368
UnresolvedMemberExpr *TypeChecker::getUnresolvedMemberChainBase (Expr *expr) {
346
- if (auto *subExpr = getMemberChainSubExpr (expr))
369
+ if (auto *subExpr =
370
+ getMemberChainSubExpr (expr, MemberChainKind::UnresolvedMember)) {
347
371
return getUnresolvedMemberChainBase (subExpr);
348
- else
349
- return dyn_cast<UnresolvedMemberExpr>(expr);
372
+ }
373
+ return dyn_cast<UnresolvedMemberExpr>(expr);
350
374
}
351
375
352
376
static bool isBindOptionalMemberChain (Expr *expr) {
353
- if (isa<BindOptionalExpr>(expr)) {
377
+ if (isa<BindOptionalExpr>(expr))
354
378
return true ;
355
- } else if (auto *base = getMemberChainSubExpr (expr)) {
379
+
380
+ if (auto *base = getMemberChainSubExpr (expr, MemberChainKind::OptionalBind))
356
381
return isBindOptionalMemberChain (base);
357
- } else {
358
- return false ;
359
- }
382
+
383
+ return false ;
360
384
}
361
385
362
386
// / 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 ) {
364
388
assert (expr && " isMemberChainTail called with null expr!" );
365
389
// If this expression's parent is not itself part of a chain (or, this expr
366
390
// 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;
368
392
}
369
393
370
394
static bool isValidForwardReference (ValueDecl *D, DeclContext *DC,
@@ -1092,6 +1116,10 @@ class PreCheckTarget final : public ASTWalker {
1092
1116
// / Pull some operator expressions into the optional chain.
1093
1117
OptionalEvaluationExpr *hoistOptionalEvaluationExprIfNeeded (Expr *E);
1094
1118
1119
+ // / Wrap an unresolved member or optional bind chain in an
1120
+ // / UnresolvedMemberChainResultExpr or OptionalEvaluationExpr respectively.
1121
+ Expr *wrapMemberChainIfNeeded (Expr *E);
1122
+
1095
1123
// / Whether the given expression "looks like" a (possibly sugared) type. For
1096
1124
// / example, `(foo, bar)` "looks like" a type, but `foo + bar` does not.
1097
1125
bool exprLooksLikeAType (Expr *expr);
@@ -1464,24 +1492,8 @@ class PreCheckTarget final : public ASTWalker {
1464
1492
return Action::Continue (OEE);
1465
1493
}
1466
1494
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
+
1485
1497
return Action::Continue (expr);
1486
1498
}
1487
1499
@@ -2653,7 +2665,6 @@ Expr *PreCheckTarget::simplifyTypeConstructionWithLiteralArg(Expr *E) {
2653
2665
// /
2654
2666
// / foo? = newFoo // LHS of the assignment operator
2655
2667
// / foo?.bar += value // LHS of 'assignment: true' precedence group operators.
2656
- // / for?.bar++ // Postfix operator.
2657
2668
// /
2658
2669
// / In such cases, the operand is constructed to be an 'OperatorEvaluationExpr'
2659
2670
// / wrapping the actual operand. This function hoist it and wraps the entire
@@ -2678,16 +2689,34 @@ PreCheckTarget::hoistOptionalEvaluationExprIfNeeded(Expr *expr) {
2678
2689
}
2679
2690
}
2680
2691
}
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
- }
2687
2692
}
2688
2693
return nullptr ;
2689
2694
}
2690
2695
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
+
2691
2720
bool ConstraintSystem::preCheckTarget (SyntacticElementTarget &target) {
2692
2721
auto *DC = target.getDeclContext ();
2693
2722
auto &ctx = DC->getASTContext ();
0 commit comments