Skip to content

Always supersede conformances implied by pre-macro-expansion conformances #68028

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions include/swift/AST/DeclContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,15 @@ enum class ConformanceEntryKind : unsigned {
/// Explicitly specified.
Explicit,

/// The conformance is generated by a macro that has not been
/// expanded yet.
PreMacroExpansion,

/// Implicitly synthesized.
Synthesized,

/// Implied by an explicitly-specified conformance.
Implied,

/// The conformance is generated by a macro that has not been
/// expanded yet.
PreMacroExpansion,
};

/// Describes the kind of conformance lookup desired.
Expand Down
23 changes: 17 additions & 6 deletions lib/AST/ConformanceLookupTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ class ConformanceLookupTable : public ASTAllocated<ConformanceLookupTable> {
///
/// The only difference between the ranking kind and the kind is
/// that implied conformances originating from a synthesized
/// conformance are considered to be synthesized (which has a
/// or pre-macro-expansion conformance are considered to be synthesized (which has a
/// lower ranking).
ConformanceEntryKind getRankingKind() const {
switch (auto kind = getKind()) {
Expand All @@ -157,11 +157,22 @@ class ConformanceLookupTable : public ASTAllocated<ConformanceLookupTable> {
case ConformanceEntryKind::PreMacroExpansion:
return kind;

case ConformanceEntryKind::Implied:
return (getImpliedSource()->getDeclaredConformance()->getKind()
== ConformanceEntryKind::Synthesized)
? ConformanceEntryKind::Synthesized
: ConformanceEntryKind::Implied;
case ConformanceEntryKind::Implied: {
auto impliedSourceKind =
getImpliedSource()->getDeclaredConformance()->getKind();
switch (impliedSourceKind) {
case ConformanceEntryKind::Synthesized:
case ConformanceEntryKind::PreMacroExpansion:
return impliedSourceKind;

case ConformanceEntryKind::Explicit:
case ConformanceEntryKind::Inherited:
return ConformanceEntryKind::Implied;

case ConformanceEntryKind::Implied:
return getImpliedSource()->getRankingKind();
}
}
}

llvm_unreachable("Unhandled ConformanceEntryKind in switch.");
Expand Down
13 changes: 13 additions & 0 deletions test/Macros/Inputs/syntax_macro_definitions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1360,6 +1360,19 @@ public struct HashableMacro: ExtensionMacro {
}
}

public struct ImpliesHashableMacro: ExtensionMacro {
public static func expansion(
of node: AttributeSyntax,
attachedTo: some DeclGroupSyntax,
providingExtensionsOf type: some TypeSyntaxProtocol,
conformingTo protocols: [TypeSyntax],
in context: some MacroExpansionContext
) throws -> [ExtensionDeclSyntax] {
let ext: DeclSyntax = "extension \(type.trimmed): ImpliesHashable {}"
return [ext.cast(ExtensionDeclSyntax.self)]
}
}

public struct DelegatedConformanceMacro: ExtensionMacro, MemberMacro {
public static func expansion(
of node: AttributeSyntax,
Expand Down
18 changes: 18 additions & 0 deletions test/Macros/macro_expand_extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
// 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
// RUN: c-index-test -read-diagnostics %t/macro_expand.dia 2>&1 | %FileCheck -check-prefix CHECK-DIAGS %s

// Ensure that we can serialize this file as a module.
// 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

// 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
// RUN: %target-codesign %t/main
// RUN: %target-run %t/main | %FileCheck %s
Expand Down Expand Up @@ -198,3 +201,18 @@ func requiresEquatable<T: Equatable>(_: T) { }
func testHasPropertyWrappers(hpw: HasPropertyWrappers) {
requiresEquatable(hpw)
}

// Check that conformances implied by a macro-defined conformance are serialized
// without issue.
public protocol ImpliesHashable: Hashable { }

@attached(extension, conformances: ImpliesHashable)
macro ImpliesHashable() = #externalMacro(module: "MacroDefinition", type: "ImpliesHashableMacro")

func requiresHashable<T: Hashable>(_: T) { }
func testMakeMeHashable(mmh: MakeMeHashable, dict: [MakeMeHashable: Int]) {
requiresHashable(mmh)
}

@ImpliesHashable
public struct MakeMeHashable { }