Skip to content

Commit aaa442b

Browse files
committed
Always supersede conformances implied by pre-macro-expansion conformances
Pre-macro-expansion conformances are introduced at the point where an attached extension macro is attached to a particular nominal type, and can imply other conformances. Once the macro is expanded, they are expected to be replaced by the real conformance from the extension produced by the macro. This includes any other conformances that are implied by that conformances. Ensure that the real conformance---and every conformances it implies---are considered "better" than the pre-expansion conformances. Fixes a bug where we would pick the wrong (pre-expansion) conformances, which would then fail to get fully type-checked prior to serialization. This could accept invalid code that then crashed the compiler, as in rdar://112916159. (cherry picked from commit ab576b3) (cherry picked from commit 5fb5a27)
1 parent 2aaa983 commit aaa442b

File tree

4 files changed

+52
-10
lines changed

4 files changed

+52
-10
lines changed

include/swift/AST/DeclContext.h

+4-4
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

+17-6
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.");

test/Macros/Inputs/syntax_macro_definitions.swift

+13
Original file line numberDiff line numberDiff line change
@@ -1403,6 +1403,19 @@ public struct HashableMacro: ConformanceMacro {
14031403
}
14041404
}
14051405

1406+
public struct ImpliesHashableMacro: ExtensionMacro {
1407+
public static func expansion(
1408+
of node: AttributeSyntax,
1409+
attachedTo: some DeclGroupSyntax,
1410+
providingExtensionsOf type: some TypeSyntaxProtocol,
1411+
conformingTo protocols: [TypeSyntax],
1412+
in context: some MacroExpansionContext
1413+
) throws -> [ExtensionDeclSyntax] {
1414+
let ext: DeclSyntax = "extension \(type.trimmed): ImpliesHashable {}"
1415+
return [ext.cast(ExtensionDeclSyntax.self)]
1416+
}
1417+
}
1418+
14061419
public struct DelegatedConformanceMacro: ConformanceMacro, MemberMacro {
14071420
public static func expansion(
14081421
of node: AttributeSyntax,

test/Macros/macro_expand_extensions.swift

+18
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
@@ -184,3 +187,18 @@ func requiresEquatable<T: Equatable>(_: T) { }
184187
func testHasPropertyWrappers(hpw: HasPropertyWrappers) {
185188
requiresEquatable(hpw)
186189
}
190+
191+
// Check that conformances implied by a macro-defined conformance are serialized
192+
// without issue.
193+
public protocol ImpliesHashable: Hashable { }
194+
195+
@attached(extension, conformances: ImpliesHashable)
196+
macro ImpliesHashable() = #externalMacro(module: "MacroDefinition", type: "ImpliesHashableMacro")
197+
198+
func requiresHashable<T: Hashable>(_: T) { }
199+
func testMakeMeHashable(mmh: MakeMeHashable, dict: [MakeMeHashable: Int]) {
200+
requiresHashable(mmh)
201+
}
202+
203+
@ImpliesHashable
204+
public struct MakeMeHashable { }

0 commit comments

Comments
 (0)