@@ -231,12 +231,19 @@ class ASTScopeDeclConsumerForUnqualifiedLookup
231231 : public AbstractASTScopeDeclConsumer {
232232 UnqualifiedLookupFactory &factory;
233233
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+
234239public:
235240 ASTScopeDeclConsumerForUnqualifiedLookup (UnqualifiedLookupFactory &factory)
236- : factory(factory) {}
241+ : factory(factory), candidateSelfDC( nullptr ) {}
237242
238243 virtual ~ASTScopeDeclConsumerForUnqualifiedLookup () = default ;
239244
245+ void maybeUpdateSelfDC (VarDecl *var);
246+
240247 bool consume (ArrayRef<ValueDecl *> values, DeclVisibilityKind vis,
241248 NullablePtr<DeclContext> baseDC = nullptr ) override ;
242249
@@ -547,12 +554,61 @@ void UnqualifiedLookupFactory::lookInASTScopes() {
547554 Name, Loc, consumer);
548555}
549556
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+
550597bool ASTScopeDeclConsumerForUnqualifiedLookup::consume (
551598 ArrayRef<ValueDecl *> values, DeclVisibilityKind vis,
552599 NullablePtr<DeclContext> baseDC) {
553600 for (auto *value: values) {
554601 if (factory.isOriginallyTypeLookup && !isa<TypeDecl>(value))
555602 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+
556612 if (!value->getName ().matchesRef (factory.Name .getFullName ()))
557613 continue ;
558614
@@ -589,19 +645,33 @@ bool ASTScopeDeclConsumerForUnqualifiedLookup::lookInMembers(
589645 NullablePtr<DeclContext> selfDC, DeclContext *const scopeDC,
590646 NominalTypeDecl *const nominal,
591647 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" );
596651 }
597652 }
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.
598660 auto resultFinder = UnqualifiedLookupFactory::ResultFinderForTypeContext (
599- &factory, selfDC ? selfDC. get () : scopeDC, scopeDC);
661+ &factory, candidateSelfDC ? candidateSelfDC : scopeDC, scopeDC);
600662 const bool isCascadingUse =
601663 calculateIsCascadingUse (factory.getInitialIsCascadingUse ());
602664 factory.findResultsAndSaveUnavailables (scopeDC, std::move (resultFinder),
603665 isCascadingUse, factory.baseNLOptions );
604666 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+
605675 return factory.isFirstResultEnough ();
606676}
607677
0 commit comments