Skip to content

Commit 700bcb4

Browse files
authored
Merge pull request #62990 from DougGregor/attached-macros-as-custom-attrs
2 parents 3bfe7a4 + 0b8c335 commit 700bcb4

14 files changed

+150
-33
lines changed

include/swift/AST/Attr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1712,7 +1712,7 @@ class CustomAttr final : public DeclAttribute {
17121712
}
17131713

17141714
private:
1715-
friend class CustomAttrNominalRequest;
1715+
friend class CustomAttrDeclRequest;
17161716
void resetTypeInformation(TypeExpr *repr);
17171717

17181718
private:

include/swift/AST/DiagnosticsCommon.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ NOTE(in_macro_expansion,none,
221221
"in expansion of macro %0 here", (DeclName))
222222
ERROR(macro_experimental,none,
223223
"macros are an experimental feature that is not enabled", ())
224+
ERROR(ambiguous_macro_reference,none,
225+
"ambiguous reference to macro %0", (DeclName))
224226

225227
//------------------------------------------------------------------------------
226228
// MARK: bridged diagnostics

include/swift/AST/MacroDeclaration.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ enum class MacroContext: uint8_t {
3030
/// A freestanding declaration macro.
3131
FreestandingDeclaration = 0x02,
3232
/// An attached declaration macro.
33-
AttachedDeclaration = 0x03,
33+
AttachedDeclaration = 0x04,
3434
};
3535

3636
/// The contexts in which a particular macro declaration can be used.

include/swift/AST/NameLookupRequests.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -323,11 +323,14 @@ class TypeDeclsFromWhereClauseRequest :
323323
ExtensionDecl *ext) const;
324324
};
325325

326-
/// Request the nominal type declaration to which the given custom attribute
327-
/// refers.
328-
class CustomAttrNominalRequest :
329-
public SimpleRequest<CustomAttrNominalRequest,
330-
NominalTypeDecl *(CustomAttr *, DeclContext *),
326+
using MacroOrNominalTypeDecl =
327+
llvm::PointerUnion<MacroDecl *, NominalTypeDecl *>;
328+
329+
/// Request the macro or nominal type declaration to which the given custom
330+
/// attribute refers.
331+
class CustomAttrDeclRequest :
332+
public SimpleRequest<CustomAttrDeclRequest,
333+
MacroOrNominalTypeDecl(CustomAttr *, DeclContext *),
331334
RequestFlags::Cached> {
332335
public:
333336
using SimpleRequest::SimpleRequest;
@@ -336,7 +339,7 @@ class CustomAttrNominalRequest :
336339
friend SimpleRequest;
337340

338341
// Evaluation.
339-
NominalTypeDecl *
342+
MacroOrNominalTypeDecl
340343
evaluate(Evaluator &evaluator, CustomAttr *attr, DeclContext *dc) const;
341344

342345
public:

include/swift/AST/NameLookupTypeIDZone.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
SWIFT_REQUEST(NameLookup, AnyObjectLookupRequest,
1919
QualifiedLookupResult(const DeclContext *, DeclName, NLOptions),
2020
Uncached, NoLocationInfo)
21-
SWIFT_REQUEST(NameLookup, CustomAttrNominalRequest,
22-
NominalTypeDecl *(CustomAttr *, DeclContext *), Cached,
21+
SWIFT_REQUEST(NameLookup, CustomAttrDeclRequest,
22+
MacroOrNominalTypeDecl(CustomAttr *, DeclContext *), Cached,
2323
NoLocationInfo)
2424
SWIFT_REQUEST(NameLookup, DirectLookupRequest,
2525
TinyPtrVector<ValueDecl *>(DirectLookupDescriptor), Uncached,

lib/AST/Decl.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6807,8 +6807,11 @@ VarDecl::getAttachedPropertyWrapperTypeInfo(unsigned i) const {
68076807
auto attr = attrs[i];
68086808
auto dc = getDeclContext();
68096809
ASTContext &ctx = getASTContext();
6810-
nominal = evaluateOrDefault(
6811-
ctx.evaluator, CustomAttrNominalRequest{attr, dc}, nullptr);
6810+
if (auto found = evaluateOrDefault(
6811+
ctx.evaluator, CustomAttrDeclRequest{attr, dc}, nullptr))
6812+
nominal = found.dyn_cast<NominalTypeDecl *>();
6813+
else
6814+
nominal = nullptr;
68126815
}
68136816

68146817
if (!nominal)
@@ -9748,7 +9751,8 @@ NominalTypeDecl *
97489751
ValueDecl::getRuntimeDiscoverableAttrTypeDecl(CustomAttr *attr) const {
97499752
auto &ctx = getASTContext();
97509753
auto *nominal = evaluateOrDefault(
9751-
ctx.evaluator, CustomAttrNominalRequest{attr, getDeclContext()}, nullptr);
9754+
ctx.evaluator, CustomAttrDeclRequest{attr, getDeclContext()}, nullptr)
9755+
.get<NominalTypeDecl *>();
97529756
assert(nominal->getAttrs().hasAttribute<RuntimeMetadataAttr>());
97539757
return nominal;
97549758
}

lib/AST/NameLookup.cpp

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3040,9 +3040,57 @@ GenericParamListRequest::evaluate(Evaluator &evaluator, GenericContext *value) c
30403040
parsedGenericParams->getRAngleLoc());
30413041
}
30423042

3043-
NominalTypeDecl *
3044-
CustomAttrNominalRequest::evaluate(Evaluator &evaluator,
3045-
CustomAttr *attr, DeclContext *dc) const {
3043+
/// Perform lookup to determine whether the given custom attribute refers to
3044+
/// a macro declaration, and return that macro declaration.
3045+
static MacroDecl *findMacroForCustomAttr(CustomAttr *attr, DeclContext *dc) {
3046+
auto *identTypeRepr = dyn_cast_or_null<IdentTypeRepr>(attr->getTypeRepr());
3047+
if (!identTypeRepr)
3048+
return nullptr;
3049+
3050+
// Look for macros at module scope. They can only occur at module scope, and
3051+
// we need to be sure not to trigger name lookup into type contexts along
3052+
// the way.
3053+
llvm::TinyPtrVector<MacroDecl *> macros;
3054+
auto moduleScopeDC = dc->getModuleScopeContext();
3055+
ASTContext &ctx = moduleScopeDC->getASTContext();
3056+
UnqualifiedLookupDescriptor descriptor(
3057+
identTypeRepr->getNameRef(), moduleScopeDC
3058+
);
3059+
auto lookup = evaluateOrDefault(
3060+
ctx.evaluator, UnqualifiedLookupRequest{descriptor}, {});
3061+
for (const auto &result : lookup.allResults()) {
3062+
// Only keep attached macros, which can be spelled as custom attributes.
3063+
if (auto macro = dyn_cast<MacroDecl>(result.getValueDecl()))
3064+
if (macro->getMacroContexts().contains(MacroContext::AttachedDeclaration))
3065+
macros.push_back(macro);
3066+
}
3067+
3068+
if (macros.empty())
3069+
return nullptr;
3070+
3071+
if (macros.size() > 1) {
3072+
ctx.Diags.diagnose(attr->getLocation(), diag::ambiguous_macro_reference,
3073+
identTypeRepr->getNameRef().getFullName());
3074+
3075+
for (auto macro : macros) {
3076+
macro->diagnose(
3077+
diag::kind_declname_declared_here, macro->getDescriptiveKind(),
3078+
macro->getName());
3079+
}
3080+
}
3081+
3082+
return macros.front();
3083+
}
3084+
3085+
MacroOrNominalTypeDecl
3086+
CustomAttrDeclRequest::evaluate(Evaluator &evaluator,
3087+
CustomAttr *attr, DeclContext *dc) const {
3088+
// Look for names at module scope, so we don't trigger name lookup for
3089+
// nested scopes. At this point, we're looking to see whether there are
3090+
// any suitable macros.
3091+
if (auto macro = findMacroForCustomAttr(attr, dc))
3092+
return macro;
3093+
30463094
// Find the types referenced by the custom attribute.
30473095
auto &ctx = dc->getASTContext();
30483096
DirectlyReferencedTypeDecls decls;

lib/Sema/TypeCheckAttr.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3553,11 +3553,22 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
35533553
auto dc = D->getDeclContext();
35543554

35553555
// Figure out which nominal declaration this custom attribute refers to.
3556-
auto nominal = evaluateOrDefault(
3557-
Ctx.evaluator, CustomAttrNominalRequest{attr, dc}, nullptr);
3556+
auto found = evaluateOrDefault(
3557+
Ctx.evaluator, CustomAttrDeclRequest{attr, dc}, nullptr);
3558+
3559+
// FIXME: deal with macros.
3560+
NominalTypeDecl *nominal = nullptr;
3561+
if (found) {
3562+
// FIXME: Do full checking of the macro arguments here by turning it into
3563+
// a macro expansion expression (?).
3564+
if (found.is<MacroDecl *>())
3565+
return;
3566+
3567+
nominal = found.dyn_cast<NominalTypeDecl *>();
3568+
}
35583569

35593570
// Diagnose errors.
3560-
if (!nominal) {
3571+
if (!found) {
35613572
auto typeRepr = attr->getTypeRepr();
35623573

35633574
auto type = TypeResolution::forInterface(dc, TypeResolverContext::CustomAttr,
@@ -7377,12 +7388,15 @@ static void forEachCustomAttribute(
73777388
for (auto *attr : decl->getAttrs().getAttributes<CustomAttr>()) {
73787389
auto *mutableAttr = const_cast<CustomAttr *>(attr);
73797390

7380-
auto *nominal = evaluateOrDefault(
7391+
auto found = evaluateOrDefault(
73817392
ctx.evaluator,
7382-
CustomAttrNominalRequest{mutableAttr, decl->getDeclContext()}, nullptr);
7393+
CustomAttrDeclRequest{mutableAttr, decl->getDeclContext()}, nullptr);
7394+
if (!found)
7395+
continue;
73837396

7397+
auto nominal = found.dyn_cast<NominalTypeDecl *>();
73847398
if (!nominal)
7385-
continue;
7399+
continue; // FIXME: add another entry point for macros we've found
73867400

73877401
if (nominal->getAttrs().hasAttribute<ATTR>())
73887402
fn(mutableAttr, nominal);

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,11 +257,15 @@ swift::checkGlobalActorAttributes(
257257
NominalTypeDecl *globalActorNominal = nullptr;
258258
for (auto attr : attrs) {
259259
// Figure out which nominal declaration this custom attribute refers to.
260-
auto nominal = evaluateOrDefault(ctx.evaluator,
261-
CustomAttrNominalRequest{attr, dc},
262-
nullptr);
260+
auto found = evaluateOrDefault(ctx.evaluator,
261+
CustomAttrDeclRequest{attr, dc},
262+
nullptr);
263263

264264
// Ignore unresolvable custom attributes.
265+
if (!found)
266+
continue;
267+
268+
auto nominal = found.dyn_cast<NominalTypeDecl *>();
265269
if (!nominal)
266270
continue;
267271

lib/Sema/TypeCheckPropertyWrapper.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -439,8 +439,12 @@ AttachedPropertyWrappersRequest::evaluate(Evaluator &evaluator,
439439
for (auto attr : var->getAttrs().getAttributes<CustomAttr>()) {
440440
auto mutableAttr = const_cast<CustomAttr *>(attr);
441441
// Figure out which nominal declaration this custom attribute refers to.
442-
auto nominal = evaluateOrDefault(
443-
ctx.evaluator, CustomAttrNominalRequest{mutableAttr, dc}, nullptr);
442+
auto found = evaluateOrDefault(
443+
ctx.evaluator, CustomAttrDeclRequest{mutableAttr, dc}, nullptr);
444+
445+
NominalTypeDecl *nominal = nullptr;
446+
if (found)
447+
nominal = found.dyn_cast<NominalTypeDecl *>();
444448

445449
// If we didn't find a nominal type with a @propertyWrapper attribute,
446450
// skip this custom attribute.

lib/Sema/TypeCheckRequestFunctions.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,15 @@ AttachedResultBuilderRequest::evaluate(Evaluator &evaluator,
174174
for (auto attr : decl->getAttrs().getAttributes<CustomAttr>()) {
175175
auto mutableAttr = const_cast<CustomAttr *>(attr);
176176
// Figure out which nominal declaration this custom attribute refers to.
177-
auto nominal = evaluateOrDefault(ctx.evaluator,
178-
CustomAttrNominalRequest{mutableAttr, dc},
179-
nullptr);
177+
auto found = evaluateOrDefault(ctx.evaluator,
178+
CustomAttrDeclRequest{mutableAttr, dc},
179+
nullptr);
180180

181181
// Ignore unresolvable custom attributes.
182+
if (!found)
183+
continue;
184+
185+
auto nominal = found.dyn_cast<NominalTypeDecl *>();
182186
if (!nominal)
183187
continue;
184188

lib/Sema/TypeCheckType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5022,7 +5022,7 @@ Type CustomAttrTypeRequest::evaluate(Evaluator &eval, CustomAttr *attr,
50225022

50235023
// We always require the type to resolve to a nominal type. If the type was
50245024
// not a nominal type, we should have already diagnosed an error via
5025-
// CustomAttrNominalRequest.
5025+
// CustomAttrDeclRequest.
50265026
auto checkType = [](Type type) -> bool {
50275027
while (auto *genericDecl = type->getAnyGeneric()) {
50285028
if (isa<NominalTypeDecl>(genericDecl))

lib/Sema/TypeCheckTypeWrapper.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,13 @@ static void getTypeWrappers(NominalTypeDecl *decl,
123123
// Attributes applied directly to the type.
124124
for (auto *attr : decl->getAttrs().getAttributes<CustomAttr>()) {
125125
auto *mutableAttr = const_cast<CustomAttr *>(attr);
126-
auto *nominal = evaluateOrDefault(
127-
ctx.evaluator, CustomAttrNominalRequest{mutableAttr, decl}, nullptr);
126+
auto found = evaluateOrDefault(
127+
ctx.evaluator, CustomAttrDeclRequest{mutableAttr, decl}, nullptr);
128128

129+
if (!found)
130+
continue;
131+
132+
auto nominal = found.dyn_cast<NominalTypeDecl *>();
129133
if (!nominal)
130134
continue;
131135

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature Macros -module-name MacrosTest
2+
3+
@declaration(attached) macro m1: Void = #externalMacro(module: "MyMacros", type: "Macro1")
4+
// expected-warning@-1{{external macro implementation type 'MyMacros.Macro1' could not be found for macro 'm1'}}
5+
6+
@declaration(attached) macro m2(_: Int) -> Void = #externalMacro(module: "MyMacros", type: "Macro2")
7+
// expected-warning@-1{{external macro implementation type 'MyMacros.Macro2' could not be found for macro 'm2'}}
8+
// expected-note@-2 2{{macro 'm2' declared here}}
9+
10+
@declaration(attached) macro m2(_: Double) -> Void = #externalMacro(module: "MyMacros", type: "Macro2")
11+
// expected-warning@-1{{external macro implementation type 'MyMacros.Macro2' could not be found for macro 'm2'}}
12+
// expected-note@-2 2{{macro 'm2' declared here}}
13+
14+
@m1 struct X1 { }
15+
16+
// FIXME: Redundant diagnostic
17+
@m2 struct X2 { } // expected-error 2{{ambiguous reference to macro 'm2'}}
18+
19+
// Check for nesting rules.
20+
struct SkipNestedType {
21+
@propertyWrapper
22+
struct m1<T> {
23+
init() { }
24+
25+
var wrappedValue: T
26+
}
27+
28+
// We select the macro, not the property wrapper.
29+
@m1 var x: Int = 0
30+
}

0 commit comments

Comments
 (0)