Skip to content

Commit 628d624

Browse files
slavapestovcalda
authored andcommitted
AST: Refactor unqualified lookup a little bit
1 parent 97178b2 commit 628d624

File tree

3 files changed

+86
-168
lines changed

3 files changed

+86
-168
lines changed

include/swift/AST/ASTScope.h

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -482,45 +482,33 @@ class Portion : public ASTAllocated<ASTScopeImpl> {
482482

483483
virtual NullablePtr<ASTScopeImpl>
484484
insertionPointForDeferredExpansion(IterableTypeScope *) const = 0;
485-
};
486-
487-
// For the whole Decl scope of a GenericType or an Extension
488-
class GenericTypeOrExtensionWholePortion final : public Portion {
489-
public:
490-
GenericTypeOrExtensionWholePortion() : Portion("Decl") {}
491-
virtual ~GenericTypeOrExtensionWholePortion() {}
492-
493-
// Just for TypeAlias
494-
ASTScopeImpl *expandScope(GenericTypeOrExtensionScope *,
495-
ScopeCreator &) const override;
485+
};
496486

497-
SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *,
498-
bool omitAssertions) const override;
487+
// For the whole Decl scope of a GenericType or an Extension
488+
class GenericTypeOrExtensionWholePortion final : public Portion {
489+
public:
490+
GenericTypeOrExtensionWholePortion() : Portion("Decl") {}
491+
virtual ~GenericTypeOrExtensionWholePortion() {}
499492

500-
NullablePtr<const ASTScopeImpl>
501-
getLookupLimitFor(const GenericTypeOrExtensionScope *) const override;
493+
// Just for TypeAlias
494+
ASTScopeImpl *expandScope(GenericTypeOrExtensionScope *,
495+
ScopeCreator &) const override;
502496

503-
NullablePtr<ASTScopeImpl>
504-
insertionPointForDeferredExpansion(IterableTypeScope *) const override;
505-
};
497+
SourceRange getChildlessSourceRangeOf(const GenericTypeOrExtensionScope *,
498+
bool omitAssertions) const override;
506499

507-
/// GenericTypeOrExtension = GenericType or Extension
508-
class GenericTypeOrExtensionWhereOrBodyPortion : public Portion {
509-
public:
510-
GenericTypeOrExtensionWhereOrBodyPortion(const char *n) : Portion(n) {}
511-
virtual ~GenericTypeOrExtensionWhereOrBodyPortion() {}
500+
NullablePtr<const ASTScopeImpl>
501+
getLookupLimitFor(const GenericTypeOrExtensionScope *) const override;
512502

513-
bool lookupMembersOf(const GenericTypeOrExtensionScope *scope,
514-
ASTScopeImpl::DeclConsumer consumer) const override;
503+
NullablePtr<ASTScopeImpl>
504+
insertionPointForDeferredExpansion(IterableTypeScope *) const override;
515505
};
516506

517507
/// Behavior specific to representing the trailing where clause of a
518508
/// GenericTypeDecl or ExtensionDecl scope.
519-
class GenericTypeOrExtensionWherePortion final
520-
: public GenericTypeOrExtensionWhereOrBodyPortion {
509+
class GenericTypeOrExtensionWherePortion final : public Portion {
521510
public:
522-
GenericTypeOrExtensionWherePortion()
523-
: GenericTypeOrExtensionWhereOrBodyPortion("Where") {}
511+
GenericTypeOrExtensionWherePortion() : Portion("Where") {}
524512

525513
bool lookupMembersOf(const GenericTypeOrExtensionScope *scope,
526514
ASTScopeImpl::DeclConsumer consumer) const override;
@@ -537,11 +525,12 @@ class GenericTypeOrExtensionWherePortion final
537525

538526
/// Behavior specific to representing the Body of a NominalTypeDecl or
539527
/// ExtensionDecl scope
540-
class IterableTypeBodyPortion final
541-
: public GenericTypeOrExtensionWhereOrBodyPortion {
528+
class IterableTypeBodyPortion final : public Portion {
542529
public:
543-
IterableTypeBodyPortion()
544-
: GenericTypeOrExtensionWhereOrBodyPortion("Body") {}
530+
IterableTypeBodyPortion() : Portion("Body") {}
531+
532+
bool lookupMembersOf(const GenericTypeOrExtensionScope *scope,
533+
ASTScopeImpl::DeclConsumer consumer) const override;
545534

546535
ASTScopeImpl *expandScope(GenericTypeOrExtensionScope *,
547536
ScopeCreator &) const override;

lib/AST/ASTScopeLookup.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -274,22 +274,24 @@ bool Portion::lookupMembersOf(const GenericTypeOrExtensionScope *,
274274
return false;
275275
}
276276

277-
bool GenericTypeOrExtensionWhereOrBodyPortion::lookupMembersOf(
277+
bool GenericTypeOrExtensionWherePortion::lookupMembersOf(
278278
const GenericTypeOrExtensionScope *scope,
279279
ASTScopeImpl::DeclConsumer consumer) const {
280280
if (scope->getCorrespondingNominalTypeDecl().isNull())
281281
return false;
282+
283+
if (!scope->areMembersVisibleFromWhereClause())
284+
return false;
285+
282286
return consumer.lookInMembers(scope->getGenericContext());
283287
}
284288

285-
bool GenericTypeOrExtensionWherePortion::lookupMembersOf(
289+
bool IterableTypeBodyPortion::lookupMembersOf(
286290
const GenericTypeOrExtensionScope *scope,
287291
ASTScopeImpl::DeclConsumer consumer) const {
288-
if (!scope->areMembersVisibleFromWhereClause())
292+
if (scope->getCorrespondingNominalTypeDecl().isNull())
289293
return false;
290-
291-
return GenericTypeOrExtensionWhereOrBodyPortion::lookupMembersOf(
292-
scope, consumer);
294+
return consumer.lookInMembers(scope->getGenericContext());
293295
}
294296

295297
bool GenericTypeOrExtensionScope::areMembersVisibleFromWhereClause() const {

lib/AST/UnqualifiedLookup.cpp

Lines changed: 56 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -51,49 +51,6 @@ namespace {
5151
using ResultsVector = SmallVector<LookupResultEntry, 4>;
5252

5353
private:
54-
/// Finds lookup results based on the types that self conforms to.
55-
/// For instance, self always conforms to a struct, enum or class.
56-
/// But in addition, self could conform to any number of protocols.
57-
/// For example, when there's a protocol extension, e.g. extension P where
58-
/// self: P2, self also conforms to P2 so P2 must be searched.
59-
class ResultFinderForTypeContext {
60-
UnqualifiedLookupFactory *const factory;
61-
/// Nontypes are formally members of the base type, i.e. the dynamic type
62-
/// of the activation record.
63-
const DeclContext *const dynamicContext;
64-
/// Types are formally members of the metatype, i.e. the static type of the
65-
/// activation record.
66-
const DeclContext *const staticContext;
67-
using SelfBounds = SmallVector<NominalTypeDecl *, 2>;
68-
SelfBounds selfBounds;
69-
70-
public:
71-
/// \p staticContext is also the context from which to derive the self types
72-
ResultFinderForTypeContext(UnqualifiedLookupFactory *factory,
73-
const DeclContext *dynamicContext,
74-
const DeclContext *staticContext);
75-
76-
SWIFT_DEBUG_DUMP;
77-
78-
private:
79-
SelfBounds findSelfBounds(const DeclContext *dc);
80-
ValueDecl *lookupBaseDecl(const DeclContext *baseDC) const;
81-
ValueDecl *getBaseDeclForResult(const DeclContext *baseDC) const;
82-
83-
// Classify this declaration.
84-
// Types are formally members of the metatype.
85-
const DeclContext *
86-
whereValueIsMember(const ValueDecl *const member) const {
87-
return isa<TypeDecl>(member) ? staticContext : dynamicContext;
88-
}
89-
90-
public:
91-
/// Do the lookups and add matches to results.
92-
void findResults(const DeclNameRef &Name, NLOptions baseNLOptions,
93-
const DeclContext *contextForLookup,
94-
SmallVectorImpl<LookupResultEntry> &results) const;
95-
};
96-
9754
// Inputs
9855
const DeclNameRef Name;
9956
DeclContext *const DC;
@@ -152,6 +109,10 @@ namespace {
152109

153110
#pragma mark context-based lookup declarations
154111

112+
ValueDecl *lookupBaseDecl(const DeclContext *baseDC) const;
113+
114+
ValueDecl *getBaseDeclForResult(const DeclContext *baseDC) const;
115+
155116
/// For diagnostic purposes, move aside the unavailables, and put
156117
/// them back as a last-ditch effort.
157118
/// Could be cleaner someday with a richer interface to UnqualifiedLookup.
@@ -172,8 +133,9 @@ namespace {
172133
const bool isOriginallyMacroLookup);
173134

174135
void findResultsAndSaveUnavailables(
175-
const DeclContext *lookupContextForThisContext,
176-
ResultFinderForTypeContext &&resultFinderForTypeContext,
136+
const DeclContext *dynamicContext,
137+
const DeclContext *staticContext,
138+
SmallVector<NominalTypeDecl *, 2> selfBounds,
177139
NLOptions baseNLOptions);
178140

179141
public:
@@ -335,30 +297,8 @@ void UnqualifiedLookupFactory::lookUpTopLevelNamesInModuleScopeContext(
335297

336298
#pragma mark context-based lookup definitions
337299

338-
void UnqualifiedLookupFactory::ResultFinderForTypeContext::findResults(
339-
const DeclNameRef &Name, NLOptions baseNLOptions,
340-
const DeclContext *contextForLookup,
341-
SmallVectorImpl<LookupResultEntry> &results) const {
342-
// An optimization:
343-
if (selfBounds.empty())
344-
return;
345-
346-
SmallVector<ValueDecl *, 4> Lookup;
347-
contextForLookup->lookupQualified(selfBounds, Name, factory->Loc,
348-
baseNLOptions, Lookup);
349-
for (auto Result : Lookup) {
350-
auto baseDC = const_cast<DeclContext *>(whereValueIsMember(Result));
351-
auto baseDecl = getBaseDeclForResult(baseDC);
352-
results.emplace_back(baseDC, baseDecl, Result);
353-
#ifndef NDEBUG
354-
factory->addedResult(results.back());
355-
#endif
356-
}
357-
}
358-
359300
ValueDecl *
360-
UnqualifiedLookupFactory::ResultFinderForTypeContext::getBaseDeclForResult(
361-
const DeclContext *baseDC) const {
301+
UnqualifiedLookupFactory::getBaseDeclForResult(const DeclContext *baseDC) const {
362302
if (baseDC == nullptr) {
363303
return nullptr;
364304
}
@@ -393,7 +333,7 @@ UnqualifiedLookupFactory::ResultFinderForTypeContext::getBaseDeclForResult(
393333
/// unwrapping condition (e.g. `guard let self else { return }`).
394334
/// If this is true, then we know any implicit self reference in the
395335
/// following scope is guaranteed to be non-optional.
396-
bool implicitSelfReferenceIsUnwrapped(const ValueDecl *selfDecl) {
336+
static bool implicitSelfReferenceIsUnwrapped(const ValueDecl *selfDecl) {
397337
ASTContext &Ctx = selfDecl->getASTContext();
398338

399339
// Check if the implicit self decl refers to a var in a conditional stmt
@@ -411,25 +351,19 @@ bool implicitSelfReferenceIsUnwrapped(const ValueDecl *selfDecl) {
411351
return conditionalStmt->rebindsSelf(Ctx);
412352
}
413353

414-
ValueDecl *UnqualifiedLookupFactory::ResultFinderForTypeContext::lookupBaseDecl(
415-
const DeclContext *baseDC) const {
416-
auto dc = factory->DC;
417-
if (!dc) {
418-
return nullptr;
419-
}
420-
354+
ValueDecl *UnqualifiedLookupFactory::lookupBaseDecl(const DeclContext *baseDC) const {
421355
// Perform an unqualified lookup for the base decl of this result. This
422356
// handles cases where self was rebound (e.g. `guard let self = self`)
423357
// earlier in this closure or some outer closure.
424-
auto closureExpr =
425-
dyn_cast_or_null<ClosureExpr>(dc->getInnermostClosureForSelfCapture());
358+
auto closureExpr =
359+
dyn_cast_or_null<ClosureExpr>(dc->getInnermostClosureForSelfCapture());
360+
426361
if (!closureExpr) {
427362
return nullptr;
428363
}
429364

430365
auto selfDecl = ASTScope::lookupSingleLocalDecl(
431-
factory->DC->getParentSourceFile(), DeclName(factory->Ctx.Id_self),
432-
factory->Loc);
366+
DC->getParentSourceFile(), DeclName(Ctx.Id_self), Loc);
433367

434368
if (!selfDecl) {
435369
return nullptr;
@@ -466,7 +400,7 @@ ValueDecl *UnqualifiedLookupFactory::ResultFinderForTypeContext::lookupBaseDecl(
466400
// In these cases, using the Swift 6 lookup behavior doesn't affect
467401
// how the body is type-checked, so it can be used in Swift 5 mode
468402
// without breaking source compatibility for non-escaping closures.
469-
if (capturesSelfWeakly && !factory->Ctx.LangOpts.isSwiftVersionAtLeast(6) &&
403+
if (capturesSelfWeakly && !Ctx.LangOpts.isSwiftVersionAtLeast(6) &&
470404
!implicitSelfReferenceIsUnwrapped(selfDecl)) {
471405
return nullptr;
472406
}
@@ -612,12 +546,25 @@ void UnqualifiedLookupFactory::lookForAModuleWithTheGivenName(
612546
#pragma mark common helper definitions
613547

614548
void UnqualifiedLookupFactory::findResultsAndSaveUnavailables(
615-
const DeclContext *lookupContextForThisContext,
616-
ResultFinderForTypeContext &&resultFinderForTypeContext,
549+
const DeclContext *dynamicContext,
550+
const DeclContext *staticContext,
551+
SmallVector<NominalTypeDecl *, 2> selfBounds,
617552
NLOptions baseNLOptions) {
553+
if (selfBounds.empty())
554+
return;
555+
618556
auto firstPossiblyUnavailableResult = Results.size();
619-
resultFinderForTypeContext.findResults(Name, baseNLOptions,
620-
lookupContextForThisContext, Results);
557+
SmallVector<ValueDecl *, 4> Lookup;
558+
staticContext->lookupQualified(selfBounds, Name, Loc, baseNLOptions, Lookup);
559+
for (auto Result : Lookup) {
560+
auto baseDC = isa<TypeDecl>(Result) ? staticContext : dynamicContext;
561+
auto baseDecl = getBaseDeclForResult(baseDC);
562+
Results.emplace_back(const_cast<DeclContext *>(baseDC), baseDecl, Result);
563+
#ifndef NDEBUG
564+
addedResult(Results.back());
565+
#endif
566+
}
567+
621568
setAsideUnavailableResults(firstPossiblyUnavailableResult);
622569
}
623570

@@ -651,34 +598,6 @@ void UnqualifiedLookupFactory::recordCompletionOfAScope() {
651598
IndexOfFirstOuterResult = Results.size();
652599
}
653600

654-
UnqualifiedLookupFactory::ResultFinderForTypeContext::
655-
ResultFinderForTypeContext(UnqualifiedLookupFactory *factory,
656-
const DeclContext *dynamicContext,
657-
const DeclContext *staticContext)
658-
: factory(factory), dynamicContext(dynamicContext),
659-
staticContext(staticContext), selfBounds(findSelfBounds(staticContext)) {}
660-
661-
UnqualifiedLookupFactory::ResultFinderForTypeContext::SelfBounds
662-
UnqualifiedLookupFactory::ResultFinderForTypeContext::findSelfBounds(
663-
const DeclContext *dc) {
664-
auto nominal = dc->getSelfNominalTypeDecl();
665-
if (!nominal)
666-
return {};
667-
668-
SelfBounds selfBounds;
669-
selfBounds.push_back(nominal);
670-
671-
// For a protocol extension, check whether there are additional "Self"
672-
// constraints that can affect name lookup.
673-
if (dc->getExtendedProtocolDecl()) {
674-
auto ext = cast<ExtensionDecl>(dc);
675-
auto bounds = getSelfBoundsFromWhereClause(ext);
676-
for (auto bound : bounds.decls)
677-
selfBounds.push_back(bound);
678-
}
679-
return selfBounds;
680-
}
681-
682601
#pragma mark ASTScopeImpl support
683602

684603
void UnqualifiedLookupFactory::lookInASTScopes() {
@@ -799,19 +718,39 @@ bool ASTScopeDeclGatherer::consume(ArrayRef<ValueDecl *> valuesArg,
799718
return false;
800719
}
801720

721+
static SmallVector<NominalTypeDecl *, 2> findSelfBounds(const DeclContext *dc) {
722+
auto nominal = dc->getSelfNominalTypeDecl();
723+
if (!nominal)
724+
return {};
725+
726+
SmallVector<NominalTypeDecl *, 2> selfBounds;
727+
selfBounds.push_back(nominal);
728+
729+
// For a protocol extension, check whether there are additional "Self"
730+
// constraints that can affect name lookup.
731+
if (dc->getExtendedProtocolDecl()) {
732+
auto ext = cast<ExtensionDecl>(dc);
733+
auto bounds = getSelfBoundsFromWhereClause(ext);
734+
for (auto bound : bounds.decls)
735+
selfBounds.push_back(bound);
736+
}
737+
738+
return selfBounds;
739+
}
740+
802741
// TODO: in future, migrate this functionality into ASTScopes
803742
bool ASTScopeDeclConsumerForUnqualifiedLookup::lookInMembers(
804743
const DeclContext *scopeDC) const {
744+
auto selfBounds = findSelfBounds(scopeDC);
745+
805746
// We're looking for members of a type.
806747
//
807748
// If we started the looking from inside a scope where a 'self' parameter
808749
// is visible, instance members are returned with the 'self' parameter's
809750
// DeclContext as the base, which is how the expression checker knows to
810751
// convert the unqualified reference into a self member access.
811-
auto resultFinder = UnqualifiedLookupFactory::ResultFinderForTypeContext(
812-
&factory, candidateSelfDC ? candidateSelfDC : scopeDC, scopeDC);
813-
factory.findResultsAndSaveUnavailables(scopeDC, std::move(resultFinder),
814-
factory.baseNLOptions);
752+
factory.findResultsAndSaveUnavailables(candidateSelfDC ? candidateSelfDC : scopeDC,
753+
scopeDC, selfBounds, factory.baseNLOptions);
815754
factory.recordCompletionOfAScope();
816755

817756
// We're done looking inside a nominal type declaration. It is possible
@@ -837,18 +776,6 @@ UnqualifiedLookupRequest::evaluate(Evaluator &evaluator,
837776

838777
#pragma mark debugging
839778

840-
void UnqualifiedLookupFactory::ResultFinderForTypeContext::dump() const {
841-
(void)factory;
842-
llvm::errs() << "dynamicContext: ";
843-
dynamicContext->dumpContext();
844-
llvm::errs() << "staticContext: ";
845-
staticContext->dumpContext();
846-
llvm::errs() << "selfBounds: ";
847-
for (const auto *D : selfBounds)
848-
D->dump(llvm::errs(), 1);
849-
llvm::errs() << "\n";
850-
}
851-
852779
void UnqualifiedLookupFactory::dump() const { print(llvm::errs()); }
853780
void UnqualifiedLookupFactory::dumpScopes() const { printScopes(llvm::errs()); }
854781
void UnqualifiedLookupFactory::dumpResults() const {

0 commit comments

Comments
 (0)