Skip to content

Commit 4efe08e

Browse files
authored
Merge pull request #80379 from hamishknight/extendable-expansion
2 parents 7bf2994 + a359816 commit 4efe08e

File tree

6 files changed

+56
-17
lines changed

6 files changed

+56
-17
lines changed

lib/Sema/TypeCheckMacros.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -957,8 +957,12 @@ static CharSourceRange getExpansionInsertionRange(MacroRole role,
957957
}
958958

959959
case MacroRole::Extension: {
960+
// Extensions are expanded at the top-level.
961+
auto *NTD = cast<NominalTypeDecl>(target.get<Decl *>());
962+
auto *topLevelDecl = NTD->getTopmostDeclarationDeclContext();
963+
960964
SourceLoc afterDeclLoc =
961-
Lexer::getLocForEndOfToken(sourceMgr, target.getEndLoc());
965+
Lexer::getLocForEndOfToken(sourceMgr, topLevelDecl->getEndLoc());
962966
return CharSourceRange(afterDeclLoc, 0);
963967
}
964968

@@ -2095,7 +2099,7 @@ std::optional<unsigned> swift::expandExtensions(CustomAttr *attr,
20952099
MacroDecl *macro,
20962100
MacroRole role,
20972101
NominalTypeDecl *nominal) {
2098-
if (nominal->getDeclContext()->isLocalContext()) {
2102+
if (nominal->getLocalContext()) {
20992103
nominal->diagnose(diag::local_extension_macro);
21002104
return std::nullopt;
21012105
}

test/ConstExtraction/Inputs/Macros.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,9 @@ public struct AddExtensionMacro: ExtensionMacro {
4141
conformingTo protocols: [TypeSyntax],
4242
in context: some MacroExpansionContext
4343
) throws -> [ExtensionDeclSyntax] {
44-
let typeName = declaration.declGroupName
4544
return protocols.map {
4645
("""
47-
extension \(typeName): \($0) {
46+
extension \(type.trimmed): \($0) {
4847
struct _Extension_\($0): \($0) {
4948
var nested = 8
5049
}
@@ -53,8 +52,8 @@ public struct AddExtensionMacro: ExtensionMacro {
5352
.cast(ExtensionDeclSyntax.self)
5453
} + [
5554
("""
56-
extension \(typeName) {
57-
static let _extension_\(typeName) = 3
55+
extension \(type.trimmed) {
56+
static let _extension_\(declaration.declGroupName) = 3
5857
}
5958
""" as DeclSyntax).cast(ExtensionDeclSyntax.self)
6059
]

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,20 @@ public struct FooExtensionMacro: ExtensionMacro {
16281628
}
16291629
}
16301630

1631+
public struct BadExtensionMacro: ExtensionMacro {
1632+
public static func expansion(
1633+
of node: AttributeSyntax,
1634+
attachedTo declaration: some DeclGroupSyntax,
1635+
providingExtensionsOf type: some TypeSyntaxProtocol,
1636+
conformingTo protocols: [TypeSyntax],
1637+
in context: some MacroExpansionContext
1638+
) throws -> [ExtensionDeclSyntax] {
1639+
// Note this is purposefully not using `providingExtensionsOf`.
1640+
let unqualifiedName = declaration.as(StructDeclSyntax.self)!.name.trimmed
1641+
return [try ExtensionDeclSyntax("extension \(unqualifiedName) {}")]
1642+
}
1643+
}
1644+
16311645
public struct ConformanceViaExtensionMacro: ExtensionMacro {
16321646
public static func expansion(
16331647
of node: AttributeSyntax,

test/Macros/macro_expand_extensions.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ func testLocal() {
115115
@DelegatedConformance
116116
struct Local<Element> {}
117117
// expected-error@-1{{local type cannot have attached extension macro}}
118+
119+
struct S {
120+
@DelegatedConformance
121+
struct Local<Element> {}
122+
// expected-error@-1{{local type cannot have attached extension macro}}
123+
}
118124
}
119125

120126
@DelegatedConformance
@@ -161,6 +167,17 @@ struct TestUndocumentedEncodable {}
161167

162168
// CHECK-DIAGS: error: conformance to 'Codable' (aka 'Decodable & Encodable') is not covered by macro 'UndocumentedEncodable'
163169

170+
@attached(extension)
171+
macro BadExtension() = #externalMacro(module: "MacroDefinition", type: "BadExtensionMacro")
172+
173+
// Make sure 'extension Foo' is rejected here as it needs to
174+
// be a qualified reference.
175+
struct HasSomeNestedType {
176+
@BadExtension // expected-note {{in expansion of macro 'BadExtension' on struct 'SomeNestedType' here}}
177+
struct SomeNestedType {}
178+
}
179+
// CHECK-DIAGS: error: cannot find type 'SomeNestedType' in scope
180+
164181
#endif
165182

166183
@attached(extension, conformances: Equatable)

test/Reflection/Inputs/Macros.swift

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,9 @@ public struct AddExtensionMacro: ExtensionMacro {
4040
conformingTo protocols: [TypeSyntax],
4141
in context: some MacroExpansionContext
4242
) throws -> [ExtensionDeclSyntax] {
43-
let typeName = declaration.declGroupName
4443
return protocols.map {
4544
("""
46-
extension \(typeName): \($0) {
45+
extension \(type.trimmed): \($0) {
4746
struct _Extension_\($0): \($0) {}
4847
}
4948
""" as DeclSyntax)
@@ -66,12 +65,3 @@ extension DeclSyntaxProtocol {
6665
fatalError("Not implemented")
6766
}
6867
}
69-
70-
extension DeclGroupSyntax {
71-
var declGroupName: TokenSyntax {
72-
if let structDecl = self.as(StructDeclSyntax.self) {
73-
return structDecl.name.trimmed
74-
}
75-
fatalError("Not implemented")
76-
}
77-
}

test/SourceKit/Macros/macro_basic.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,14 @@ func remoteCall<Result: ConjureRemoteValue>(function: String, arguments: [String
121121
return Result.conjureValue()
122122
}
123123

124+
@attached(extension, conformances: Equatable)
125+
macro AddEquatable() = #externalMacro(module: "MacroDefinition", type: "EquatableMacro")
126+
127+
struct HasNestedType {
128+
@AddEquatable
129+
struct Inner {}
130+
}
131+
124132
// REQUIRES: swift_swift_parser, executable_test, shell, asserts
125133
// REQUIRES: swift_feature_PreambleMacros
126134

@@ -379,3 +387,10 @@ func remoteCall<Result: ConjureRemoteValue>(function: String, arguments: [String
379387
// BODY_EXPAND-NEXT: return try await remoteCall(function: "f", arguments: ["a": a, "b": b])
380388
// BODY_EXPAND-NEXT: }"
381389
// BODY_EXPAND-NEXT: source.edit.kind.active:
390+
391+
// Make sure the extension is added at the top level.
392+
// RUN: %sourcekitd-test -req=refactoring.expand.macro -pos=128:4 %s -- ${COMPILER_ARGS[@]} | %FileCheck -check-prefix=ADD_EQUATABLE_EXPAND %s
393+
// ADD_EQUATABLE_EXPAND: source.edit.kind.active:
394+
// ADD_EQUATABLE_EXPAND-NEXT: 130:2-130:2 (@__swiftmacro_9MacroUser13HasNestedTypeV5Inner12AddEquatablefMe_.swift) "extension HasNestedType.Inner: Equatable {
395+
// ADD_EQUATABLE_EXPAND-NEXT: }"
396+
// ADD_EQUATABLE_EXPAND-NEXT: source.edit.kind.active:

0 commit comments

Comments
 (0)