Skip to content

Commit aaeb38d

Browse files
committed
[Macros] Expand extension macros at the top-level
Ensure we always expand extension macros after the top-level decl for the given attached decl. This ensures correct unqualified lookup behavior, and bans macro implementations from extending the unqualified name (they're expected to use `providingExtensionsOf` instead, which uses the qualified name). rdar://148119538
1 parent bc5c8f5 commit aaeb38d

File tree

4 files changed

+45
-1
lines changed

4 files changed

+45
-1
lines changed

lib/Sema/TypeCheckMacros.cpp

Lines changed: 5 additions & 1 deletion
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

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: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,17 @@ struct TestUndocumentedEncodable {}
161161

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

164+
@attached(extension)
165+
macro BadExtension() = #externalMacro(module: "MacroDefinition", type: "BadExtensionMacro")
166+
167+
// Make sure 'extension Foo' is rejected here as it needs to
168+
// be a qualified reference.
169+
struct HasSomeNestedType {
170+
@BadExtension // expected-note {{in expansion of macro 'BadExtension' on struct 'SomeNestedType' here}}
171+
struct SomeNestedType {}
172+
}
173+
// CHECK-DIAGS: error: cannot find type 'SomeNestedType' in scope
174+
164175
#endif
165176

166177
@attached(extension, conformances: Equatable)

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)