Skip to content

Commit 71fff5b

Browse files
committed
Sema: Look for generic parameters first when inferring an associated type
Previously we did this as a last resort if inference fails. The new behavior is technically source-breaking, but I suspect nobody relied on the old behavior. This can help avoid cycles by eliminating some unnecessary validation work. Fixes <https://bugs.swift.org/browse/SR-11407>, <rdar://problem/54979757>.
1 parent aab54a1 commit 71fff5b

File tree

5 files changed

+55
-29
lines changed

5 files changed

+55
-29
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3518,20 +3518,37 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
35183518
AssociatedTypeDecl *assocType) {
35193519
// Conformances constructed by the ClangImporter should have explicit type
35203520
// witnesses already.
3521-
if (isa<ClangModuleUnit>(Conformance->getDeclContext()->getModuleScopeContext())) {
3521+
if (isa<ClangModuleUnit>(DC->getModuleScopeContext())) {
35223522
llvm::errs() << "Cannot look up associated type for imported conformance:\n";
35233523
Conformance->getType().dump(llvm::errs());
35243524
assocType->dump(llvm::errs());
35253525
abort();
35263526
}
35273527

3528+
// If we fail to find a witness via lookup, check for a generic parameter.
3529+
auto checkForGenericParameter = [&]() {
3530+
// If there is a generic parameter of the named type, use that.
3531+
if (auto genericSig = DC->getGenericSignatureOfContext()) {
3532+
for (auto gp : genericSig->getInnermostGenericParams()) {
3533+
if (gp->getName() == assocType->getName()) {
3534+
if (!checkTypeWitness(DC, Proto, assocType, gp)) {
3535+
recordTypeWitness(assocType, gp, nullptr);
3536+
return ResolveWitnessResult::Success;
3537+
}
3538+
}
3539+
}
3540+
}
3541+
3542+
return ResolveWitnessResult::Missing;
3543+
};
3544+
35283545
// Look for a member type with the same name as the associated type.
35293546
auto candidates = TypeChecker::lookupMemberType(
35303547
DC, Adoptee, assocType->getName(), NameLookupFlags::ProtocolMembers);
35313548

35323549
// If there aren't any candidates, we're done.
35333550
if (!candidates) {
3534-
return ResolveWitnessResult::Missing;
3551+
return checkForGenericParameter();
35353552
}
35363553

35373554
// Determine which of the candidates is viable.
@@ -3565,7 +3582,7 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
35653582
return x.first->getDeclContext()
35663583
->getSelfProtocolDecl() == nullptr;
35673584
}) == nonViable.end())
3568-
return ResolveWitnessResult::Missing;
3585+
return checkForGenericParameter();
35693586

35703587
// If there is a single viable candidate, form a substitution for it.
35713588
if (viable.size() == 1) {

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -918,14 +918,6 @@ AssociatedTypeInference::computeAbstractTypeWitness(
918918
return derivedType;
919919
}
920920

921-
// If there is a generic parameter of the named type, use that.
922-
if (auto genericSig = dc->getGenericSignatureOfContext()) {
923-
for (auto gp : genericSig->getInnermostGenericParams()) {
924-
if (gp->getName() == assocType->getName())
925-
return dc->mapTypeIntoContext(gp);
926-
}
927-
}
928-
929921
return Type();
930922
}
931923

stdlib/public/core/NativeSet.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,9 @@ extension _NativeSet {
282282
}
283283

284284
extension _NativeSet: _SetBuffer {
285+
@usableFromInline
286+
internal typealias Element = Element
287+
285288
@usableFromInline
286289
internal typealias Index = Set<Element>.Index
287290

test/decl/protocol/req/associated_type_inference_valid.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,35 @@ struct R : P {
2222
let x: Y? = nil
2323
func foo(_: Y) {}
2424
}
25+
26+
// SR-8813
27+
protocol BaseProtocol {
28+
associatedtype Value
29+
typealias Closure = () -> Value
30+
31+
init(closure: Closure)
32+
}
33+
34+
struct Base<Value>: BaseProtocol {
35+
private var closure: Closure?
36+
37+
init(closure: Closure) {
38+
withoutActuallyEscaping(closure) { new in
39+
self.closure = new
40+
}
41+
}
42+
}
43+
44+
// SR-11407
45+
protocol _Drivable: AnyObject {
46+
typealias Driver = Self
47+
}
48+
protocol Configurator {
49+
associatedtype Drivable: _Drivable
50+
typealias Driver = Drivable.Driver
51+
func configure(driver: Driver)
52+
}
53+
struct AnyConfigurator<Drivable: _Drivable>: Configurator {
54+
private let thing: Driver?
55+
func configure(driver: AnyConfigurator.Driver) {}
56+
}

test/decl/protocol/typealias_inference.swift

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)