Skip to content

Commit d1bfe72

Browse files
committed
[Macros] Register the extension for a conformance macro fully.
When we form an extension for a conformance macro, make sure to register that extension as being part of the nominal type to which the conformance macro is attached. This ensures that the conformance is seen everywhere. Crucially, this ensures that that protocol conformance table handles conformances that are implied by the conformance macro. For example, a conformance macro that introduces a `Hashable` conformance will also imply an `Equatable` conformance; that wasn't happening before this change. This is needed to make the `OptionSet` macro work fully.
1 parent ee3bcf2 commit d1bfe72

File tree

3 files changed

+29
-25
lines changed

3 files changed

+29
-25
lines changed

lib/Sema/TypeCheckMacros.cpp

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,34 +1276,14 @@ swift::expandConformances(CustomAttr *attr, MacroDecl *macro,
12761276
if (!extension)
12771277
continue;
12781278

1279-
auto &extensionCtx = extension->getASTContext();
1280-
12811279
// Bind the extension to the original nominal type.
12821280
extension->setExtendedNominal(nominal);
1281+
nominal->addExtension(extension);
12831282

1284-
// Resolve the protocol type.
1285-
assert(extension->getInherited().size() == 1);
1286-
auto inheritedType = evaluateOrDefault(
1287-
extensionCtx.evaluator,
1288-
InheritedTypeRequest{extension, 0, TypeResolutionStage::Interface},
1289-
Type());
1290-
1291-
if (!inheritedType || inheritedType->hasError())
1292-
continue;
1293-
1294-
auto protocolType = inheritedType->getAs<ProtocolType>();
1295-
if (!protocolType)
1296-
continue;
1297-
1298-
// Create a synthesized conformance and register it with the nominal type.
1299-
auto conformance = extensionCtx.getConformance(
1300-
nominal->getDeclaredInterfaceType(), protocolType->getDecl(),
1301-
nominal->getLoc(), extension, ProtocolConformanceState::Incomplete,
1302-
/*isUnchecked=*/false);
1303-
conformance->setSourceKindAndImplyingConformance(
1304-
ConformanceEntryKind::Synthesized, nullptr);
1305-
1306-
nominal->registerProtocolConformance(conformance, /*synthesized=*/true);
1283+
// Make it accessible to getTopLevelDecls()
1284+
if (auto file = dyn_cast<FileUnit>(
1285+
decl->getDeclContext()->getModuleScopeContext()))
1286+
file->getOrCreateSynthesizedFile().addTopLevelDecl(extension);
13071287
}
13081288

13091289
return macroSourceFile->getBufferID();

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,17 @@ public struct EquatableMacro: ConformanceMacro {
10371037
}
10381038
}
10391039

1040+
public struct HashableMacro: ConformanceMacro {
1041+
public static func expansion(
1042+
of node: AttributeSyntax,
1043+
providingConformancesOf decl: some DeclGroupSyntax,
1044+
in context: some MacroExpansionContext
1045+
) throws -> [(TypeSyntax, GenericWhereClauseSyntax?)] {
1046+
let protocolName: TypeSyntax = "Hashable"
1047+
return [(protocolName, nil)]
1048+
}
1049+
}
1050+
10401051
public struct DelegatedConformanceMacro: ConformanceMacro, MemberMacro {
10411052
public static func expansion(
10421053
of node: AttributeSyntax,

test/Macros/macro_expand_conformances.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,32 @@
1313
@attached(conformance)
1414
macro Equatable() = #externalMacro(module: "MacroDefinition", type: "EquatableMacro")
1515

16+
@attached(conformance)
17+
macro Hashable() = #externalMacro(module: "MacroDefinition", type: "HashableMacro")
18+
1619
func requireEquatable(_ value: some Equatable) {
1720
print(value == value)
1821
}
1922

23+
func requireHashable(_ value: some Hashable) {
24+
print(value.hashValue)
25+
}
26+
2027
@Equatable
2128
struct S {}
2229

30+
@Hashable
31+
struct S2 {}
32+
2333
// CHECK-DUMP: @__swiftmacro_25macro_expand_conformances1SV9EquatablefMc_.swift
2434
// CHECK-DUMP: extension S : Equatable {}
2535

2636
// CHECK: true
2737
requireEquatable(S())
2838

39+
requireEquatable(S2())
40+
requireHashable(S2())
41+
2942
@attached(conformance)
3043
@attached(member)
3144
macro DelegatedConformance() = #externalMacro(module: "MacroDefinition", type: "DelegatedConformanceMacro")

0 commit comments

Comments
 (0)