Skip to content

Commit 5008b5c

Browse files
authored
Merge pull request #71194 from slavapestov/once-more-for-good-luck
Sema: Two more associated type inference fixes
2 parents 066f253 + 35730d6 commit 5008b5c

File tree

4 files changed

+55
-45
lines changed

4 files changed

+55
-45
lines changed

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2167,6 +2167,18 @@ AssociatedTypeInference::computeAbstractTypeWitness(
21672167
return llvm::None;
21682168
}
21692169

2170+
static SmallVector<ProtocolConformance *, 2>
2171+
getPeerConformances(NormalProtocolConformance *conformance) {
2172+
auto *dc = conformance->getDeclContext();
2173+
IterableDeclContext *idc = dyn_cast<ExtensionDecl>(dc);
2174+
if (!idc)
2175+
idc = cast<NominalTypeDecl>(dc);
2176+
2177+
// NonStructural skips the Sendable synthesis which can cycle, and Sendable
2178+
// doesn't have associated types anyway.
2179+
return idc->getLocalConformances(ConformanceLookupKind::NonStructural);
2180+
}
2181+
21702182
void AssociatedTypeInference::collectAbstractTypeWitnesses(
21712183
TypeWitnessSystem &system,
21722184
ArrayRef<AssociatedTypeDecl *> unresolvedAssocTypes) const {
@@ -2212,10 +2224,13 @@ void AssociatedTypeInference::collectAbstractTypeWitnesses(
22122224
// are less likely to cause request cycles.
22132225
considerProtocolRequirements(conformance->getProtocol());
22142226

2215-
// Also look through all other protocols the conforming type conforms to.
2216-
for (auto *const conformedProto :
2217-
dc->getSelfNominalTypeDecl()->getAllProtocols(/*sorted=*/true)) {
2218-
considerProtocolRequirements(conformedProto);
2227+
// Look through all conformances in the same DeclContext as ours.
2228+
for (auto *otherConformance : getPeerConformances(conformance)) {
2229+
// Don't visit this one twice.
2230+
if (otherConformance->getProtocol() == conformance->getProtocol())
2231+
continue;
2232+
2233+
considerProtocolRequirements(otherConformance->getProtocol());
22192234
}
22202235

22212236
// If the same-type constraints weren't enough to resolve an associated type,
@@ -4070,18 +4085,8 @@ ResolveTypeWitnessesRequest::evaluate(Evaluator &evaluator,
40704085
static NormalProtocolConformance *
40714086
getBetterConformanceForResolvingTypeWitnesses(NormalProtocolConformance *conformance,
40724087
AssociatedTypeDecl *requirement) {
4073-
auto *dc = conformance->getDeclContext();
4074-
assert(dc->getParentSourceFile() && "What are you doing?");
40754088
auto *proto = conformance->getProtocol();
4076-
4077-
IterableDeclContext *idc;
4078-
if (auto *extensionDecl = dyn_cast<ExtensionDecl>(dc))
4079-
idc = extensionDecl;
4080-
else
4081-
idc = cast<NominalTypeDecl>(dc);
4082-
4083-
auto otherConformances = idc->getLocalConformances(ConformanceLookupKind::NonStructural);
4084-
for (auto *otherConformance : otherConformances) {
4089+
for (auto *otherConformance : getPeerConformances(conformance)) {
40854090
auto *otherNormal = dyn_cast<NormalProtocolConformance>(
40864091
otherConformance->getRootConformance());
40874092
if (otherNormal == nullptr)
@@ -4116,6 +4121,14 @@ TypeWitnessRequest::evaluate(Evaluator &eval,
41164121
auto *better = getBetterConformanceForResolvingTypeWitnesses(
41174122
conformance, requirement);
41184123

4124+
if (better == conformance) {
4125+
LLVM_DEBUG(llvm::dbgs() << "Conformance to " << conformance->getProtocol()
4126+
<< " is best\n";);
4127+
} else {
4128+
LLVM_DEBUG(llvm::dbgs() << "Conformance to " << better->getProtocol()
4129+
<< " is better than " << conformance->getProtocol()
4130+
<< "\n";);
4131+
}
41194132
if (better != conformance &&
41204133
!ctx.evaluator.hasActiveRequest(ResolveTypeWitnessesRequest{better})) {
41214134
// Let's try to resolve type witnesses in the better conformance.

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4018,22 +4018,6 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
40184018
assert(!isa<AssociatedTypeDecl>(requirement) && "Use resolveTypeWitnessVia*");
40194019
auto *nominal = DC->getSelfNominalTypeDecl();
40204020

4021-
// Resolve all associated types before trying to resolve this witness.
4022-
evaluateOrDefault(getASTContext().evaluator,
4023-
ResolveTypeWitnessesRequest{Conformance},
4024-
evaluator::SideEffect());
4025-
4026-
// If any of the type witnesses was erroneous, don't bother to check
4027-
// this value witness: it will fail.
4028-
auto referenced = evaluateOrDefault(getASTContext().evaluator,
4029-
ReferencedAssociatedTypesRequest{requirement},
4030-
TinyPtrVector<AssociatedTypeDecl *>());
4031-
for (auto assocType : referenced) {
4032-
if (Conformance->getTypeWitness(assocType)->hasError()) {
4033-
return ResolveWitnessResult::ExplicitFailed;
4034-
}
4035-
}
4036-
40374021
// Determine whether we can derive a witness for this requirement.
40384022
bool canDerive = false;
40394023

@@ -4537,18 +4521,13 @@ void ConformanceChecker::resolveSingleWitness(ValueDecl *requirement) {
45374521
if (!requirement->isProtocolRequirement())
45384522
return;
45394523

4540-
// Resolve all associated types before trying to resolve this witness.
4541-
evaluateOrDefault(getASTContext().evaluator,
4542-
ResolveTypeWitnessesRequest{Conformance},
4543-
evaluator::SideEffect());
4544-
4545-
// If any of the type witnesses was erroneous, don't bother to check
4546-
// this value witness: it will fail.
4547-
auto assocTypes = evaluateOrDefault(getASTContext().evaluator,
4524+
// Resolve the type witnesses for all associated types referenced by
4525+
// the requirement. If any are erroneous, don't bother resolving the
4526+
// witness.
4527+
auto referenced = evaluateOrDefault(getASTContext().evaluator,
45484528
ReferencedAssociatedTypesRequest{requirement},
45494529
TinyPtrVector<AssociatedTypeDecl *>());
4550-
4551-
for (auto assocType : assocTypes) {
4530+
for (auto assocType : referenced) {
45524531
if (Conformance->getTypeWitness(assocType)->hasError()) {
45534532
Conformance->setInvalid();
45544533
return;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %target-typecheck-verify-swift -disable-experimental-associated-type-inference
2+
// RUN: %target-typecheck-verify-swift -enable-experimental-associated-type-inference
3+
4+
// The 'for' loop has to come first, to force Sequence.makeIterator().
5+
for x in S() { _ = x }
6+
7+
struct S: RandomAccessCollection {
8+
public var startIndex: Int { 0 }
9+
public var endIndex: Int { 0 }
10+
public subscript(position: Int) -> Int { 0 }
11+
}
12+
Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
// RUN: %target-swift-frontend -emit-sil -module-name main -primary-file %s %S/Inputs/protocol-conformance-issue-53408-other.swift -verify
2-
// RUN: %target-swift-frontend -emit-sil -module-name main %s -primary-file %S/Inputs/protocol-conformance-issue-53408-other.swift
1+
// RUN: not %target-swift-frontend -emit-sil -module-name main -primary-file %s %S/Inputs/protocol-conformance-issue-53408-other.swift -disable-experimental-associated-type-inference
2+
// RUN: %target-swift-frontend -emit-sil -module-name main %s -primary-file %S/Inputs/protocol-conformance-issue-53408-other.swift -disable-experimental-associated-type-inference
3+
// RUN: not %target-swift-frontend -emit-sil -module-name main %s %S/Inputs/protocol-conformance-issue-53408-other.swift -disable-experimental-associated-type-inference
4+
// RUN: %target-swift-frontend -emit-sil -module-name main %S/Inputs/protocol-conformance-issue-53408-other.swift %s -disable-experimental-associated-type-inference
5+
6+
// RUN: %target-swift-frontend -emit-sil -module-name main -primary-file %s %S/Inputs/protocol-conformance-issue-53408-other.swift -enable-experimental-associated-type-inference
7+
// RUN: %target-swift-frontend -emit-sil -module-name main %s -primary-file %S/Inputs/protocol-conformance-issue-53408-other.swift -enable-experimental-associated-type-inference
8+
// RUN: %target-swift-frontend -emit-sil -module-name main %s %S/Inputs/protocol-conformance-issue-53408-other.swift -enable-experimental-associated-type-inference
9+
// RUN: %target-swift-frontend -emit-sil -module-name main %S/Inputs/protocol-conformance-issue-53408-other.swift %s -enable-experimental-associated-type-inference
310

411
// https://github.com/apple/swift/issues/53408
512

613
func reproducer() -> Float { return Struct().func1(1.0) }
7-
// expected-error@-1 {{cannot convert value of type 'Double' to expected argument type 'Struct.Input'}}
8-
// expected-error@-2 {{type 'Struct' does not conform to protocol 'Proto1'}}
14+

0 commit comments

Comments
 (0)