@@ -231,12 +231,19 @@ class ASTScopeDeclConsumerForUnqualifiedLookup
231
231
: public AbstractASTScopeDeclConsumer {
232
232
UnqualifiedLookupFactory &factory;
233
233
234
+ // / The 'self' parameter from the innermost scope containing the lookup
235
+ // / location to be used when an instance member of a type is accessed,
236
+ // / or nullptr if instance members should not be 'self' qualified.
237
+ DeclContext *candidateSelfDC;
238
+
234
239
public:
235
240
ASTScopeDeclConsumerForUnqualifiedLookup (UnqualifiedLookupFactory &factory)
236
- : factory(factory) {}
241
+ : factory(factory), candidateSelfDC( nullptr ) {}
237
242
238
243
virtual ~ASTScopeDeclConsumerForUnqualifiedLookup () = default ;
239
244
245
+ void maybeUpdateSelfDC (VarDecl *var);
246
+
240
247
bool consume (ArrayRef<ValueDecl *> values, DeclVisibilityKind vis,
241
248
NullablePtr<DeclContext> baseDC = nullptr ) override ;
242
249
@@ -547,12 +554,61 @@ void UnqualifiedLookupFactory::lookInASTScopes() {
547
554
Name, Loc, consumer);
548
555
}
549
556
557
+ void ASTScopeDeclConsumerForUnqualifiedLookup::maybeUpdateSelfDC (
558
+ VarDecl *var) {
559
+ // We have a binding named 'self'.
560
+ //
561
+ // There are three possibilities:
562
+ //
563
+ // 1) This binding is the 'self' parameter of a method,
564
+ // 2) This binding is a bona-fide 'self' capture, meaning a capture
565
+ // list entry named 'self' with initial value expression 'self',
566
+ // 3) None of the above.
567
+ //
568
+ // How we handle these cases depends on whether we've already seen
569
+ // another 'self' binding.
570
+ if (candidateSelfDC == nullptr ) {
571
+ // We haven't seen one yet, so record it.
572
+ if (var->isSelfParameter ())
573
+ candidateSelfDC = var->getDeclContext ();
574
+ else if (var->isSelfParamCapture ())
575
+ candidateSelfDC = var->getParentCaptureList ()->getClosureBody ();
576
+ } else {
577
+ // If we see a binding named 'self' that is not a bona-fide
578
+ // 'self', we have to forget about the previous 'self' capture
579
+ // because it's not going to be the right one for accessing
580
+ // instance members of the innermost nominal type. Eg,
581
+ //
582
+ // class C {
583
+ // func bar() {}
584
+ // func foo() {
585
+ // _ { [self=12] { [self] bar() } }
586
+ // }
587
+ // }
588
+ //
589
+ // Instead, we're going to move on and look for the next-innermost
590
+ // 'self' binding.
591
+ if (!var->isSelfParameter () &&
592
+ !var->isSelfParamCapture ())
593
+ candidateSelfDC = nullptr ;
594
+ }
595
+ }
596
+
550
597
bool ASTScopeDeclConsumerForUnqualifiedLookup::consume (
551
598
ArrayRef<ValueDecl *> values, DeclVisibilityKind vis,
552
599
NullablePtr<DeclContext> baseDC) {
553
600
for (auto *value: values) {
554
601
if (factory.isOriginallyTypeLookup && !isa<TypeDecl>(value))
555
602
continue ;
603
+
604
+ // Try to resolve the base for unqualified instance member
605
+ // references. This is used by lookInMembers().
606
+ if (auto *var = dyn_cast<VarDecl>(value)) {
607
+ if (var->getName () == factory.Ctx .Id_self ) {
608
+ maybeUpdateSelfDC (var);
609
+ }
610
+ }
611
+
556
612
if (!value->getName ().matchesRef (factory.Name .getFullName ()))
557
613
continue ;
558
614
@@ -589,19 +645,33 @@ bool ASTScopeDeclConsumerForUnqualifiedLookup::lookInMembers(
589
645
NullablePtr<DeclContext> selfDC, DeclContext *const scopeDC,
590
646
NominalTypeDecl *const nominal,
591
647
function_ref<bool (Optional<bool >)> calculateIsCascadingUse) {
592
- if (selfDC) {
593
- if (auto *d = selfDC.get ()->getAsDecl ()) {
594
- if (auto *afd = dyn_cast<AbstractFunctionDecl>(d))
595
- assert (!factory.isOutsideBodyOfFunction (afd) && " Should be inside" );
648
+ if (candidateSelfDC) {
649
+ if (auto *afd = dyn_cast<AbstractFunctionDecl>(candidateSelfDC)) {
650
+ assert (!factory.isOutsideBodyOfFunction (afd) && " Should be inside" );
596
651
}
597
652
}
653
+
654
+ // We're looking for members of a type.
655
+ //
656
+ // If we started the looking from inside a scope where a 'self' parameter
657
+ // is visible, instance members are returned with the 'self' parameter's
658
+ // DeclContext as the base, which is how the expression checker knows to
659
+ // convert the unqualified reference into a self member access.
598
660
auto resultFinder = UnqualifiedLookupFactory::ResultFinderForTypeContext (
599
- &factory, selfDC ? selfDC. get () : scopeDC, scopeDC);
661
+ &factory, candidateSelfDC ? candidateSelfDC : scopeDC, scopeDC);
600
662
const bool isCascadingUse =
601
663
calculateIsCascadingUse (factory.getInitialIsCascadingUse ());
602
664
factory.findResultsAndSaveUnavailables (scopeDC, std::move (resultFinder),
603
665
isCascadingUse, factory.baseNLOptions );
604
666
factory.recordCompletionOfAScope ();
667
+
668
+ // We're done looking inside a nominal type declaration. It is possible
669
+ // that this nominal type is nested inside of another type, in which case
670
+ // we will visit the outer type next. Make sure to clear out the known
671
+ // 'self' parameeter context, since any members of the outer type are
672
+ // not accessed via the innermost 'self' parameter.
673
+ candidateSelfDC = nullptr ;
674
+
605
675
return factory.isFirstResultEnough ();
606
676
}
607
677
0 commit comments