Skip to content

Commit 81d8c2e

Browse files
authored
Merge pull request #37637 from slavapestov/associated-type-inference-proto-ext-fix
Fix associated type inference crash with constrained protocol extensions
2 parents 39af9ba + c1201a5 commit 81d8c2e

File tree

2 files changed

+63
-27
lines changed

2 files changed

+63
-27
lines changed

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include "swift/AST/Decl.h"
2121
#include "swift/AST/GenericSignature.h"
22+
#include "swift/AST/NameLookupRequests.h"
2223
#include "swift/AST/ProtocolConformance.h"
2324
#include "swift/AST/SubstitutionMap.h"
2425
#include "swift/AST/TypeMatcher.h"
@@ -206,20 +207,22 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses(
206207
if (extendedNominal == nullptr)
207208
return true;
208209

209-
// FIXME: The extension may not have a generic signature set up yet as
210-
// resolving signatures may trigger associated type inference. This cycle
211-
// is now detectable and we should look into untangling it
212-
// - see rdar://55263708
213-
if (!extension->hasComputedGenericSignature())
214-
return true;
215-
216-
// Retrieve the generic signature of the extension.
217-
const auto extensionSig = extension->getGenericSignature();
210+
auto *proto = dyn_cast<ProtocolDecl>(extendedNominal);
218211

219212
// If the extension is bound to the nominal the conformance is
220213
// declared on, it is viable for inference when its conditional
221214
// requirements are satisfied by those of the conformance context.
222-
if (!isa<ProtocolDecl>(extendedNominal)) {
215+
if (!proto) {
216+
// FIXME: The extension may not have a generic signature set up yet as
217+
// resolving signatures may trigger associated type inference. This cycle
218+
// is now detectable and we should look into untangling it
219+
// - see rdar://55263708
220+
if (!extension->hasComputedGenericSignature())
221+
return true;
222+
223+
// Retrieve the generic signature of the extension.
224+
const auto extensionSig = extension->getGenericSignature();
225+
223226
// Extensions of non-generic nominals are always viable for inference.
224227
if (!extensionSig)
225228
return true;
@@ -235,30 +238,29 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses(
235238
// in the first place. Only check conformances on the `Self` type,
236239
// because those have to be explicitly declared on the type somewhere
237240
// so won't be affected by whatever answer inference comes up with.
238-
auto selfTy = extension->getSelfInterfaceType();
239-
for (const Requirement &reqt : extensionSig->getRequirements()) {
240-
switch (reqt.getKind()) {
241-
case RequirementKind::Conformance:
242-
case RequirementKind::Superclass:
243-
// FIXME: This is the wrong check
244-
if (selfTy->isEqual(reqt.getFirstType()) &&
245-
!TypeChecker::isSubtypeOf(conformance->getType(),
246-
reqt.getSecondType(), dc))
247-
return false;
248-
break;
241+
auto *module = dc->getParentModule();
242+
auto checkConformance = [&](ProtocolDecl *proto) {
243+
auto otherConf = module->lookupConformance(conformance->getType(),
244+
proto);
245+
return (otherConf && otherConf.getConditionalRequirements().empty());
246+
};
249247

250-
case RequirementKind::Layout:
251-
case RequirementKind::SameType:
252-
break;
248+
// First check the extended protocol itself.
249+
if (!checkConformance(proto))
250+
return false;
251+
252+
// Now check any additional bounds on 'Self' from the where clause.
253+
auto bounds = getSelfBoundsFromWhereClause(extension);
254+
for (auto *decl : bounds.decls) {
255+
if (auto *proto = dyn_cast<ProtocolDecl>(decl)) {
256+
if (!checkConformance(proto))
257+
return false;
253258
}
254259
}
255260

256261
return true;
257262
};
258263

259-
auto typeInContext =
260-
conformance->getDeclContext()->mapTypeIntoContext(conformance->getType());
261-
262264
for (auto witness :
263265
checker.lookupValueWitnesses(req, /*ignoringNames=*/nullptr)) {
264266
LLVM_DEBUG(llvm::dbgs() << "Inferring associated types from decl:\n";
@@ -314,6 +316,10 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses(
314316
if (!associatedTypesAreSameEquivalenceClass(dmt->getAssocType(),
315317
result.first))
316318
return false;
319+
320+
auto typeInContext =
321+
conformance->getDeclContext()->mapTypeIntoContext(conformance->getType());
322+
317323
if (!dmt->getBase()->isEqual(typeInContext))
318324
return false;
319325

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
struct Pair<A, B> {
4+
var a: A
5+
var b: B
6+
}
7+
8+
extension Pair: Codable where A: Codable, B: Codable {}
9+
10+
extension Pair: Collection where A == B {
11+
// expected-error@-1 {{conditional conformance of type 'Pair<A, B>' to protocol 'Collection' does not imply conformance to inherited protocol 'Sequence'}}
12+
// expected-note@-2 {{did you mean to explicitly state the conformance like 'extension Pair: Sequence where ...'?}}
13+
typealias Element = A
14+
15+
var startIndex: Int { return 0 }
16+
var endIndex: Int { return 2 }
17+
18+
subscript(index: Int) -> Element {
19+
switch index {
20+
case 0: return self.a
21+
case 1: return self.b
22+
default: fatalError("Index out of bounds.")
23+
}
24+
}
25+
26+
func index(after i: Int) -> Int {
27+
precondition(i < endIndex, "Can't advance beyond endIndex")
28+
return i + 1
29+
}
30+
}

0 commit comments

Comments
 (0)