Skip to content

Commit 24aa030

Browse files
committed
[Associated type inference] Break recursive inference and fail predictably.
There was a path through associated type inference where we would end up recording a type witness that contained an error, but for which we had not reported that error, which would lead to downstream crashes. Make sure that we reject such inferences. And because it triggers once we fix this issue... make sure break recursion when trying to resolve type witnesses lazily. Fixes the crash in SR-6609 / rdar://problem/36038033, but we're still failing to infer in those cases.
1 parent d18ecda commit 24aa030

8 files changed

+30
-14
lines changed

lib/AST/ProtocolConformance.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -550,8 +550,9 @@ bool NormalProtocolConformance::hasTypeWitness(AssociatedTypeDecl *assocType,
550550
if (Loader)
551551
resolveLazyInfo();
552552

553-
if (TypeWitnesses.find(assocType) != TypeWitnesses.end()) {
554-
return true;
553+
auto found = TypeWitnesses.find(assocType);
554+
if (found != TypeWitnesses.end()) {
555+
return !found->getSecond().first.isNull();
555556
}
556557
if (resolver) {
557558
PrettyStackTraceRequirement trace("resolving", this, assocType);
@@ -594,6 +595,9 @@ NormalProtocolConformance::getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
594595
// Otherwise, resolve the type witness.
595596
PrettyStackTraceRequirement trace("resolving", this, assocType);
596597
assert(resolver && "Unable to resolve type witness");
598+
599+
// Block recursive resolution of this type witness.
600+
TypeWitnesses[assocType] = { Type(), nullptr };
597601
resolver->resolveTypeWitness(this, assocType);
598602

599603
known = TypeWitnesses.find(assocType);
@@ -606,7 +610,9 @@ void NormalProtocolConformance::setTypeWitness(AssociatedTypeDecl *assocType,
606610
TypeDecl *typeDecl) const {
607611
assert(getProtocol() == cast<ProtocolDecl>(assocType->getDeclContext()) &&
608612
"associated type in wrong protocol");
609-
assert(TypeWitnesses.count(assocType) == 0 && "Type witness already known");
613+
assert((TypeWitnesses.count(assocType) == 0 ||
614+
TypeWitnesses[assocType].first.isNull()) &&
615+
"Type witness already known");
610616
assert((!isComplete() || isInvalid()) && "Conformance already complete?");
611617
assert(!type->hasArchetype() && "type witnesses must be interface types");
612618
TypeWitnesses[assocType] = std::make_pair(type, typeDecl);

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2655,8 +2655,12 @@ CheckTypeWitnessResult swift::checkTypeWitness(TypeChecker &tc, DeclContext *dc,
26552655
auto *depTy = DependentMemberType::get(proto->getSelfInterfaceType(),
26562656
assocType);
26572657

2658+
if (type->hasError())
2659+
return ErrorType::get(tc.Context);
2660+
26582661
Type contextType = type->hasTypeParameter() ? dc->mapTypeIntoContext(type)
26592662
: type;
2663+
26602664
if (auto superclass = genericSig->getSuperclassBound(depTy)) {
26612665
if (!superclass->isExactSuperclassOf(contextType))
26622666
return superclass;
@@ -2780,7 +2784,8 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
27802784
[nonViable](NormalProtocolConformance *conformance) {
27812785
auto &diags = conformance->getDeclContext()->getASTContext().Diags;
27822786
for (auto candidate : nonViable) {
2783-
if (candidate.first->getDeclaredInterfaceType()->hasError())
2787+
if (candidate.first->getDeclaredInterfaceType()->hasError() ||
2788+
candidate.second.isError())
27842789
continue;
27852790

27862791
diags.diagnose(

lib/Sema/TypeCheckProtocol.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ class CheckTypeWitnessResult {
7878
bool isConformanceRequirement() const {
7979
return Requirement->isExistentialType();
8080
}
81-
81+
bool isError() const {
82+
return Requirement->is<ErrorType>();
83+
}
8284
explicit operator bool() const { return !Requirement.isNull(); }
8385
};
8486

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,7 @@ Type AssociatedTypeInference::computeDefaultTypeWitness(
818818

819819
if (auto failed = checkTypeWitness(tc, dc, proto, assocType, defaultType)) {
820820
// Record the failure, if we haven't seen one already.
821-
if (!failedDefaultedAssocType) {
821+
if (!failedDefaultedAssocType && !failed.isError()) {
822822
failedDefaultedAssocType = defaultedAssocType;
823823
failedDefaultedWitness = defaultType;
824824
failedDefaultedResult = failed;
@@ -1680,6 +1680,9 @@ bool AssociatedTypeInference::diagnoseNoSolutions(
16801680
diags.diagnose(assocType, diag::bad_associated_type_deduction,
16811681
assocType->getFullName(), proto->getFullName());
16821682
for (const auto &failed : failedSet) {
1683+
if (failed.Result.isError())
1684+
continue;
1685+
16831686
diags.diagnose(failed.Witness,
16841687
diag::associated_type_deduction_witness_failed,
16851688
failed.Requirement->getFullName(),

test/Constraints/same_types.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %target-typecheck-verify-swift -verify-ignore-unknown
22

33
protocol Fooable {
4-
associatedtype Foo
4+
associatedtype Foo // expected-note{{protocol requires nested type 'Foo'; do you want to add it?}}
55

66
var foo: Foo { get }
77
}
@@ -148,7 +148,7 @@ rdar19137463(1)
148148

149149
struct Brunch<U : Fooable> where U.Foo == X {}
150150

151-
struct BadFooable : Fooable {
151+
struct BadFooable : Fooable { // expected-error{{type 'BadFooable' does not conform to protocol 'Fooable'}}
152152
typealias Foo = DoesNotExist // expected-error{{use of undeclared type 'DoesNotExist'}}
153153
var foo: Foo { while true {} }
154154
}

test/decl/nested/type_in_function.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func hasAClosure() {
2323
}
2424

2525
protocol Racoon {
26-
associatedtype Stripes
26+
associatedtype Stripes // expected-note{{protocol requires nested type 'Stripes'; do you want to add it?}}
2727
}
2828

2929
// Types inside generic functions -- not supported yet
@@ -117,7 +117,7 @@ struct OuterGenericStruct<A> {
117117
}
118118

119119
func middleFunction() {
120-
struct ConformingType : Racoon {
120+
struct ConformingType : Racoon { // expected-error{{type 'ConformingType' does not conform to protocol 'Racoon'}}
121121
// expected-error@-1 {{type 'ConformingType' cannot be nested in generic function 'middleFunction()'}}
122122
typealias Stripes = A
123123
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
// See https://swift.org/LICENSE.txt for license information
66
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
77

8-
// REQUIRES: asserts
9-
// RUN: not --crash %target-swift-frontend %s -emit-ir
8+
9+
// RUN: not %target-swift-frontend %s -emit-ir
1010
protocol P{{}func a{}typealias e}struct A:P{typealias e:Self.a{}typealias e:Self.a{}typealias e:P

validation-test/compiler_crashers/28854-known-typewitnesses-end-didnt-resolve-witness.swift renamed to validation-test/compiler_crashers_fixed/28854-known-typewitnesses-end-didnt-resolve-witness.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
// See https://swift.org/LICENSE.txt for license information
66
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
77

8-
// REQUIRES: asserts
9-
// RUN: not --crash %target-swift-frontend %s -emit-ir
8+
9+
// RUN: not %target-swift-frontend %s -emit-ir
1010
@objc protocol A
1111
{
1212
typealias a

0 commit comments

Comments
 (0)