Skip to content

Commit ed17c33

Browse files
committed
ASTScope: Compute 'selfDC' directly in ASTScopeDeclConsumerForUnqualifiedLookup
Instead of having ASTScope compute 'selfDC', the lookup consumer can compute it on its own, by looking for bindings named 'self'.
1 parent 9b851bf commit ed17c33

File tree

1 file changed

+76
-6
lines changed

1 file changed

+76
-6
lines changed

lib/AST/UnqualifiedLookup.cpp

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
234239
public:
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+
550597
bool 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

Comments
 (0)