Skip to content

Commit 9c778f3

Browse files
committed
Sema: Don't let DependentMemberTypes with concrete bases leak out
1 parent e43fac5 commit 9c778f3

File tree

2 files changed

+90
-14
lines changed

2 files changed

+90
-14
lines changed

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2582,6 +2582,15 @@ bool AssociatedTypeInference::checkConstrainedExtension(ExtensionDecl *ext) {
25822582
llvm_unreachable("unhandled result");
25832583
}
25842584

2585+
static bool containsConcreteDependentMemberType(Type ty) {
2586+
return ty.findIf([](Type t) -> bool {
2587+
if (auto *dmt = t->getAs<DependentMemberType>())
2588+
return !dmt->isTypeParameter();
2589+
2590+
return false;
2591+
});
2592+
}
2593+
25852594
AssociatedTypeDecl *AssociatedTypeInference::inferAbstractTypeWitnesses(
25862595
ArrayRef<AssociatedTypeDecl *> unresolvedAssocTypes, unsigned reqDepth) {
25872596
if (unresolvedAssocTypes.empty()) {
@@ -2709,15 +2718,15 @@ AssociatedTypeDecl *AssociatedTypeInference::inferAbstractTypeWitnesses(
27092718
llvm::SmallPtrSet<AssociatedTypeDecl *, 4> circularityCheck;
27102719
circularityCheck.insert(assocType);
27112720

2712-
std::function<Type(Type)> substCurrentTypeWitnesses;
2713-
substCurrentTypeWitnesses = [&](Type ty) -> Type {
2721+
std::function<llvm::Optional<Type>(Type)> substCurrentTypeWitnesses;
2722+
substCurrentTypeWitnesses = [&](Type ty) -> llvm::Optional<Type> {
27142723
auto *const dmt = ty->getAs<DependentMemberType>();
27152724
if (!dmt) {
2716-
return ty;
2725+
return llvm::None;
27172726
}
27182727

27192728
const auto substBase =
2720-
dmt->getBase().transform(substCurrentTypeWitnesses);
2729+
dmt->getBase().transformRec(substCurrentTypeWitnesses);
27212730
if (!substBase) {
27222731
return nullptr;
27232732
}
@@ -2726,9 +2735,16 @@ AssociatedTypeDecl *AssociatedTypeInference::inferAbstractTypeWitnesses(
27262735
// need to look up a tentative type witness. Otherwise, just substitute
27272736
// the base.
27282737
if (substBase->getAnyNominal() != dc->getSelfNominalTypeDecl()) {
2729-
return dmt->substBaseType(substBase,
2730-
LookUpConformanceInModule(dc->getParentModule()),
2731-
substOptions);
2738+
auto substTy = dmt->substBaseType(
2739+
substBase,
2740+
LookUpConformanceInModule(dc->getParentModule()),
2741+
substOptions);
2742+
2743+
// If any unresolved dependent member types remain, give up.
2744+
if (containsConcreteDependentMemberType(substTy))
2745+
return nullptr;
2746+
2747+
return substTy;
27322748
}
27332749

27342750
auto *assocTy = dmt->getAssocType();
@@ -2765,7 +2781,7 @@ AssociatedTypeDecl *AssociatedTypeInference::inferAbstractTypeWitnesses(
27652781
// out so that we don't break any subst() invariants.
27662782
if (tyWitness->hasTypeParameter() ||
27672783
tyWitness->hasDependentMember()) {
2768-
tyWitness = tyWitness.transform(substCurrentTypeWitnesses);
2784+
tyWitness = tyWitness.transformRec(substCurrentTypeWitnesses);
27692785
}
27702786

27712787
if (tyWitness) {
@@ -2798,15 +2814,20 @@ AssociatedTypeDecl *AssociatedTypeInference::inferAbstractTypeWitnesses(
27982814
return tyWitness;
27992815
};
28002816

2801-
type = type.transform(substCurrentTypeWitnesses);
2817+
type = type.transformRec(substCurrentTypeWitnesses);
28022818

28032819
// If substitution failed, give up.
2804-
if (!type || type->hasError())
2820+
if (!type || type->hasError()) {
2821+
LLVM_DEBUG(llvm::dbgs() << "-- Simplification failed\n");
28052822
return assocType;
2823+
}
2824+
2825+
// If any unresolved dependent member types remain, give up.
2826+
assert(!containsConcreteDependentMemberType(type));
28062827

28072828
type = dc->mapTypeIntoContext(type);
28082829

2809-
LLVM_DEBUG(llvm::dbgs() << "Substituted witness type is " << type << "\n";);
2830+
LLVM_DEBUG(llvm::dbgs() << "Simplified witness type is " << type << "\n";);
28102831
}
28112832

28122833
if (const auto failed =
@@ -4229,11 +4250,11 @@ TypeWitnessRequest::evaluate(Evaluator &eval,
42294250
conformance, requirement);
42304251

42314252
if (better == conformance) {
4232-
LLVM_DEBUG(llvm::dbgs() << "Conformance to " << conformance->getProtocol()
4253+
LLVM_DEBUG(llvm::dbgs() << "Conformance to " << conformance->getProtocol()->getName()
42334254
<< " is best\n";);
42344255
} else {
4235-
LLVM_DEBUG(llvm::dbgs() << "Conformance to " << better->getProtocol()
4236-
<< " is better than " << conformance->getProtocol()
4256+
LLVM_DEBUG(llvm::dbgs() << "Conformance to " << better->getProtocol()->getName()
4257+
<< " is better than " << conformance->getProtocol()->getName()
42374258
<< "\n";);
42384259
}
42394260
if (better != conformance &&
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// RUN: %target-swift-frontend -emit-silgen %s
2+
3+
// Reduced from swift-nio.
4+
5+
public protocol AppendableCollection: Collection {
6+
mutating func append(_ newElement: Self.Iterator.Element)
7+
}
8+
9+
public struct CircularBuffer<E>: AppendableCollection {
10+
public mutating func append(_ value: E) {
11+
fatalError()
12+
}
13+
14+
private mutating func doubleCapacity() {
15+
fatalError()
16+
}
17+
18+
public subscript(index: Int) -> E {
19+
get {
20+
fatalError()
21+
}
22+
set {
23+
fatalError()
24+
}
25+
}
26+
27+
public var indices: Range<Int> {
28+
fatalError()
29+
}
30+
31+
public var isEmpty: Bool {
32+
fatalError()
33+
}
34+
35+
public var count: Int {
36+
fatalError()
37+
}
38+
39+
public var startIndex: Int {
40+
fatalError()
41+
}
42+
43+
public var endIndex: Int {
44+
fatalError()
45+
}
46+
47+
public func index(after: Int) -> Int {
48+
fatalError()
49+
}
50+
51+
public func index(before: Int) -> Int {
52+
fatalError()
53+
}
54+
}
55+

0 commit comments

Comments
 (0)