Skip to content

Commit 2481503

Browse files
committed
Sema: Clean up associated type inference using getSelfBoundsFromWhereClause()
Fixes https://bugs.swift.org/browse/SR-14639 / rdar://problem/78276768.
1 parent 5925cb2 commit 2481503

File tree

2 files changed

+50
-15
lines changed

2 files changed

+50
-15
lines changed

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 20 additions & 15 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"
@@ -216,10 +217,12 @@ AssociatedTypeInference::inferTypeWitnessesViaValueWitnesses(
216217
// Retrieve the generic signature of the extension.
217218
const auto extensionSig = extension->getGenericSignature();
218219

220+
auto *proto = dyn_cast<ProtocolDecl>(extendedNominal);
221+
219222
// If the extension is bound to the nominal the conformance is
220223
// declared on, it is viable for inference when its conditional
221224
// requirements are satisfied by those of the conformance context.
222-
if (!isa<ProtocolDecl>(extendedNominal)) {
225+
if (!proto) {
223226
// Extensions of non-generic nominals are always viable for inference.
224227
if (!extensionSig)
225228
return true;
@@ -235,21 +238,23 @@ 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

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)