Skip to content

Commit ca1b731

Browse files
authored
Merge pull request #68032 from DougGregor/supersede-pre-macro-expansion-implied-conformances-5.9
2 parents a51f98d + 5fb5a27 commit ca1b731

File tree

7 files changed

+105
-64
lines changed

7 files changed

+105
-64
lines changed

include/swift/AST/DeclContext.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,15 +150,15 @@ enum class ConformanceEntryKind : unsigned {
150150
/// Explicitly specified.
151151
Explicit,
152152

153+
/// The conformance is generated by a macro that has not been
154+
/// expanded yet.
155+
PreMacroExpansion,
156+
153157
/// Implicitly synthesized.
154158
Synthesized,
155159

156160
/// Implied by an explicitly-specified conformance.
157161
Implied,
158-
159-
/// The conformance is generated by a macro that has not been
160-
/// expanded yet.
161-
PreMacroExpansion,
162162
};
163163

164164
/// Describes the kind of conformance lookup desired.

lib/AST/ConformanceLookupTable.h

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ class ConformanceLookupTable : public ASTAllocated<ConformanceLookupTable> {
147147
///
148148
/// The only difference between the ranking kind and the kind is
149149
/// that implied conformances originating from a synthesized
150-
/// conformance are considered to be synthesized (which has a
150+
/// or pre-macro-expansion conformance are considered to be synthesized (which has a
151151
/// lower ranking).
152152
ConformanceEntryKind getRankingKind() const {
153153
switch (auto kind = getKind()) {
@@ -157,11 +157,22 @@ class ConformanceLookupTable : public ASTAllocated<ConformanceLookupTable> {
157157
case ConformanceEntryKind::PreMacroExpansion:
158158
return kind;
159159

160-
case ConformanceEntryKind::Implied:
161-
return (getImpliedSource()->getDeclaredConformance()->getKind()
162-
== ConformanceEntryKind::Synthesized)
163-
? ConformanceEntryKind::Synthesized
164-
: ConformanceEntryKind::Implied;
160+
case ConformanceEntryKind::Implied: {
161+
auto impliedSourceKind =
162+
getImpliedSource()->getDeclaredConformance()->getKind();
163+
switch (impliedSourceKind) {
164+
case ConformanceEntryKind::Synthesized:
165+
case ConformanceEntryKind::PreMacroExpansion:
166+
return impliedSourceKind;
167+
168+
case ConformanceEntryKind::Explicit:
169+
case ConformanceEntryKind::Inherited:
170+
return ConformanceEntryKind::Implied;
171+
172+
case ConformanceEntryKind::Implied:
173+
return getImpliedSource()->getRankingKind();
174+
}
175+
}
165176
}
166177

167178
llvm_unreachable("Unhandled ConformanceEntryKind in switch.");

lib/Macros/Sources/SwiftMacros/OptionSetMacro.swift

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -123,27 +123,25 @@ public struct OptionSetMacro {
123123
}
124124
}
125125

126-
extension OptionSetMacro: ConformanceMacro {
127-
public static func expansion<
128-
Decl: DeclGroupSyntax,
129-
Context: MacroExpansionContext
130-
>(
126+
extension OptionSetMacro: ExtensionMacro {
127+
public static func expansion(
131128
of attribute: AttributeSyntax,
132-
providingConformancesOf decl: Decl,
133-
in context: Context
134-
) throws -> [(TypeSyntax, GenericWhereClauseSyntax?)] {
135-
// Decode the expansion arguments.
136-
guard let (structDecl, _, _) = decodeExpansion(of: attribute, attachedTo: decl, in: context) else {
137-
return []
138-
}
139-
129+
attachedTo decl: some DeclGroupSyntax,
130+
providingExtensionsOf type: some TypeSyntaxProtocol,
131+
conformingTo protocols: [TypeSyntax],
132+
in context: some MacroExpansionContext
133+
) throws -> [ExtensionDeclSyntax] {
140134
// If there is an explicit conformance to OptionSet already, don't add one.
141-
if let inheritedTypes = structDecl.inheritanceClause?.inheritedTypeCollection,
142-
inheritedTypes.contains(where: { inherited in inherited.typeName.trimmedDescription == "OptionSet" }) {
135+
if protocols.isEmpty {
143136
return []
144137
}
145138

146-
return [("OptionSet", nil)]
139+
let ext: DeclSyntax =
140+
"""
141+
extension \(type.trimmed): OptionSet {}
142+
"""
143+
144+
return [ext.cast(ExtensionDeclSyntax.self)]
147145
}
148146
}
149147

test/Index/index_macros.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,14 +207,16 @@ public struct SomeAccessorMacro: AccessorMacro {
207207
}
208208
}
209209

210-
public struct SomeConformanceMacro: ConformanceMacro {
210+
public struct SomeConformanceMacro: ExtensionMacro {
211211
public static func expansion(
212212
of node: AttributeSyntax,
213-
providingConformancesOf decl: some DeclGroupSyntax,
213+
attachedTo: some DeclGroupSyntax,
214+
providingExtensionsOf type: some TypeSyntaxProtocol,
215+
conformingTo protocols: [TypeSyntax],
214216
in context: some MacroExpansionContext
215-
) throws -> [(TypeSyntax, GenericWhereClauseSyntax?)] {
216-
let protocolName: TypeSyntax = "TestProto"
217-
return [(protocolName, nil)]
217+
) throws -> [ExtensionDeclSyntax] {
218+
let ext: DeclSyntax = "extension \(type.trimmed): TestProto {}"
219+
return [ext.cast(ExtensionDeclSyntax.self)]
218220
}
219221
}
220222

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,14 +1344,16 @@ public struct EmptyPeerMacro: PeerMacro {
13441344
}
13451345
}
13461346

1347-
public struct EquatableMacro: ConformanceMacro {
1347+
public struct EquatableMacro: ExtensionMacro {
13481348
public static func expansion(
13491349
of node: AttributeSyntax,
1350-
providingConformancesOf decl: some DeclGroupSyntax,
1350+
attachedTo: some DeclGroupSyntax,
1351+
providingExtensionsOf type: some TypeSyntaxProtocol,
1352+
conformingTo protocols: [TypeSyntax],
13511353
in context: some MacroExpansionContext
1352-
) throws -> [(TypeSyntax, GenericWhereClauseSyntax?)] {
1353-
let protocolName: TypeSyntax = "Equatable"
1354-
return [(protocolName, nil)]
1354+
) throws -> [ExtensionDeclSyntax] {
1355+
let ext: DeclSyntax = "extension \(type.trimmed): Equatable {}"
1356+
return [ext.cast(ExtensionDeclSyntax.self)]
13551357
}
13561358
}
13571359

@@ -1412,34 +1414,50 @@ public struct ConformanceViaExtensionMacro: ExtensionMacro {
14121414
}
14131415
}
14141416

1415-
public struct HashableMacro: ConformanceMacro {
1417+
public struct HashableMacro: ExtensionMacro {
1418+
public static func expansion(
1419+
of node: AttributeSyntax,
1420+
attachedTo: some DeclGroupSyntax,
1421+
providingExtensionsOf type: some TypeSyntaxProtocol,
1422+
conformingTo protocols: [TypeSyntax],
1423+
in context: some MacroExpansionContext
1424+
) throws -> [ExtensionDeclSyntax] {
1425+
let ext: DeclSyntax = "extension \(type.trimmed): Hashable {}"
1426+
return [ext.cast(ExtensionDeclSyntax.self)]
1427+
}
1428+
}
1429+
1430+
public struct ImpliesHashableMacro: ExtensionMacro {
14161431
public static func expansion(
14171432
of node: AttributeSyntax,
1418-
providingConformancesOf decl: some DeclGroupSyntax,
1433+
attachedTo: some DeclGroupSyntax,
1434+
providingExtensionsOf type: some TypeSyntaxProtocol,
1435+
conformingTo protocols: [TypeSyntax],
14191436
in context: some MacroExpansionContext
1420-
) throws -> [(TypeSyntax, GenericWhereClauseSyntax?)] {
1421-
let protocolName: TypeSyntax = "Hashable"
1422-
return [(protocolName, nil)]
1437+
) throws -> [ExtensionDeclSyntax] {
1438+
let ext: DeclSyntax = "extension \(type.trimmed): ImpliesHashable {}"
1439+
return [ext.cast(ExtensionDeclSyntax.self)]
14231440
}
14241441
}
14251442

1426-
public struct DelegatedConformanceMacro: ConformanceMacro, MemberMacro {
1443+
public struct DelegatedConformanceMacro: ExtensionMacro, MemberMacro {
14271444
public static func expansion(
14281445
of node: AttributeSyntax,
1429-
providingConformancesOf decl: some DeclGroupSyntax,
1446+
attachedTo: some DeclGroupSyntax,
1447+
providingExtensionsOf type: some TypeSyntaxProtocol,
1448+
conformingTo protocols: [TypeSyntax],
14301449
in context: some MacroExpansionContext
1431-
) throws -> [(TypeSyntax, GenericWhereClauseSyntax?)] {
1432-
let protocolName: TypeSyntax = "P"
1450+
) throws -> [ExtensionDeclSyntax] {
14331451
let conformance: DeclSyntax =
14341452
"""
1435-
extension Placeholder where Element: P {}
1453+
extension \(type.trimmed): P where Element: P {}
14361454
"""
14371455

14381456
guard let extensionDecl = conformance.as(ExtensionDeclSyntax.self) else {
14391457
return []
14401458
}
14411459

1442-
return [(protocolName, extensionDecl.genericWhereClause)]
1460+
return [extensionDecl]
14431461
}
14441462

14451463
public static func expansion(
@@ -1894,26 +1912,21 @@ public struct AddPeerStoredPropertyMacro: PeerMacro, Sendable {
18941912
}
18951913
}
18961914

1897-
public struct InitializableMacro: ConformanceMacro, MemberMacro {
1915+
public struct InitializableMacro: ExtensionMacro {
18981916
public static func expansion(
18991917
of node: AttributeSyntax,
1900-
providingConformancesOf decl: some DeclGroupSyntax,
1901-
in context: some MacroExpansionContext
1902-
) throws -> [(TypeSyntax, GenericWhereClauseSyntax?)] {
1903-
return [("Initializable", nil)]
1904-
}
1905-
1906-
public static func expansion(
1907-
of node: AttributeSyntax,
1908-
providingMembersOf decl: some DeclGroupSyntax,
1918+
attachedTo: some DeclGroupSyntax,
1919+
providingExtensionsOf type: some TypeSyntaxProtocol,
1920+
conformingTo protocols: [TypeSyntax],
19091921
in context: some MacroExpansionContext
1910-
) throws -> [DeclSyntax] {
1911-
let requirement: DeclSyntax =
1922+
) throws -> [ExtensionDeclSyntax] {
1923+
let ext: DeclSyntax =
19121924
"""
1913-
init(value: Int) {}
1925+
extension \(type.trimmed): Initializable {
1926+
init(value: Int) {}
1927+
}
19141928
"""
1915-
1916-
return [requirement]
1929+
return [ext.cast(ExtensionDeclSyntax.self)]
19171930
}
19181931
}
19191932

test/Macros/macro_expand_extensions.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
// RUN: not %target-swift-frontend -enable-experimental-feature ExtensionMacros -swift-version 5 -typecheck -load-plugin-library %t/%target-library-name(MacroDefinition) -module-name MacroUser -DTEST_DIAGNOSTICS -serialize-diagnostics-path %t/macro_expand.dia %s -emit-macro-expansion-files no-diagnostics
1111
// RUN: c-index-test -read-diagnostics %t/macro_expand.dia 2>&1 | %FileCheck -check-prefix CHECK-DIAGS %s
1212

13+
// Ensure that we can serialize this file as a module.
14+
// RUN: %target-swift-frontend -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) %s -I %t -disable-availability-checking -emit-module -o %t/MyModule.swiftmodule -enable-testing
15+
1316
// RUN: %target-build-swift -enable-experimental-feature ExtensionMacros -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) %s -o %t/main -module-name MacroUser -swift-version 5 -emit-tbd -emit-tbd-path %t/MacroUser.tbd -I %t
1417
// RUN: %target-codesign %t/main
1518
// RUN: %target-run %t/main | %FileCheck %s
@@ -198,3 +201,18 @@ func requiresEquatable<T: Equatable>(_: T) { }
198201
func testHasPropertyWrappers(hpw: HasPropertyWrappers) {
199202
requiresEquatable(hpw)
200203
}
204+
205+
// Check that conformances implied by a macro-defined conformance are serialized
206+
// without issue.
207+
public protocol ImpliesHashable: Hashable { }
208+
209+
@attached(extension, conformances: ImpliesHashable)
210+
macro ImpliesHashable() = #externalMacro(module: "MacroDefinition", type: "ImpliesHashableMacro")
211+
212+
func requiresHashable<T: Hashable>(_: T) { }
213+
func testMakeMeHashable(mmh: MakeMeHashable, dict: [MakeMeHashable: Int]) {
214+
requiresHashable(mmh)
215+
}
216+
217+
@ImpliesHashable
218+
public struct MakeMeHashable { }

test/Macros/top_level_freestanding.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,7 @@ macro Empty<T>(_ closure: () -> T) = #externalMacro(module: "MacroDefinition", t
117117
S(a: 10, b: 10)
118118
}
119119

120-
@attached(extension, conformances: Initializable)
121-
@attached(member, names: named(init))
120+
@attached(extension, conformances: Initializable, names: named(init))
122121
macro Initializable() = #externalMacro(module: "MacroDefinition", type: "InitializableMacro")
123122

124123
protocol Initializable {

0 commit comments

Comments
 (0)