Skip to content

Commit 6fcd3f6

Browse files
committed
[Macros] Enable composition of member attribute macros and accessor macros.
1 parent ae1f824 commit 6fcd3f6

File tree

6 files changed

+126
-3
lines changed

6 files changed

+126
-3
lines changed

include/swift/AST/SourceFile.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,17 @@ class SourceFile final : public FileUnit {
500500
/// the \c SourceFileKind is \c MacroExpansion.
501501
ASTNode getMacroExpansion() const;
502502

503+
/// For source files created to hold the source code created by expanding
504+
/// an attached macro, this is the custom attribute that describes the macro
505+
/// expansion.
506+
///
507+
/// The source location of this attribute is the place in the source that
508+
/// triggered the creation of the macro expansion whose resulting source
509+
/// code is in this source file. This will only produce a non-null value when
510+
/// the \c SourceFileKind is \c MacroExpansion , and the macro is an attached
511+
/// macro.
512+
CustomAttr *getAttachedMacroAttribute() const;
513+
503514
/// When this source file is enclosed within another source file, for example
504515
/// because it describes a macro expansion, return the source file it was
505516
/// enclosed in.

lib/AST/Module.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,15 @@ ASTNode SourceFile::getMacroExpansion() const {
887887
return ASTNode::getFromOpaqueValue(genInfo.astNode);
888888
}
889889

890+
CustomAttr *SourceFile::getAttachedMacroAttribute() const {
891+
if (Kind != SourceFileKind::MacroExpansion)
892+
return nullptr;
893+
894+
auto genInfo =
895+
*getASTContext().SourceMgr.getGeneratedSourceInfo(*getBufferID());
896+
return genInfo.attachedMacroCustomAttr;
897+
}
898+
890899
SourceFile *SourceFile::getEnclosingSourceFile() const {
891900
auto macroExpansion = getMacroExpansion();
892901
if (!macroExpansion)

lib/Sema/TypeCheckMacros.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,17 @@ static bool isFromExpansionOfMacro(SourceFile *sourceFile, MacroDecl *macro) {
326326
// in it.
327327
if (expansionDecl->getMacro().getFullName() == macro->getName())
328328
return true;
329+
} else if (auto *macroAttr = sourceFile->getAttachedMacroAttribute()) {
330+
auto *decl = expansion.dyn_cast<Decl *>();
331+
auto &ctx = decl->getASTContext();
332+
auto attrDecl = evaluateOrDefault(ctx.evaluator,
333+
CustomAttrDeclRequest{macroAttr, decl->getDeclContext()},
334+
nullptr);
335+
auto *macroDecl = attrDecl.dyn_cast<MacroDecl *>();
336+
if (!macroDecl)
337+
return false;
338+
339+
return macroDecl == macro;
329340
} else {
330341
llvm_unreachable("Unknown macro expansion node kind");
331342
}

lib/Sema/TypeCheckStorage.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3441,7 +3441,7 @@ StorageImplInfoRequest::evaluate(Evaluator &evaluator,
34413441
}
34423442

34433443
// Check for an accessor macro.
3444-
for (auto customAttrConst : storage->getAttrs().getAttributes<CustomAttr>()) {
3444+
for (auto customAttrConst : storage->getSemanticAttrs().getAttributes<CustomAttr>()) {
34453445
auto customAttr = const_cast<CustomAttr *>(customAttrConst);
34463446
auto decl = evaluateOrDefault(
34473447
evaluator,
@@ -3457,8 +3457,8 @@ StorageImplInfoRequest::evaluate(Evaluator &evaluator,
34573457
if (!macro)
34583458
continue;
34593459

3460-
// FIXME: Make sure it's an accessors macro. We're not currently parsing
3461-
// this information in the @declaration attribute.
3460+
if (!macro->getMacroRoles().contains(MacroRole::Accessor))
3461+
continue;
34623462

34633463
// Expand the accessors.
34643464
expandAccessors(storage, customAttr, macro);

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,57 @@ public struct WrapAllProperties: MemberAttributeMacro {
273273
return [propertyWrapperAttr]
274274
}
275275
}
276+
277+
public struct TypeWrapperMacro: MemberAttributeMacro {
278+
public static func expansion(
279+
of node: AttributeSyntax,
280+
attachedTo decl: DeclSyntax,
281+
annotating member: DeclSyntax,
282+
in context: inout MacroExpansionContext
283+
) throws -> [AttributeSyntax] {
284+
guard let varDecl = member.as(VariableDeclSyntax.self),
285+
let binding = varDecl.bindings.first,
286+
let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier,
287+
binding.accessor == nil
288+
else {
289+
return []
290+
}
291+
292+
if identifier.text == "_storage" {
293+
return []
294+
}
295+
296+
let customAttr = AttributeSyntax(
297+
attributeName: SimpleTypeIdentifierSyntax(
298+
name: .identifier("accessViaStorage")
299+
)
300+
)
301+
302+
return [customAttr]
303+
}
304+
}
305+
306+
public struct AccessViaStorageMacro: AccessorDeclarationMacro {
307+
public static func expansion(
308+
of node: AttributeSyntax,
309+
attachedTo declaration: DeclSyntax,
310+
in context: inout MacroExpansionContext
311+
) throws -> [AccessorDeclSyntax] {
312+
guard let varDecl = declaration.as(VariableDeclSyntax.self),
313+
let binding = varDecl.bindings.first,
314+
let identifier = binding.pattern.as(IdentifierPatternSyntax.self)?.identifier,
315+
binding.accessor == nil
316+
else {
317+
return []
318+
}
319+
320+
if identifier.text == "_storage" {
321+
return []
322+
}
323+
324+
return [
325+
"get { _storage.\(identifier) }",
326+
"set { _storage.\(identifier) = newValue }",
327+
]
328+
}
329+
}

test/Macros/composed_macro.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -I %swift-host-lib-dir -L %swift-host-lib-dir -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath
3+
// RUNx: %target-swift-frontend -dump-ast -enable-experimental-feature Macros -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir %s -module-name MacroUser 2>&1 | %FileCheck --check-prefix CHECK-AST %s
4+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature Macros -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir -module-name MacroUser -DTEST_DIAGNOSTICS -swift-version 5
5+
// RUN: %target-build-swift -enable-experimental-feature Macros -load-plugin-library %t/%target-library-name(MacroDefinition) -I %swift-host-lib-dir -L %swift-host-lib-dir %s -o %t/main -module-name MacroUser -swift-version 5
6+
// RUN: %target-run %t/main | %FileCheck %s
7+
// REQUIRES: executable_test
8+
9+
// FIXME: Swift parser is not enabled on Linux CI yet.
10+
// REQUIRES: OS=macosx
11+
12+
@attached(memberAttributes) macro myTypeWrapper() = #externalMacro(module: "MacroDefinition", type: "TypeWrapperMacro")
13+
@attached(accessor) macro accessViaStorage() = #externalMacro(module: "MacroDefinition", type: "AccessViaStorageMacro")
14+
15+
struct _Storage {
16+
var x: Int = 0 {
17+
willSet { print("setting \(newValue)") }
18+
}
19+
var y: Int = 0 {
20+
willSet { print("setting \(newValue)") }
21+
}
22+
}
23+
24+
@myTypeWrapper
25+
struct S {
26+
var _storage = _Storage()
27+
28+
var x: Int
29+
var y: Int
30+
}
31+
32+
var s = S()
33+
34+
// CHECK: setting 10
35+
s.x = 10
36+
37+
// CHECK: setting 100
38+
s.y = 100

0 commit comments

Comments
 (0)