Skip to content

Commit 25ebcac

Browse files
authored
Merge pull request #28157 from slavapestov/tiny-assoc-type-fixes
Tiny associated type inference fixes
2 parents 10aac56 + 04fbcc0 commit 25ebcac

File tree

9 files changed

+144
-64
lines changed

9 files changed

+144
-64
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2215,16 +2215,39 @@ ConformanceChecker::getReferencedAssociatedTypes(ValueDecl *req) {
22152215
return known->second;
22162216

22172217
// Collect the set of associated types rooted on Self in the
2218-
// signature.
2218+
// signature. Note that for references to nested types, we only
2219+
// want to consider the outermost dependent member type.
2220+
//
2221+
// For example, a requirement typed '(Iterator.Element) -> ()'
2222+
// is not considered to reference the associated type 'Iterator'.
22192223
auto &assocTypes = ReferencedAssociatedTypes[req];
2220-
llvm::SmallPtrSet<AssociatedTypeDecl *, 4> knownAssocTypes;
2221-
req->getInterfaceType()->getCanonicalType().visit([&](CanType type) {
2222-
if (auto assocType = getReferencedAssocTypeOfProtocol(type, Proto)) {
2223-
if (knownAssocTypes.insert(assocType).second) {
2224-
assocTypes.push_back(assocType);
2224+
2225+
class Walker : public TypeWalker {
2226+
ProtocolDecl *Proto;
2227+
llvm::SmallVectorImpl<AssociatedTypeDecl *> &assocTypes;
2228+
llvm::SmallPtrSet<AssociatedTypeDecl *, 4> knownAssocTypes;
2229+
2230+
public:
2231+
Walker(ProtocolDecl *Proto,
2232+
llvm::SmallVectorImpl<AssociatedTypeDecl *> &assocTypes)
2233+
: Proto(Proto), assocTypes(assocTypes) {}
2234+
2235+
Action walkToTypePre(Type type) override {
2236+
if (type->is<DependentMemberType>()) {
2237+
if (auto assocType = getReferencedAssocTypeOfProtocol(type, Proto)) {
2238+
if (knownAssocTypes.insert(assocType).second)
2239+
assocTypes.push_back(assocType);
22252240
}
2241+
2242+
return Action::SkipChildren;
22262243
}
2227-
});
2244+
2245+
return Action::Continue;
2246+
}
2247+
};
2248+
2249+
Walker walker(Proto, assocTypes);
2250+
req->getInterfaceType()->getCanonicalType().walk(walker);
22282251

22292252
return assocTypes;
22302253
}
@@ -3487,20 +3510,37 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
34873510
AssociatedTypeDecl *assocType) {
34883511
// Conformances constructed by the ClangImporter should have explicit type
34893512
// witnesses already.
3490-
if (isa<ClangModuleUnit>(Conformance->getDeclContext()->getModuleScopeContext())) {
3513+
if (isa<ClangModuleUnit>(DC->getModuleScopeContext())) {
34913514
llvm::errs() << "Cannot look up associated type for imported conformance:\n";
34923515
Conformance->getType().dump(llvm::errs());
34933516
assocType->dump(llvm::errs());
34943517
abort();
34953518
}
34963519

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+
34973537
// Look for a member type with the same name as the associated type.
34983538
auto candidates = TypeChecker::lookupMemberType(
34993539
DC, Adoptee, assocType->getName(), NameLookupFlags::ProtocolMembers);
35003540

35013541
// If there aren't any candidates, we're done.
35023542
if (!candidates) {
3503-
return ResolveWitnessResult::Missing;
3543+
return checkForGenericParameter();
35043544
}
35053545

35063546
// Determine which of the candidates is viable.
@@ -3534,7 +3574,7 @@ ResolveWitnessResult ConformanceChecker::resolveTypeWitnessViaLookup(
35343574
return x.first->getDeclContext()
35353575
->getSelfProtocolDecl() == nullptr;
35363576
}) == nonViable.end())
3537-
return ResolveWitnessResult::Missing;
3577+
return checkForGenericParameter();
35383578

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

lib/Sema/TypeCheckType.cpp

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,18 +1406,13 @@ static Type resolveNestedIdentTypeComponent(
14061406

14071407
// Diagnose a bad conformance reference if we need to.
14081408
if (!options.contains(TypeResolutionFlags::SilenceErrors) &&
1409-
inferredAssocType && memberType && memberType->hasError()) {
1409+
inferredAssocType && memberType->hasError()) {
14101410
maybeDiagnoseBadConformanceRef(DC, parentTy, comp->getLoc(),
14111411
inferredAssocType);
14121412
}
14131413

1414-
// If we found a reference to an associated type or other member type that
1415-
// was marked invalid, just return ErrorType to silence downstream errors.
1416-
if (member->isInvalid())
1417-
return ErrorType::get(ctx);
1418-
14191414
// At this point, we need to have resolved the type of the member.
1420-
if (!memberType || memberType->hasError())
1415+
if (memberType->hasError())
14211416
return memberType;
14221417

14231418
// If there are generic arguments, apply them now.
@@ -2592,26 +2587,11 @@ Type TypeResolver::resolveSILBoxType(SILBoxTypeRepr *repr,
25922587
auto argTy = resolveType(repr->getGenericArguments()[i], options);
25932588
genericArgMap.insert({params[i], argTy->getCanonicalType()});
25942589
}
2595-
2596-
bool ok = true;
2590+
25972591
subMap = SubstitutionMap::get(
25982592
genericSig,
25992593
QueryTypeSubstitutionMap{genericArgMap},
2600-
[&](CanType depTy, Type replacement, ProtocolDecl *proto)
2601-
-> ProtocolConformanceRef {
2602-
auto result = TypeChecker::conformsToProtocol(
2603-
replacement, proto, DC,
2604-
ConformanceCheckOptions());
2605-
if (result.isInvalid()) {
2606-
ok = false;
2607-
return ProtocolConformanceRef(proto);
2608-
}
2609-
2610-
return result;
2611-
});
2612-
2613-
if (!ok)
2614-
return ErrorType::get(Context);
2594+
TypeChecker::LookUpConformance(DC));
26152595
}
26162596

26172597
auto layout = SILLayout::get(Context, genericSig, fields);

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/nested/protocol.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,7 @@ func testLookup(_ x: OuterForUFI.Inner) {
106106
x.extMethod()
107107
}
108108

109-
// N.B. Lookup fails here because OuterForUFI.Inner is marked invalid.
110109
func testLookup<T: OuterForUFI.Inner>(_ x: T) {
111-
x.req() // expected-error {{value of type 'T' has no member 'req'}}
112-
x.extMethod() // expected-error {{value of type 'T' has no member 'extMethod'}}
110+
x.req()
111+
x.extMethod()
113112
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// RUN: %target-swift-frontend -emit-silgen %s
2+
3+
// This is a SILGen test to ensure we can completely check these conformances
4+
// and build valid AST.
5+
6+
protocol P {
7+
associatedtype T : Q = S
8+
typealias Y = T.X
9+
10+
func foo(_: T.X)
11+
}
12+
13+
protocol Q {
14+
associatedtype X
15+
}
16+
17+
struct S : Q {
18+
typealias X = ()
19+
}
20+
21+
struct R : P {
22+
let x: Y? = nil
23+
func foo(_: Y) {}
24+
}
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.

validation-test/compiler_crashers_2_fixed/sr11052-typealias.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ struct Concrete<AType2: ProtoA>: ProtoB {
1919
fatalError()
2020
}
2121

22-
func protoFunc() -> Alias { // expected-error{{unsupported recursion for reference to type alias 'Alias' of type 'Concrete<AType2>'}}
22+
func protoFunc() -> Alias {
2323
fatalError()
2424
}
2525
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %target-swift-frontend -verify -emit-ir %s
2+
3+
// Ideally this would type check successfully; we should be able to
4+
// infer that X == Int using the same-type constraint 'A.X == X'.
5+
6+
protocol P1 {
7+
associatedtype X
8+
// expected-note@-1 {{protocol requires nested type 'X'; do you want to add it?}}
9+
associatedtype A: P2 where A.X == X
10+
}
11+
12+
protocol P2 {
13+
associatedtype X
14+
}
15+
16+
struct S {}
17+
18+
extension S {
19+
struct A: P2 {
20+
typealias X = Int
21+
}
22+
}
23+
24+
25+
extension S: P1 {}
26+
// expected-error@-1 {{type 'S' does not conform to protocol 'P1'}}
27+
28+
print(S.X.self)

0 commit comments

Comments
 (0)