Skip to content

Commit e40c8f6

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. (cherry picked from commit 24aa030)
1 parent 4973417 commit e40c8f6

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
@@ -530,8 +530,9 @@ bool NormalProtocolConformance::hasTypeWitness(AssociatedTypeDecl *assocType,
530530
if (Loader)
531531
resolveLazyInfo();
532532

533-
if (TypeWitnesses.find(assocType) != TypeWitnesses.end()) {
534-
return true;
533+
auto found = TypeWitnesses.find(assocType);
534+
if (found != TypeWitnesses.end()) {
535+
return !found->getSecond().first.isNull();
535536
}
536537
if (resolver) {
537538
PrettyStackTraceRequirement trace("resolving", this, assocType);
@@ -574,6 +575,9 @@ NormalProtocolConformance::getTypeWitnessAndDecl(AssociatedTypeDecl *assocType,
574575
// Otherwise, resolve the type witness.
575576
PrettyStackTraceRequirement trace("resolving", this, assocType);
576577
assert(resolver && "Unable to resolve type witness");
578+
579+
// Block recursive resolution of this type witness.
580+
TypeWitnesses[assocType] = { Type(), nullptr };
577581
resolver->resolveTypeWitness(this, assocType);
578582

579583
known = TypeWitnesses.find(assocType);
@@ -586,7 +590,9 @@ void NormalProtocolConformance::setTypeWitness(AssociatedTypeDecl *assocType,
586590
TypeDecl *typeDecl) const {
587591
assert(getProtocol() == cast<ProtocolDecl>(assocType->getDeclContext()) &&
588592
"associated type in wrong protocol");
589-
assert(TypeWitnesses.count(assocType) == 0 && "Type witness already known");
593+
assert((TypeWitnesses.count(assocType) == 0 ||
594+
TypeWitnesses[assocType].first.isNull()) &&
595+
"Type witness already known");
590596
assert((!isComplete() || isInvalid()) && "Conformance already complete?");
591597
assert(!type->hasArchetype() && "type witnesses must be interface types");
592598
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
@@ -2656,8 +2656,12 @@ CheckTypeWitnessResult swift::checkTypeWitness(TypeChecker &tc, DeclContext *dc,
26562656
auto *depTy = DependentMemberType::get(proto->getSelfInterfaceType(),
26572657
assocType);
26582658

2659+
if (type->hasError())
2660+
return ErrorType::get(tc.Context);
2661+
26592662
Type contextType = type->hasTypeParameter() ? dc->mapTypeIntoContext(type)
26602663
: type;
2664+
26612665
if (auto superclass = genericSig->getSuperclassBound(depTy)) {
26622666
if (!superclass->isExactSuperclassOf(contextType))
26632667
return superclass;
@@ -2781,7 +2785,8 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
27812785
[nonViable](NormalProtocolConformance *conformance) {
27822786
auto &diags = conformance->getDeclContext()->getASTContext().Diags;
27832787
for (auto candidate : nonViable) {
2784-
if (candidate.first->getDeclaredInterfaceType()->hasError())
2788+
if (candidate.first->getDeclaredInterfaceType()->hasError() ||
2789+
candidate.second.isError())
27852790
continue;
27862791

27872792
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)