Skip to content

Commit 393b4ce

Browse files
committed
[NameLookup] Move macro-related name lookup operations into the namelookup
namespace. This moves the `isInMacroArgument` predicate and `lookupMacros` into `namelookup`. ASTScope still encapsulates the scope tree and contains the operation to lookup the enclosing macro scope, which then invokes a callback to determine whether a potential macro scope is indeed a macro, because answering this question requires name lookup.
1 parent 51e1a39 commit 393b4ce

12 files changed

+115
-74
lines changed

include/swift/AST/ASTScope.h

+9-19
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@ class ASTScopeImpl : public ASTAllocated<ASTScopeImpl> {
218218
return nullptr;
219219
}
220220

221+
virtual NullablePtr<MacroExpansionDecl> getFreestandingMacro() const {
222+
return nullptr;
223+
}
224+
221225
#pragma mark - debugging and printing
222226

223227
public:
@@ -278,16 +282,9 @@ class ASTScopeImpl : public ASTAllocated<ASTScopeImpl> {
278282
static std::pair<CaseStmt *, CaseStmt *>
279283
lookupFallthroughSourceAndDest(SourceFile *sourceFile, SourceLoc loc);
280284

281-
/// Returns \c true if the given source location is inside an attached
282-
/// or freestanding macro argument.
283-
static bool isInMacroArgument(SourceFile *sourceFile, SourceLoc loc);
284-
285-
/// Returns \c true if this scope contains macro arguments.
286-
///
287-
/// This is always true within macro expansion decl scopes, and it's
288-
/// true within custom attribute scopes if the attribute name is a
289-
/// potential macro reference.
290-
virtual bool isMacroArgumentScope() const { return false; }
285+
static void lookupEnclosingMacroScope(
286+
SourceFile *sourceFile, SourceLoc loc,
287+
llvm::function_ref<bool(ASTScope::PotentialMacro)> consume);
291288

292289
/// Scopes that cannot bind variables may set this to true to create more
293290
/// compact scope tree in the debug info.
@@ -879,13 +876,6 @@ class CustomAttributeScope final : public ASTScopeImpl {
879876
return attr;
880877
}
881878
bool ignoreInDebugInfo() const override { return true; }
882-
883-
bool isMacroArgumentScope() const override {
884-
// FIXME: This should check whether the attribute name is
885-
// a macro. Otherwise, macro expansion will be suppressed
886-
// for property wrapper arguments.
887-
return true;
888-
}
889879

890880
private:
891881
void expandAScopeThatDoesNotCreateANewInsertionPoint(ScopeCreator &);
@@ -1285,8 +1275,8 @@ class MacroExpansionDeclScope final : public ASTScopeImpl {
12851275
SourceRange
12861276
getSourceRangeOfThisASTNode(bool omitAssertions = false) const override;
12871277

1288-
bool isMacroArgumentScope() const override {
1289-
return true;
1278+
NullablePtr<MacroExpansionDecl> getFreestandingMacro() const override {
1279+
return decl;
12901280
}
12911281

12921282
protected:

include/swift/AST/NameLookup.h

+24-3
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,15 @@ template <typename Result>
545545
void filterForDiscriminator(SmallVectorImpl<Result> &results,
546546
DebuggerClient *debugClient);
547547

548+
/// \returns The set of macro declarations with the given name that
549+
/// fulfill any of the given macro roles.
550+
SmallVector<MacroDecl *, 1>
551+
lookupMacros(DeclContext *dc, DeclNameRef macroName, MacroRoles roles);
552+
553+
/// \returns Whether the given source location is inside an attached
554+
/// or freestanding macro argument.
555+
bool isInMacroArgument(SourceFile *sourceFile, SourceLoc loc);
556+
548557
/// Call the given function body with each macro declaration and its associated
549558
/// role attribute for the given role.
550559
///
@@ -816,9 +825,21 @@ class ASTScope : public ASTAllocated<ASTScope> {
816825
static std::pair<CaseStmt *, CaseStmt *>
817826
lookupFallthroughSourceAndDest(SourceFile *sourceFile, SourceLoc loc);
818827

819-
/// Returns \c true if the given source location is inside an attached
820-
/// or freestanding macro argument.
821-
static bool isInMacroArgument(SourceFile *sourceFile, SourceLoc loc);
828+
using PotentialMacro =
829+
llvm::PointerUnion<FreestandingMacroExpansion *, CustomAttr *>;
830+
831+
/// Look up the scope tree for the nearest enclosing macro scope at
832+
/// the given source location.
833+
///
834+
/// \param sourceFile The source file containing the given location.
835+
/// \param loc The source location to start lookup from.
836+
/// \param consume A function that is called when a potential macro
837+
/// scope is found. If \c consume returns \c true, lookup
838+
/// will stop. If \c consume returns \c false, lookup will
839+
/// continue up the scope tree.
840+
static void lookupEnclosingMacroScope(
841+
SourceFile *sourceFile, SourceLoc loc,
842+
llvm::function_ref<bool(PotentialMacro macro)> consume);
822843

823844
SWIFT_DEBUG_DUMP;
824845
void print(llvm::raw_ostream &) const;

include/swift/AST/TypeCheckRequests.h

+3
Original file line numberDiff line numberDiff line change
@@ -3249,6 +3249,9 @@ class UnresolvedMacroReference {
32493249
public:
32503250
UnresolvedMacroReference(FreestandingMacroExpansion *exp) : pointer(exp) {}
32513251
UnresolvedMacroReference(CustomAttr *attr) : pointer(attr) {}
3252+
UnresolvedMacroReference(
3253+
llvm::PointerUnion<FreestandingMacroExpansion *, CustomAttr *> pointer)
3254+
: pointer(pointer) {}
32523255

32533256
FreestandingMacroExpansion *getFreestanding() const {
32543257
return pointer.dyn_cast<FreestandingMacroExpansion *>();

lib/AST/ASTScope.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,10 @@ std::pair<CaseStmt *, CaseStmt *> ASTScope::lookupFallthroughSourceAndDest(
6060
return ASTScopeImpl::lookupFallthroughSourceAndDest(sourceFile, loc);
6161
}
6262

63-
bool ASTScope::isInMacroArgument(SourceFile *sourceFile,
64-
SourceLoc loc) {
65-
return ASTScopeImpl::isInMacroArgument(sourceFile, loc);
63+
void ASTScope::lookupEnclosingMacroScope(
64+
SourceFile *sourceFile, SourceLoc loc,
65+
llvm::function_ref<bool(PotentialMacro)> body) {
66+
return ASTScopeImpl::lookupEnclosingMacroScope(sourceFile, loc, body);
6667
}
6768

6869
#if SWIFT_COMPILER_IS_MSVC

lib/AST/ASTScopeLookup.cpp

+14-9
Original file line numberDiff line numberDiff line change
@@ -676,19 +676,26 @@ std::pair<CaseStmt *, CaseStmt *> ASTScopeImpl::lookupFallthroughSourceAndDest(
676676
return { nullptr, nullptr };
677677
}
678678

679-
bool ASTScopeImpl::isInMacroArgument(SourceFile *sourceFile,
680-
SourceLoc loc) {
679+
void ASTScopeImpl::lookupEnclosingMacroScope(
680+
SourceFile *sourceFile, SourceLoc loc,
681+
llvm::function_ref<bool(ASTScope::PotentialMacro)> consume) {
681682
if (!sourceFile || sourceFile->Kind == SourceFileKind::Interface)
682-
return false;
683+
return;
683684

684685
if (loc.isInvalid())
685-
return false;
686+
return;
686687

687688
auto *fileScope = sourceFile->getScope().impl;
688689
auto *scope = fileScope->findInnermostEnclosingScope(loc, nullptr);
689690
do {
690-
if (scope->isMacroArgumentScope())
691-
return true;
691+
auto *freestanding = scope->getFreestandingMacro().getPtrOrNull();
692+
if (freestanding && consume(freestanding))
693+
return;
694+
695+
auto *attr = scope->getDeclAttributeIfAny().getPtrOrNull();
696+
auto *potentialAttached = dyn_cast_or_null<CustomAttr>(attr);
697+
if (potentialAttached && consume(potentialAttached))
698+
return;
692699

693700
// If we've reached a source file scope, we can't be inside of
694701
// a macro argument. Either this is a top-level source file, or
@@ -697,9 +704,7 @@ bool ASTScopeImpl::isInMacroArgument(SourceFile *sourceFile,
697704
// MacroExpansionDeclScope, and child scopes of freestanding macros
698705
// are otherwise inside the macro argument.
699706
if (scope->getClassName() == "ASTSourceFileScope")
700-
return false;
707+
return;
701708

702709
} while ((scope = scope->getParent().getPtrOrNull()));
703-
704-
return false;
705710
}

lib/AST/NameLookup.cpp

+55-1
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,60 @@ static DeclName adjustLazyMacroExpansionNameKey(
15941594
return name;
15951595
}
15961596

1597+
SmallVector<MacroDecl *, 1>
1598+
namelookup::lookupMacros(DeclContext *dc, DeclNameRef macroName,
1599+
MacroRoles roles) {
1600+
SmallVector<MacroDecl *, 1> choices;
1601+
auto moduleScopeDC = dc->getModuleScopeContext();
1602+
ASTContext &ctx = moduleScopeDC->getASTContext();
1603+
1604+
// Macro lookup should always exclude macro expansions; macro
1605+
// expansions cannot introduce new macro declarations. Note that
1606+
// the source location here doesn't matter.
1607+
UnqualifiedLookupDescriptor descriptor{
1608+
macroName, moduleScopeDC, SourceLoc(),
1609+
UnqualifiedLookupFlags::ExcludeMacroExpansions
1610+
};
1611+
1612+
auto lookup = evaluateOrDefault(
1613+
ctx.evaluator, UnqualifiedLookupRequest{descriptor}, {});
1614+
for (const auto &found : lookup.allResults()) {
1615+
if (auto macro = dyn_cast<MacroDecl>(found.getValueDecl())) {
1616+
auto candidateRoles = macro->getMacroRoles();
1617+
if ((candidateRoles && roles.contains(candidateRoles)) ||
1618+
// FIXME: `externalMacro` should have all roles.
1619+
macro->getBaseIdentifier().str() == "externalMacro") {
1620+
choices.push_back(macro);
1621+
}
1622+
}
1623+
}
1624+
return choices;
1625+
}
1626+
1627+
bool
1628+
namelookup::isInMacroArgument(SourceFile *sourceFile, SourceLoc loc) {
1629+
bool inMacroArgument = false;
1630+
1631+
ASTScope::lookupEnclosingMacroScope(
1632+
sourceFile, loc,
1633+
[&](auto potentialMacro) -> bool {
1634+
UnresolvedMacroReference macro(potentialMacro);
1635+
1636+
if (macro.getFreestanding()) {
1637+
inMacroArgument = true;
1638+
} else if (auto *attr = macro.getAttr()) {
1639+
auto *moduleScope = sourceFile->getModuleScopeContext();
1640+
auto results = lookupMacros(moduleScope, macro.getMacroName(),
1641+
getAttachedMacroRoles());
1642+
inMacroArgument = !results.empty();
1643+
}
1644+
1645+
return inMacroArgument;
1646+
});
1647+
1648+
return inMacroArgument;
1649+
}
1650+
15971651
/// Call the given function body with each macro declaration and its associated
15981652
/// role attribute for the given role.
15991653
///
@@ -2631,7 +2685,7 @@ directReferencesForUnqualifiedTypeLookup(DeclNameRef name,
26312685

26322686
// Manually exclude macro expansions here since the source location
26332687
// is overridden below.
2634-
if (ASTScope::isInMacroArgument(dc->getParentSourceFile(), loc))
2688+
if (namelookup::isInMacroArgument(dc->getParentSourceFile(), loc))
26352689
options |= UnqualifiedLookupFlags::ExcludeMacroExpansions;
26362690

26372691
// In a protocol or protocol extension, the 'where' clause can refer to

lib/AST/NameLookupRequests.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ static UnqualifiedLookupDescriptor excludeMacrosIfNeeded(
545545
UnqualifiedLookupFlags::ExcludeMacroExpansions))
546546
return descriptor;
547547

548-
auto isInMacroArgument = ASTScope::isInMacroArgument(
548+
auto isInMacroArgument = namelookup::isInMacroArgument(
549549
descriptor.DC->getParentSourceFile(), descriptor.Loc);
550550

551551
if (!isInMacroArgument)
@@ -562,7 +562,7 @@ static DirectLookupDescriptor excludeMacrosIfNeeded(
562562
NominalTypeDecl::LookupDirectFlags::ExcludeMacroExpansions))
563563
return descriptor;
564564

565-
auto isInMacroArgument = ASTScope::isInMacroArgument(
565+
auto isInMacroArgument = namelookup::isInMacroArgument(
566566
descriptor.DC->getParentSourceFile(), loc);
567567

568568
if (!isInMacroArgument)
@@ -581,7 +581,7 @@ excludeMacrosIfNeeded(const DeclContext *dc, SourceLoc loc,
581581
if (options & NL_ExcludeMacroExpansions)
582582
return options;
583583

584-
auto isInMacroArgument = ASTScope::isInMacroArgument(
584+
auto isInMacroArgument = namelookup::isInMacroArgument(
585585
dc->getParentSourceFile(), loc);
586586

587587
if (!isInMacroArgument)

lib/Sema/CSGen.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -3900,7 +3900,7 @@ namespace {
39003900
FunctionRefKind functionRefKind,
39013901
MacroRoles roles) {
39023902
SmallVector<OverloadChoice, 1> choices;
3903-
auto results = TypeChecker::lookupMacros(
3903+
auto results = namelookup::lookupMacros(
39043904
CurDC, DeclNameRef(macroName), roles);
39053905
for (const auto &result : results) {
39063906
OverloadChoice choice = OverloadChoice(Type(), result, functionRefKind);

lib/Sema/PreCheckExpr.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE,
606606
// FIXME: Don't perform typo correction inside macro arguments, because it
607607
// will invoke synthesizing declarations in this scope, which will attempt to
608608
// expand this macro which leads to circular reference errors.
609-
if (!ASTScope::isInMacroArgument(DC->getParentSourceFile(), UDRE->getLoc())) {
609+
if (!namelookup::isInMacroArgument(DC->getParentSourceFile(), UDRE->getLoc())) {
610610
TypeChecker::performTypoCorrection(DC, UDRE->getRefKind(), Type(),
611611
lookupOptions, corrections);
612612
}

lib/Sema/TypeCheckDecl.cpp

-30
Original file line numberDiff line numberDiff line change
@@ -1609,36 +1609,6 @@ TypeChecker::lookupPrecedenceGroup(DeclContext *dc, Identifier name,
16091609
return PrecedenceGroupLookupResult(dc, name, std::move(groups));
16101610
}
16111611

1612-
SmallVector<MacroDecl *, 1>
1613-
TypeChecker::lookupMacros(DeclContext *dc, DeclNameRef macroName,
1614-
MacroRoles roles) {
1615-
SmallVector<MacroDecl *, 1> choices;
1616-
auto moduleScopeDC = dc->getModuleScopeContext();
1617-
ASTContext &ctx = moduleScopeDC->getASTContext();
1618-
1619-
// Macro lookup should always exclude macro expansions; macro
1620-
// expansions cannot introduce new macro declarations. Note that
1621-
// the source location here doesn't matter.
1622-
UnqualifiedLookupDescriptor descriptor{
1623-
macroName, moduleScopeDC, SourceLoc(),
1624-
UnqualifiedLookupFlags::ExcludeMacroExpansions
1625-
};
1626-
1627-
auto lookup = evaluateOrDefault(
1628-
ctx.evaluator, UnqualifiedLookupRequest{descriptor}, {});
1629-
for (const auto &found : lookup.allResults()) {
1630-
if (auto macro = dyn_cast<MacroDecl>(found.getValueDecl())) {
1631-
auto candidateRoles = macro->getMacroRoles();
1632-
if ((candidateRoles && roles.contains(candidateRoles)) ||
1633-
// FIXME: `externalMacro` should have all roles.
1634-
macro->getBaseIdentifier().str() == "externalMacro") {
1635-
choices.push_back(macro);
1636-
}
1637-
}
1638-
}
1639-
return choices;
1640-
}
1641-
16421612
/// Validate the given operator declaration.
16431613
///
16441614
/// This establishes key invariants, such as an InfixOperatorDecl's

lib/Sema/TypeCheckMacros.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1520,7 +1520,7 @@ ConcreteDeclRef ResolveMacroRequest::evaluate(Evaluator &evaluator,
15201520
// When a macro is not found for a custom attribute, it may be a non-macro.
15211521
// So bail out to prevent diagnostics from the contraint system.
15221522
if (macroRef.getAttr()) {
1523-
auto foundMacros = TypeChecker::lookupMacros(
1523+
auto foundMacros = namelookup::lookupMacros(
15241524
dc, macroRef.getMacroName(), roles);
15251525
if (foundMacros.empty())
15261526
return ConcreteDeclRef();

lib/Sema/TypeChecker.h

-3
Original file line numberDiff line numberDiff line change
@@ -941,9 +941,6 @@ lookupPrecedenceGroupForInfixOperator(DeclContext *dc, Expr *op, bool diagnose);
941941
PrecedenceGroupLookupResult
942942
lookupPrecedenceGroup(DeclContext *dc, Identifier name, SourceLoc nameLoc);
943943

944-
SmallVector<MacroDecl *, 1>
945-
lookupMacros(DeclContext *dc, DeclNameRef macroName, MacroRoles contexts);
946-
947944
enum class UnsupportedMemberTypeAccessKind : uint8_t {
948945
None,
949946
TypeAliasOfUnboundGeneric,

0 commit comments

Comments
 (0)