Skip to content

[5.9] Arbitrary peer and freestanding macros #65127

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

12 changes: 6 additions & 6 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -396,13 +396,13 @@ Entities

macro-discriminator-list ::= macro-discriminator-list? file-discriminator? macro-expansion-operator INDEX

macro-expansion-operator ::= identifier 'fMa' // attached accessor macro
macro-expansion-operator ::= identifier 'fMA' // attached member-attribute macro
macro-expansion-operator ::= decl-name identifier 'fMa' // attached accessor macro
macro-expansion-operator ::= decl-name identifier 'fMA' // attached member-attribute macro
macro-expansion-operator ::= identifier 'fMf' // freestanding macro
macro-expansion-operator ::= identifier 'fMm' // attached member macro
macro-expansion-operator ::= identifier 'fMp' // attached peer macro
macro-expansion-operator ::= identifier 'fMc' // attached conformance macro
macro-expansion-operator ::= identifier 'fMu' // uniquely-named entity
macro-expansion-operator ::= decl-name identifier 'fMm' // attached member macro
macro-expansion-operator ::= decl-name identifier 'fMp' // attached peer macro
macro-expansion-operator ::= decl-name identifier 'fMc' // attached conformance macro
macro-expansion-operator ::= decl-name identifier 'fMu' // uniquely-named entity

file-discriminator ::= identifier 'Ll' // anonymous file-discriminated declaration

Expand Down
3 changes: 2 additions & 1 deletion include/swift/AST/ASTMangler.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,8 @@ class ASTMangler : public Mangler {
void appendType(Type type, GenericSignature sig,
const ValueDecl *forDecl = nullptr);

void appendDeclName(const ValueDecl *decl);
void appendDeclName(
const ValueDecl *decl, DeclBaseName name = DeclBaseName());

GenericTypeParamType *appendAssocType(DependentMemberType *DepTy,
GenericSignature sig,
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3835,6 +3835,8 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
/// Whether to include @_implements members.
/// Used by conformance-checking to find special @_implements members.
IncludeAttrImplements = 1 << 0,
/// Whether to exclude members of macro expansions.
ExcludeMacroExpansions = 1 << 1,
};

/// Find all of the declarations with the given name within this nominal type
Expand Down
29 changes: 27 additions & 2 deletions include/swift/AST/Evaluator.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,18 @@ class Evaluator {
/// is treated as a stack and is used to detect cycles.
llvm::SetVector<ActiveRequest> activeRequests;

/// How many `ResolveMacroRequest` requests are active.
///
/// This allows us to quickly determine whether there is any
/// `ResolveMacroRequest` active in the active request stack.
/// It saves us from a linear scan through `activeRequests` when
/// we need to determine this information.
///
/// Why on earth would we need to determine this information?
/// Please see the extended comment that goes with the constructor
/// of `UnqualifiedLookupRequest`.
unsigned numActiveResolveMacroRequests = 0;

/// A cache that stores the results of requests.
evaluator::RequestCache cache;

Expand Down Expand Up @@ -324,6 +336,16 @@ class Evaluator {
return activeRequests.count(ActiveRequest(request));
}

/// Determine whether there is any active "resolve macro" request
/// on the request stack.
///
/// Why on earth would we need to determine this information?
/// Please see the extended comment that goes with the constructor
/// of `UnqualifiedLookupRequest`.
bool hasActiveResolveMacroRequest() const {
return numActiveResolveMacroRequests > 0;
}

private:
/// Diagnose a cycle detected in the evaluation of the given
/// request.
Expand All @@ -337,6 +359,10 @@ class Evaluator {
/// request to the \c activeRequests stack.
bool checkDependency(const ActiveRequest &request);

/// Note that we have finished this request, popping it from the
/// \c activeRequests stack.
void finishedRequest(const ActiveRequest &request);

/// Produce the result of the request without caching.
template<typename Request>
llvm::Expected<typename Request::OutputType>
Expand Down Expand Up @@ -366,8 +392,7 @@ class Evaluator {

// Make sure we remove this from the set of active requests once we're
// done.
assert(activeRequests.back() == activeReq);
activeRequests.pop_back();
finishedRequest(activeReq);

return std::move(result);
}
Expand Down
17 changes: 12 additions & 5 deletions include/swift/AST/NameLookupRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ class UnqualifiedLookupRequest
RequestFlags::Uncached |
RequestFlags::DependencySink> {
public:
using SimpleRequest::SimpleRequest;
UnqualifiedLookupRequest(UnqualifiedLookupDescriptor);

private:
friend SimpleRequest;
Expand All @@ -456,7 +456,10 @@ class LookupInModuleRequest
NLOptions),
RequestFlags::Uncached | RequestFlags::DependencySink> {
public:
using SimpleRequest::SimpleRequest;
LookupInModuleRequest(
const DeclContext *, DeclName, NLKind,
namelookup::ResolutionKind, const DeclContext *,
NLOptions);

private:
friend SimpleRequest;
Expand Down Expand Up @@ -504,7 +507,9 @@ class ModuleQualifiedLookupRequest
RequestFlags::Uncached |
RequestFlags::DependencySink> {
public:
using SimpleRequest::SimpleRequest;
ModuleQualifiedLookupRequest(const DeclContext *,
ModuleDecl *, DeclNameRef,
NLOptions);

private:
friend SimpleRequest;
Expand All @@ -528,7 +533,9 @@ class QualifiedLookupRequest
DeclNameRef, NLOptions),
RequestFlags::Uncached> {
public:
using SimpleRequest::SimpleRequest;
QualifiedLookupRequest(const DeclContext *,
SmallVector<NominalTypeDecl *, 4>,
DeclNameRef, NLOptions);

private:
friend SimpleRequest;
Expand Down Expand Up @@ -579,7 +586,7 @@ class DirectLookupRequest
TinyPtrVector<ValueDecl *>(DirectLookupDescriptor),
RequestFlags::Uncached|RequestFlags::DependencySink> {
public:
using SimpleRequest::SimpleRequest;
DirectLookupRequest(DirectLookupDescriptor);

private:
friend SimpleRequest;
Expand Down
34 changes: 25 additions & 9 deletions lib/AST/ASTMangler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1006,8 +1006,9 @@ static Optional<std::string> getOverriddenSwiftProtocolObjCName(
return None;
}

void ASTMangler::appendDeclName(const ValueDecl *decl) {
DeclBaseName name = decl->getBaseName();
void ASTMangler::appendDeclName(const ValueDecl *decl, DeclBaseName name) {
if (name.empty())
name = decl->getBaseName();
assert(!name.isSpecial() && "Cannot print special names");

auto *synthesizedTypeAttr =
Expand Down Expand Up @@ -4022,28 +4023,43 @@ std::string ASTMangler::mangleAttachedMacroExpansion(
const Decl *decl, CustomAttr *attr, MacroRole role) {
beginMangling();

// Append the context and name of the declaration.
// We don't mangle the declaration itself because doing so requires semantic
// information (e.g., its interface type), which introduces cyclic
// dependencies.
const Decl *attachedTo = decl;
DeclBaseName attachedToName;
if (auto valueDecl = dyn_cast<ValueDecl>(decl)) {
if (role != MacroRole::MemberAttribute) {
appendAnyDecl(valueDecl);
} else {
// Appending the member would result in a cycle since `VarDecl` appends
// its type, which would then loop back around to getting the attributes
// again. We'll instead add a discriminator for each member.
appendContextOf(valueDecl);
appendContextOf(valueDecl);

// Mangle the name, replacing special names with their user-facing names.
attachedToName = valueDecl->getName().getBaseName();
if (attachedToName.isSpecial()) {
attachedToName =
decl->getASTContext().getIdentifier(attachedToName.userFacingName());
}
appendDeclName(valueDecl, attachedToName);

// For member attribute macros, the attribute is attached to the enclosing
// declaration.
if (role == MacroRole::MemberAttribute) {
attachedTo = decl->getDeclContext()->getAsDecl();
}
} else {
appendContext(decl->getDeclContext(), "");
appendIdentifier("_");
}

// Determine the name of the macro.
DeclBaseName macroName;
if (auto *macroDecl = attachedTo->getResolvedMacro(attr)) {
macroName = macroDecl->getName().getBaseName();
} else {
macroName = decl->getASTContext().getIdentifier("__unknown_macro__");
}

// FIXME: attached macro discriminators should take attachedToName into
// account.
appendMacroExpansionOperator(
macroName.userFacingName(), role,
decl->getAttachedMacroDiscriminator(macroName, role, attr));
Expand Down
14 changes: 13 additions & 1 deletion lib/AST/Evaluator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "swift/AST/Evaluator.h"
#include "swift/AST/DeclContext.h"
#include "swift/AST/DiagnosticEngine.h"
#include "swift/AST/TypeCheckRequests.h" // for ResolveMacroRequest
#include "swift/Basic/LangOptions.h"
#include "swift/Basic/Range.h"
#include "swift/Basic/SourceManager.h"
Expand Down Expand Up @@ -61,14 +62,25 @@ Evaluator::Evaluator(DiagnosticEngine &diags, const LangOptions &opts)

bool Evaluator::checkDependency(const ActiveRequest &request) {
// Record this as an active request.
if (activeRequests.insert(request))
if (activeRequests.insert(request)) {
if (request.getAs<ResolveMacroRequest>())
++numActiveResolveMacroRequests;
return false;
}

// Diagnose cycle.
diagnoseCycle(request);
return true;
}

void Evaluator::finishedRequest(const ActiveRequest &request) {
if (request.getAs<ResolveMacroRequest>())
--numActiveResolveMacroRequests;

assert(activeRequests.back() == request);
activeRequests.pop_back();
}

void Evaluator::diagnoseCycle(const ActiveRequest &request) {
if (debugDumpCycles) {
const auto printIndent = [](llvm::raw_ostream &OS, unsigned indent) {
Expand Down
49 changes: 45 additions & 4 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ class swift::SourceLookupCache {

using AuxiliaryDeclMap = llvm::DenseMap<DeclName, TinyPtrVector<MissingDecl *>>;
AuxiliaryDeclMap TopLevelAuxiliaryDecls;

/// Top-level macros that produce arbitrary names.
SmallVector<MissingDecl *, 4> TopLevelArbitraryMacros;

SmallVector<Decl *, 4> MayHaveAuxiliaryDecls;
void populateAuxiliaryDeclCache();

Expand Down Expand Up @@ -352,26 +356,46 @@ void SourceLookupCache::populateAuxiliaryDeclCache() {
for (auto attrConst : decl->getAttrs().getAttributes<CustomAttr>()) {
auto *attr = const_cast<CustomAttr *>(attrConst);
UnresolvedMacroReference macroRef(attr);
bool introducesArbitraryNames = false;
namelookup::forEachPotentialResolvedMacro(
decl->getDeclContext()->getModuleScopeContext(),
macroRef.getMacroName(), MacroRole::Peer,
[&](MacroDecl *macro, const MacroRoleAttr *roleAttr) {
// First check for arbitrary names.
if (roleAttr->hasNameKind(MacroIntroducedDeclNameKind::Arbitrary)) {
introducesArbitraryNames = true;
}

macro->getIntroducedNames(MacroRole::Peer,
dyn_cast<ValueDecl>(decl),
introducedNames[attr]);
});

// Record this macro where appropriate.
if (introducesArbitraryNames)
TopLevelArbitraryMacros.push_back(MissingDecl::forUnexpandedMacro(attr, decl));
}

if (auto *med = dyn_cast<MacroExpansionDecl>(decl)) {
UnresolvedMacroReference macroRef(med);
bool introducesArbitraryNames = false;
namelookup::forEachPotentialResolvedMacro(
decl->getDeclContext()->getModuleScopeContext(),
macroRef.getMacroName(), MacroRole::Declaration,
[&](MacroDecl *macro, const MacroRoleAttr *roleAttr) {
// First check for arbitrary names.
if (roleAttr->hasNameKind(MacroIntroducedDeclNameKind::Arbitrary)) {
introducesArbitraryNames = true;
}

macro->getIntroducedNames(MacroRole::Declaration,
/*attachedTo*/ nullptr,
introducedNames[med]);
});

// Record this macro where appropriate.
if (introducesArbitraryNames)
TopLevelArbitraryMacros.push_back(MissingDecl::forUnexpandedMacro(med, decl));
}

// Add macro-introduced names to the top-level auxiliary decl cache as
Expand Down Expand Up @@ -440,14 +464,31 @@ void SourceLookupCache::lookupValue(DeclName Name, NLKind LookupKind,
? UniqueMacroNamePlaceholder
: Name;
auto auxDecls = TopLevelAuxiliaryDecls.find(keyName);
if (auxDecls == TopLevelAuxiliaryDecls.end())

// Check macro expansions that could produce this name.
SmallVector<MissingDecl *, 4> unexpandedDecls;
if (auxDecls != TopLevelAuxiliaryDecls.end()) {
unexpandedDecls.insert(
unexpandedDecls.end(), auxDecls->second.begin(), auxDecls->second.end());
}

// Check macro expansions that can produce arbitrary names.
unexpandedDecls.insert(
unexpandedDecls.end(),
TopLevelArbitraryMacros.begin(), TopLevelArbitraryMacros.end());

if (unexpandedDecls.empty())
return;

for (auto *unexpandedDecl : auxDecls->second) {
// Add expanded peers to the result.
// Add matching expanded peers and freestanding declarations to the results.
SmallPtrSet<ValueDecl *, 4> macroExpandedDecls;
for (auto *unexpandedDecl : unexpandedDecls) {
unexpandedDecl->forEachMacroExpandedDecl(
[&](ValueDecl *decl) {
Result.push_back(decl);
if (decl->getName().matchesRef(Name)) {
if (macroExpandedDecls.insert(decl).second)
Result.push_back(decl);
}
});
}
}
Expand Down
Loading