Skip to content

Commit 04fbcc0

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 686ddd7 commit 04fbcc0

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
@@ -3510,20 +3510,37 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
35103510
AssociatedTypeDecl *assocType) {
35113511
// Conformances constructed by the ClangImporter should have explicit type
35123512
// witnesses already.
3513-
if (isa<ClangModuleUnit>(Conformance->getDeclContext()->getModuleScopeContext())) {
3513+
if (isa<ClangModuleUnit>(DC->getModuleScopeContext())) {
35143514
llvm::errs() << "Cannot look up associated type for imported conformance:\n";
35153515
Conformance->getType().dump(llvm::errs());
35163516
assocType->dump(llvm::errs());
35173517
abort();
35183518
}
35193519

3520+
// If we fail to find a witness via lookup, check for a generic parameter.
3521+
auto checkForGenericParameter = [&]() {
3522+
// If there is a generic parameter of the named type, use that.
3523+
if (auto genericSig = DC->getGenericSignatureOfContext()) {
3524+
for (auto gp : genericSig->getInnermostGenericParams()) {
3525+
if (gp->getName() == assocType->getName()) {
3526+
if (!checkTypeWitness(DC, Proto, assocType, gp)) {
3527+
recordTypeWitness(assocType, gp, nullptr);
3528+
return ResolveWitnessResult::Success;
3529+
}
3530+
}
3531+
}
3532+
}
3533+
3534+
return ResolveWitnessResult::Missing;
3535+
};
3536+
35203537
// Look for a member type with the same name as the associated type.
35213538
auto candidates = TypeChecker::lookupMemberType(
35223539
DC, Adoptee, assocType->getName(), NameLookupFlags::ProtocolMembers);
35233540

35243541
// If there aren't any candidates, we're done.
35253542
if (!candidates) {
3526-
return ResolveWitnessResult::Missing;
3543+
return checkForGenericParameter();
35273544
}
35283545

35293546
// Determine which of the candidates is viable.
@@ -3557,7 +3574,7 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
35573574
return x.first->getDeclContext()
35583575
->getSelfProtocolDecl() == nullptr;
35593576
}) == nonViable.end())
3560-
return ResolveWitnessResult::Missing;
3577+
return checkForGenericParameter();
35613578

35623579
// If there is a single viable candidate, form a substitution for it.
35633580
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)