mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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
This commit is contained in:
@@ -957,8 +957,12 @@ static CharSourceRange getExpansionInsertionRange(MacroRole role,
|
||||
}
|
||||
|
||||
case MacroRole::Extension: {
|
||||
// Extensions are expanded at the top-level.
|
||||
auto *NTD = cast<NominalTypeDecl>(target.get<Decl *>());
|
||||
auto *topLevelDecl = NTD->getTopmostDeclarationDeclContext();
|
||||
|
||||
SourceLoc afterDeclLoc =
|
||||
Lexer::getLocForEndOfToken(sourceMgr, target.getEndLoc());
|
||||
Lexer::getLocForEndOfToken(sourceMgr, topLevelDecl->getEndLoc());
|
||||
return CharSourceRange(afterDeclLoc, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -1628,6 +1628,20 @@ public struct FooExtensionMacro: ExtensionMacro {
|
||||
}
|
||||
}
|
||||
|
||||
public struct BadExtensionMacro: ExtensionMacro {
|
||||
public static func expansion(
|
||||
of node: AttributeSyntax,
|
||||
attachedTo declaration: some DeclGroupSyntax,
|
||||
providingExtensionsOf type: some TypeSyntaxProtocol,
|
||||
conformingTo protocols: [TypeSyntax],
|
||||
in context: some MacroExpansionContext
|
||||
) throws -> [ExtensionDeclSyntax] {
|
||||
// Note this is purposefully not using `providingExtensionsOf`.
|
||||
let unqualifiedName = declaration.as(StructDeclSyntax.self)!.name.trimmed
|
||||
return [try ExtensionDeclSyntax("extension \(unqualifiedName) {}")]
|
||||
}
|
||||
}
|
||||
|
||||
public struct ConformanceViaExtensionMacro: ExtensionMacro {
|
||||
public static func expansion(
|
||||
of node: AttributeSyntax,
|
||||
|
||||
@@ -161,6 +161,17 @@ struct TestUndocumentedEncodable {}
|
||||
|
||||
// CHECK-DIAGS: error: conformance to 'Codable' (aka 'Decodable & Encodable') is not covered by macro 'UndocumentedEncodable'
|
||||
|
||||
@attached(extension)
|
||||
macro BadExtension() = #externalMacro(module: "MacroDefinition", type: "BadExtensionMacro")
|
||||
|
||||
// Make sure 'extension Foo' is rejected here as it needs to
|
||||
// be a qualified reference.
|
||||
struct HasSomeNestedType {
|
||||
@BadExtension // expected-note {{in expansion of macro 'BadExtension' on struct 'SomeNestedType' here}}
|
||||
struct SomeNestedType {}
|
||||
}
|
||||
// CHECK-DIAGS: error: cannot find type 'SomeNestedType' in scope
|
||||
|
||||
#endif
|
||||
|
||||
@attached(extension, conformances: Equatable)
|
||||
|
||||
@@ -121,6 +121,14 @@ func remoteCall<Result: ConjureRemoteValue>(function: String, arguments: [String
|
||||
return Result.conjureValue()
|
||||
}
|
||||
|
||||
@attached(extension, conformances: Equatable)
|
||||
macro AddEquatable() = #externalMacro(module: "MacroDefinition", type: "EquatableMacro")
|
||||
|
||||
struct HasNestedType {
|
||||
@AddEquatable
|
||||
struct Inner {}
|
||||
}
|
||||
|
||||
// REQUIRES: swift_swift_parser, executable_test, shell, asserts
|
||||
// REQUIRES: swift_feature_PreambleMacros
|
||||
|
||||
@@ -379,3 +387,10 @@ func remoteCall<Result: ConjureRemoteValue>(function: String, arguments: [String
|
||||
// BODY_EXPAND-NEXT: return try await remoteCall(function: "f", arguments: ["a": a, "b": b])
|
||||
// BODY_EXPAND-NEXT: }"
|
||||
// BODY_EXPAND-NEXT: source.edit.kind.active:
|
||||
|
||||
// Make sure the extension is added at the top level.
|
||||
// RUN: %sourcekitd-test -req=refactoring.expand.macro -pos=128:4 %s -- ${COMPILER_ARGS[@]} | %FileCheck -check-prefix=ADD_EQUATABLE_EXPAND %s
|
||||
// ADD_EQUATABLE_EXPAND: source.edit.kind.active:
|
||||
// ADD_EQUATABLE_EXPAND-NEXT: 130:2-130:2 (@__swiftmacro_9MacroUser13HasNestedTypeV5Inner12AddEquatablefMe_.swift) "extension HasNestedType.Inner: Equatable {
|
||||
// ADD_EQUATABLE_EXPAND-NEXT: }"
|
||||
// ADD_EQUATABLE_EXPAND-NEXT: source.edit.kind.active:
|
||||
|
||||
Reference in New Issue
Block a user