Skip to content

Commit ffd651c

Browse files
committed
Sema: Try not to let protocol type aliases leak into inferred type witnesses
They don't always round-trip through a module interface, because of request cycles in type resolution. Fixes rdar://problem/122957148.
1 parent 95413de commit ffd651c

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1851,6 +1851,19 @@ static Type mapErrorTypeToOriginal(Type type) {
18511851
return type;
18521852
}
18531853

1854+
/// Desugar protocol type aliases, since they can cause request cycles in
1855+
/// type resolution if printed in a module interface and parsed back in.
1856+
static Type getWithoutProtocolTypeAliases(Type type) {
1857+
return type.transformRec([](TypeBase *t) -> llvm::Optional<Type> {
1858+
if (auto *aliasTy = dyn_cast<TypeAliasType>(t)) {
1859+
if (aliasTy->getDecl()->getDeclContext()->getExtendedProtocolDecl())
1860+
return getWithoutProtocolTypeAliases(aliasTy->getSinglyDesugaredType());
1861+
}
1862+
1863+
return llvm::None;
1864+
});
1865+
}
1866+
18541867
/// Produce the type when matching a witness.
18551868
///
18561869
/// If the witness is a member of the type itself or a superclass, we
@@ -1884,6 +1897,9 @@ static Type getWitnessTypeForMatching(NormalProtocolConformance *conformance,
18841897
conformance->getDeclContext()->mapTypeIntoContext(conformance->getType());
18851898
TypeSubstitutionMap substitutions = model->getMemberSubstitutions(witness);
18861899
Type type = witness->getInterfaceType()->getReferenceStorageReferent();
1900+
1901+
type = getWithoutProtocolTypeAliases(type);
1902+
18871903
LLVM_DEBUG(llvm::dbgs() << "Witness interface type is " << type << "\n";);
18881904

18891905
if (substitutions.empty())
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -module-name protocol_extension_type_witness -enable-experimental-associated-type-inference
2+
// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -module-name protocol_extension_type_witness
3+
// RUN: %FileCheck %s < %t.swiftinterface
4+
5+
// RUN: %target-swift-emit-module-interface(%t.swiftinterface) %s -module-name protocol_extension_type_witness -disable-experimental-associated-type-inference
6+
// RUN: %target-swift-typecheck-module-from-interface(%t.swiftinterface) -module-name protocol_extension_type_witness
7+
// RUN: %FileCheck %s < %t.swiftinterface
8+
9+
public protocol P {
10+
associatedtype A
11+
associatedtype B
12+
associatedtype C
13+
associatedtype D
14+
15+
func b(_: B)
16+
func c(_: C)
17+
func d(_: D)
18+
}
19+
20+
extension P {
21+
public typealias _Default_A = B
22+
public typealias Alias = D
23+
24+
public func c(_: Alias) {}
25+
}
26+
27+
public struct S<B>: P {
28+
public func b(_: B) {}
29+
public func d(_: String) {}
30+
}
31+
32+
// CHECK-LABEL: public struct S<B> : protocol_extension_type_witness.P {
33+
// CHECK-NEXT: public func b(_: B)
34+
// CHECK-NEXT: public func d(_: Swift.String)
35+
// CHECK-NEXT: public typealias A = B
36+
// CHECK-NEXT: public typealias C = Swift.String
37+
// CHECK-NEXT: public typealias D = Swift.String
38+
// CHECK-NEXT: }

0 commit comments

Comments
 (0)