Skip to content

Commit 3637e69

Browse files
authored
Merge pull request #79195 from DougGregor/expand-conformances-member-ordering
[Macros] Eliminate ordering dependency that suppressed conformingTo protocols
2 parents d33371a + d276006 commit 3637e69

File tree

3 files changed

+102
-2
lines changed

3 files changed

+102
-2
lines changed

lib/Sema/TypeCheckMacros.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,8 +1788,20 @@ static TinyPtrVector<ProtocolDecl *> getIntroducedConformances(
17881788
bool hasExistingConformance = llvm::any_of(
17891789
existingConformances,
17901790
[&](ProtocolConformance *conformance) {
1791-
return conformance->getSourceKind() !=
1792-
ConformanceEntryKind::PreMacroExpansion;
1791+
// The conformance is coming from a macro expansion, so ignore it.
1792+
if (conformance->getSourceKind() ==
1793+
ConformanceEntryKind::PreMacroExpansion)
1794+
return false;
1795+
1796+
// Check whether the conformance comes from an extension defined by
1797+
// a macro.
1798+
if (auto conformingExt =
1799+
dyn_cast<ExtensionDecl>(conformance->getDeclContext())) {
1800+
if (conformingExt->isInMacroExpansionInContext())
1801+
return false;
1802+
}
1803+
1804+
return true;
17931805
});
17941806

17951807
if (!hasExistingConformance) {

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1808,6 +1808,46 @@ public struct AddAllConformancesMacro: ExtensionMacro {
18081808
}
18091809
}
18101810

1811+
public struct ListConformancesMacro { }
1812+
1813+
extension ListConformancesMacro: ExtensionMacro {
1814+
public static func expansion(
1815+
of node: AttributeSyntax,
1816+
attachedTo decl: some DeclGroupSyntax,
1817+
providingExtensionsOf type: some TypeSyntaxProtocol,
1818+
conformingTo protocols: [TypeSyntax],
1819+
in context: some MacroExpansionContext
1820+
) throws -> [ExtensionDeclSyntax] {
1821+
protocols.map { proto in
1822+
let decl: DeclSyntax =
1823+
"""
1824+
extension \(type): \(proto) {}
1825+
"""
1826+
return decl.cast(ExtensionDeclSyntax.self)
1827+
}
1828+
}
1829+
}
1830+
1831+
extension ListConformancesMacro: MemberMacro {
1832+
public static func expansion(
1833+
of node: AttributeSyntax,
1834+
providingMembersOf declaration: some DeclGroupSyntax,
1835+
conformingTo protocols: [TypeSyntax],
1836+
in context: some MacroExpansionContext
1837+
) throws -> [DeclSyntax] {
1838+
let typeName = declaration.asProtocol(NamedDeclSyntax.self)!.name.text
1839+
1840+
let protocolNames: [ExprSyntax] = protocols.map { "\(literal: $0.trimmedDescription)" }
1841+
let protocolsArray: ExprSyntax =
1842+
"[ \(raw: protocolNames.map { $0.description }.joined(separator: ", ")) ]"
1843+
let unknownDecl: DeclSyntax =
1844+
"""
1845+
@_nonoverride static func conformances() -> [String: [String]] { [ \(literal: typeName): \(protocolsArray) ] }
1846+
"""
1847+
return [unknownDecl]
1848+
}
1849+
}
1850+
18111851
public struct AlwaysAddCodable: ExtensionMacro {
18121852
public static func expansion(
18131853
of node: AttributeSyntax,
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// REQUIRES: swift_swift_parser, executable_test
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath
5+
6+
// Check for errors first
7+
// RUN: %target-swift-frontend -swift-version 5 -typecheck -load-plugin-library %t/%target-library-name(MacroDefinition) %s -I %t -disable-availability-checking
8+
9+
// RUN: %target-swift-frontend -swift-version 5 -typecheck -load-plugin-library %t/%target-library-name(MacroDefinition) %s -I %t -disable-availability-checking -dump-macro-expansions > %t/expansions-dump.txt 2>&1
10+
// RUN: %FileCheck -check-prefix=CHECK-DUMP %s < %t/expansions-dump.txt
11+
12+
13+
protocol P1 {}
14+
protocol P2 {}
15+
16+
@attached(extension, conformances: P1, P2)
17+
@attached(member, conformances: P1, P2, names: named(conformances))
18+
macro ListConformances() = #externalMacro(module: "MacroDefinition", type: "ListConformancesMacro")
19+
20+
21+
// CHECK-DUMP: [ "Root": [ "P1", "P2" ] ]
22+
// CHECK-DUMP: extension Root: P1
23+
// CHECK-DUMP: extension Root: P2
24+
@ListConformances
25+
class Root {
26+
// CHECK-DUMP: extension OtherRoot: P1
27+
// CHECK-DUMP: extension OtherRoot: P2
28+
var other: OtherRoot?
29+
}
30+
31+
// CHECK-DUMP: [ "P1Root": [ "P2" ] ]
32+
// CHECK-DUMP-NOT: extension P1Root: P1
33+
// CHECK-DUMP: extension P1Root: P2
34+
@ListConformances
35+
class P1Root: P1 { }
36+
37+
// CHECK-DUMP: [ "OtherRoot": [ "P1", "P2" ] ]
38+
@ListConformances
39+
class OtherRoot {
40+
// CHECK-DUMP-NOT: extension OtherP1Root: P1
41+
// CHECK-DUMP: extension OtherP1Root: P2
42+
var other: OtherP1Root?
43+
}
44+
45+
// CHECK-DUMP: [ "OtherP1Root": [ "P2" ] ]
46+
@ListConformances
47+
class OtherP1Root: P1 { }
48+

0 commit comments

Comments
 (0)