Skip to content

Commit 0b8c335

Browse files
committed
[Macros] Allow custom attributes to resolve to attached macro declarations.
Introduce appropriate name lookup for custom attributes to find macros at module scope, and prefer those to types of the same name. We don't do anything with the macros we found other than ignore them, for the moment.
1 parent 69649a4 commit 0b8c335

File tree

5 files changed

+89
-3
lines changed

5 files changed

+89
-3
lines changed

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.

lib/AST/NameLookup.cpp

Lines changed: 49 additions & 1 deletion
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+
/// 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+
30433085
MacroOrNominalTypeDecl
30443086
CustomAttrDeclRequest::evaluate(Evaluator &evaluator,
3045-
CustomAttr *attr, DeclContext *dc) const {
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: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3558,8 +3558,14 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
35583558

35593559
// FIXME: deal with macros.
35603560
NominalTypeDecl *nominal = nullptr;
3561-
if (found)
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+
35623567
nominal = found.dyn_cast<NominalTypeDecl *>();
3568+
}
35633569

35643570
// Diagnose errors.
35653571
if (!found) {
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)