Skip to content

Commit 35ed7b5

Browse files
committed
GSB: Fix maybeResolveEquivalenceClass() with member type of superclass-constrained type
Name lookup might find an associated type whose protocol is not in our conforms-to list, if we have a superclass constraint and the superclass conforms to the associated type's protocol. We used to return an unresolved type in this case, which would result in the constraint getting delayed forever and dropped. While playing wack-a-mole with regressing crashers, I had to do some refactoring to get all the tests to pass. Unfortuanately these refactorings don't lend themselves well to being peeled off into their own commits: - maybeAddSameTypeRequirementForNestedType() was almost identical to concretizeNestedTypeFromConcreteParent(), except for superclasses instead of concrete same-type constraints. I merged them together. - We used to drop same-type constraints where the subject type was an ErrorType, because maybeResolveEquivalenceClass() would return an unresolved type in this case. This violated some invariants around nested types of ArchetypeTypes, because now it was possible for a nested type of a concrete type to be non-concrete, if the type witness in the conformance was missing due to an error. Fix this by removing the ErrorType hack, and adjusting a couple of other places to handle ErrorTypes in order to avoid regressing with invalid code. Fixes <rdar://problem/45216921>, <https://bugs.swift.org/browse/SR-8945>, <https://bugs.swift.org/browse/SR-12744>.
1 parent be173b0 commit 35ed7b5

File tree

8 files changed

+112
-127
lines changed

8 files changed

+112
-127
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 85 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -2370,43 +2370,6 @@ Type ResolvedType::getDependentType(GenericSignatureBuilder &builder) const {
23702370
return result->isTypeParameter() ? result : Type();
23712371
}
23722372

2373-
/// If there is a same-type requirement to be added for the given nested type
2374-
/// due to a superclass constraint on the parent type, add it now.
2375-
static void maybeAddSameTypeRequirementForNestedType(
2376-
ResolvedType nested,
2377-
const RequirementSource *superSource,
2378-
GenericSignatureBuilder &builder) {
2379-
// If there's no super conformance, we're done.
2380-
if (!superSource) return;
2381-
2382-
// If the nested type is already concrete, we're done.
2383-
if (nested.getAsConcreteType()) return;
2384-
2385-
// Dig out the associated type.
2386-
AssociatedTypeDecl *assocType = nullptr;
2387-
if (auto depMemTy =
2388-
nested.getDependentType(builder)->getAs<DependentMemberType>())
2389-
assocType = depMemTy->getAssocType();
2390-
else
2391-
return;
2392-
2393-
// Dig out the type witness.
2394-
auto superConformance = superSource->getProtocolConformance().getConcrete();
2395-
auto concreteType = superConformance->getTypeWitness(assocType);
2396-
if (!concreteType) return;
2397-
2398-
// We should only have interface types here.
2399-
assert(!superConformance->getType()->hasArchetype());
2400-
assert(!concreteType->hasArchetype());
2401-
2402-
// Add the same-type constraint.
2403-
auto nestedSource = superSource->viaParent(builder, assocType);
2404-
2405-
builder.addSameTypeRequirement(
2406-
nested.getUnresolvedType(), concreteType, nestedSource,
2407-
GenericSignatureBuilder::UnresolvedHandlingKind::GenerateConstraints);
2408-
}
2409-
24102373
auto PotentialArchetype::getOrCreateEquivalenceClass(
24112374
GenericSignatureBuilder &builder) const
24122375
-> EquivalenceClass * {
@@ -2542,7 +2505,9 @@ static void concretizeNestedTypeFromConcreteParent(
25422505
// If we don't already have a conformance of the parent to this protocol,
25432506
// add it now; it was elided earlier.
25442507
if (parentEquiv->conformsTo.count(proto) == 0) {
2545-
auto source = parentEquiv->concreteTypeConstraints.front().source;
2508+
auto source = (!isSuperclassConstrained
2509+
? parentEquiv->concreteTypeConstraints.front().source
2510+
: parentEquiv->superclassConstraints.front().source);
25462511
parentEquiv->recordConformanceConstraint(builder, parent, proto, source);
25472512
}
25482513

@@ -2572,7 +2537,7 @@ static void concretizeNestedTypeFromConcreteParent(
25722537
if (conformance.isConcrete()) {
25732538
witnessType =
25742539
conformance.getConcrete()->getTypeWitness(assocType);
2575-
if (!witnessType || witnessType->hasError())
2540+
if (!witnessType)
25762541
return; // FIXME: should we delay here?
25772542
} else if (auto archetype = concreteParent->getAs<ArchetypeType>()) {
25782543
witnessType = archetype->getNestedType(assocType->getName());
@@ -2637,20 +2602,11 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance(
26372602

26382603
// If we have a potential archetype that requires more processing, do so now.
26392604
if (shouldUpdatePA) {
2640-
// If there's a superclass constraint that conforms to the protocol,
2641-
// add the appropriate same-type relationship.
2642-
const auto proto = assocType->getProtocol();
2643-
if (proto) {
2644-
if (auto superSource = builder.resolveSuperConformance(this, proto)) {
2645-
maybeAddSameTypeRequirementForNestedType(resultPA, superSource,
2646-
builder);
2647-
}
2648-
}
2649-
26502605
// We know something concrete about the parent PA, so we need to propagate
26512606
// that information to this new archetype.
2652-
if (isConcreteType()) {
2653-
concretizeNestedTypeFromConcreteParent(this, resultPA, builder);
2607+
if (auto equivClass = getEquivalenceClassIfPresent()) {
2608+
if (equivClass->concreteType || equivClass->superclass)
2609+
concretizeNestedTypeFromConcreteParent(this, resultPA, builder);
26542610
}
26552611
}
26562612

@@ -3585,50 +3541,29 @@ static Type getStructuralType(TypeDecl *typeDecl, bool keepSugar) {
35853541
return typeDecl->getDeclaredInterfaceType();
35863542
}
35873543

3588-
static Type substituteConcreteType(GenericSignatureBuilder &builder,
3589-
PotentialArchetype *basePA,
3544+
static Type substituteConcreteType(Type parentType,
35903545
TypeDecl *concreteDecl) {
3546+
if (parentType->is<ErrorType>())
3547+
return parentType;
3548+
35913549
assert(concreteDecl);
35923550

35933551
auto *dc = concreteDecl->getDeclContext();
3594-
auto *proto = dc->getSelfProtocolDecl();
35953552

35963553
// Form an unsubstituted type referring to the given type declaration,
35973554
// for use in an inferred same-type requirement.
35983555
auto type = getStructuralType(concreteDecl, /*keepSugar=*/true);
35993556

3600-
SubstitutionMap subMap;
3601-
if (proto) {
3602-
// Substitute in the type of the current PotentialArchetype in
3603-
// place of 'Self' here.
3604-
auto parentType = basePA->getDependentType(builder.getGenericParams());
3605-
3606-
subMap = SubstitutionMap::getProtocolSubstitutions(
3607-
proto, parentType, ProtocolConformanceRef(proto));
3608-
} else {
3609-
// Substitute in the superclass type.
3610-
auto parentPA = basePA->getEquivalenceClassIfPresent();
3611-
auto parentType =
3612-
parentPA->concreteType ? parentPA->concreteType : parentPA->superclass;
3613-
auto parentDecl = parentType->getAnyNominal();
3614-
3615-
subMap = parentType->getContextSubstitutionMap(
3616-
parentDecl->getParentModule(), dc);
3617-
}
3557+
auto subMap = parentType->getContextSubstitutionMap(
3558+
dc->getParentModule(), dc);
36183559

36193560
return type.subst(subMap);
3620-
};
3561+
}
36213562

36223563
ResolvedType GenericSignatureBuilder::maybeResolveEquivalenceClass(
36233564
Type type,
36243565
ArchetypeResolutionKind resolutionKind,
36253566
bool wantExactPotentialArchetype) {
3626-
// An error type is best modeled as an unresolved potential archetype, since
3627-
// there's no way to be sure what it is actually meant to be.
3628-
if (type->is<ErrorType>()) {
3629-
return ResolvedType::forUnresolved(nullptr);
3630-
}
3631-
36323567
// The equivalence class of a generic type is known directly.
36333568
if (auto genericParam = type->getAs<GenericTypeParamType>()) {
36343569
unsigned index = GenericParamKey(genericParam).findIndexIn(
@@ -3650,8 +3585,11 @@ ResolvedType GenericSignatureBuilder::maybeResolveEquivalenceClass(
36503585
wantExactPotentialArchetype);
36513586
if (!resolvedBase) return resolvedBase;
36523587
// If the base is concrete, so is this member.
3653-
if (resolvedBase.getAsConcreteType())
3654-
return ResolvedType::forConcrete(type);
3588+
if (auto parentType = resolvedBase.getAsConcreteType()) {
3589+
auto concreteType = substituteConcreteType(parentType,
3590+
depMemTy->getAssocType());
3591+
return ResolvedType::forConcrete(concreteType);
3592+
}
36553593

36563594
// Find the nested type declaration for this.
36573595
auto baseEquivClass = resolvedBase.getEquivalenceClass(*this);
@@ -3668,59 +3606,84 @@ ResolvedType GenericSignatureBuilder::maybeResolveEquivalenceClass(
36683606
basePA = baseEquivClass->members.front();
36693607
}
36703608

3671-
AssociatedTypeDecl *nestedTypeDecl = nullptr;
36723609
if (auto assocType = depMemTy->getAssocType()) {
36733610
// Check whether this associated type references a protocol to which
3674-
// the base conforms. If not, it's unresolved.
3675-
if (baseEquivClass->conformsTo.find(assocType->getProtocol())
3611+
// the base conforms. If not, it's either concrete or unresolved.
3612+
auto *proto = assocType->getProtocol();
3613+
if (baseEquivClass->conformsTo.find(proto)
36763614
== baseEquivClass->conformsTo.end()) {
3677-
if (!baseEquivClass->concreteType ||
3678-
!lookupConformance(type->getCanonicalType(),
3679-
baseEquivClass->concreteType,
3680-
assocType->getProtocol())) {
3615+
if (baseEquivClass->concreteType &&
3616+
lookupConformance(type->getCanonicalType(),
3617+
baseEquivClass->concreteType,
3618+
proto)) {
3619+
// Fall through
3620+
} else if (baseEquivClass->superclass &&
3621+
lookupConformance(type->getCanonicalType(),
3622+
baseEquivClass->superclass,
3623+
proto)) {
3624+
// Fall through
3625+
} else {
36813626
return ResolvedType::forUnresolved(baseEquivClass);
36823627
}
3628+
3629+
// FIXME: Instead of falling through, we ought to return a concrete
3630+
// type here, but then we fail to update a nested PotentialArchetype
3631+
// if one happens to already exist. It would be cleaner if concrete
3632+
// types never had nested PotentialArchetypes.
36833633
}
36843634

3685-
nestedTypeDecl = assocType;
3635+
auto nestedPA =
3636+
basePA->updateNestedTypeForConformance(*this, assocType,
3637+
resolutionKind);
3638+
if (!nestedPA)
3639+
return ResolvedType::forUnresolved(baseEquivClass);
3640+
3641+
// If base resolved to the anchor, then the nested potential archetype
3642+
// we found is the resolved potential archetype. Return it directly,
3643+
// so it doesn't need to be resolved again.
3644+
if (basePA == resolvedBase.getPotentialArchetypeIfKnown())
3645+
return ResolvedType(nestedPA);
3646+
3647+
// Compute the resolved dependent type to return.
3648+
Type resolvedBaseType = resolvedBase.getDependentType(*this);
3649+
Type resolvedMemberType =
3650+
DependentMemberType::get(resolvedBaseType, assocType);
3651+
3652+
return ResolvedType(resolvedMemberType,
3653+
nestedPA->getOrCreateEquivalenceClass(*this));
36863654
} else {
3687-
auto *typeAlias =
3655+
auto *concreteDecl =
36883656
baseEquivClass->lookupNestedType(*this, depMemTy->getName());
36893657

3690-
if (!typeAlias)
3658+
if (!concreteDecl)
36913659
return ResolvedType::forUnresolved(baseEquivClass);
36923660

3693-
auto type = substituteConcreteType(*this, basePA, typeAlias);
3694-
return maybeResolveEquivalenceClass(type, resolutionKind,
3695-
wantExactPotentialArchetype);
3696-
}
3661+
Type parentType;
3662+
auto *proto = concreteDecl->getDeclContext()->getSelfProtocolDecl();
3663+
if (!proto) {
3664+
parentType = (baseEquivClass->concreteType
3665+
? baseEquivClass->concreteType
3666+
: baseEquivClass->superclass);
3667+
} else {
3668+
if (baseEquivClass->concreteType &&
3669+
lookupConformance(type->getCanonicalType(),
3670+
baseEquivClass->concreteType,
3671+
proto)) {
3672+
parentType = baseEquivClass->concreteType;
3673+
} else if (baseEquivClass->superclass &&
3674+
lookupConformance(type->getCanonicalType(),
3675+
baseEquivClass->superclass,
3676+
proto)) {
3677+
parentType = baseEquivClass->superclass;
3678+
} else {
3679+
parentType = basePA->getDependentType(getGenericParams());
3680+
}
3681+
}
36973682

3698-
auto nestedPA =
3699-
basePA->updateNestedTypeForConformance(*this, nestedTypeDecl,
3700-
resolutionKind);
3701-
if (!nestedPA)
3702-
return ResolvedType::forUnresolved(baseEquivClass);
3703-
3704-
// If base resolved to the anchor, then the nested potential archetype
3705-
// we found is the resolved potential archetype. Return it directly,
3706-
// so it doesn't need to be resolved again.
3707-
if (basePA == resolvedBase.getPotentialArchetypeIfKnown())
3708-
return ResolvedType(nestedPA);
3709-
3710-
// Compute the resolved dependent type to return.
3711-
Type resolvedBaseType = resolvedBase.getDependentType(*this);
3712-
Type resolvedMemberType;
3713-
if (auto assocType = dyn_cast<AssociatedTypeDecl>(nestedTypeDecl)) {
3714-
resolvedMemberType =
3715-
DependentMemberType::get(resolvedBaseType, assocType);
3716-
} else {
3717-
// Note: strange case that might not even really be dependent.
3718-
resolvedMemberType =
3719-
DependentMemberType::get(resolvedBaseType, depMemTy->getName());
3683+
auto concreteType = substituteConcreteType(parentType, concreteDecl);
3684+
return maybeResolveEquivalenceClass(concreteType, resolutionKind,
3685+
wantExactPotentialArchetype);
37203686
}
3721-
3722-
return ResolvedType(resolvedMemberType,
3723-
nestedPA->getOrCreateEquivalenceClass(*this));
37243687
}
37253688

37263689
// If it's not a type parameter, it won't directly resolve to one.
@@ -5523,7 +5486,8 @@ GenericSignatureBuilder::finalize(SourceLoc loc,
55235486
// Don't allow a generic parameter to be equivalent to a concrete type,
55245487
// because then we don't actually have a parameter.
55255488
auto equivClass = rep->getOrCreateEquivalenceClass(*this);
5526-
if (equivClass->concreteType) {
5489+
if (equivClass->concreteType &&
5490+
!equivClass->concreteType->is<ErrorType>()) {
55275491
if (auto constraint = equivClass->findAnyConcreteConstraintAsWritten()){
55285492
Impl->HadAnyError = true;
55295493

test/Constraints/same_types.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,14 @@ func test6<T: Barrable>(_ t: T) -> (Y, X) where T.Bar == Y {
8989
}
9090

9191
func test7<T: Barrable>(_ t: T) -> (Y, X) where T.Bar == Y, T.Bar.Foo == X {
92-
// expected-warning@-1{{redundant same-type constraint 'T.Bar.Foo' == 'X'}}
93-
// expected-note@-2{{same-type constraint 'T.Bar.Foo' == 'Y.Foo' (aka 'X') implied here}}
92+
// expected-warning@-1{{neither type in same-type constraint ('Y.Foo' (aka 'X') or 'X') refers to a generic parameter or associated type}}
9493
return (t.bar, t.bar.foo)
9594
}
9695

9796
func fail4<T: Barrable>(_ t: T) -> (Y, Z)
9897
where
99-
T.Bar == Y, // expected-note{{same-type constraint 'T.Bar.Foo' == 'Y.Foo' (aka 'X') implied here}}
100-
T.Bar.Foo == Z { // expected-error{{'T.Bar.Foo' cannot be equal to both 'Z' and 'Y.Foo' (aka 'X')}}
98+
T.Bar == Y,
99+
T.Bar.Foo == Z { // expected-error{{generic signature requires types 'Y.Foo' (aka 'X') and 'Z' to be the same}}
101100
return (t.bar, t.bar.foo) // expected-error{{cannot convert return expression of type '(Y, X)' to return type '(Y, Z)'}}
102101
}
103102

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public protocol P {
2+
associatedtype T
3+
}

test/Generics/sr8945.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module %S/Inputs/sr8945-other.swift -emit-module-path %t/other.swiftmodule -module-name other
3+
// RUN: %target-swift-frontend -emit-silgen %s -I%t
4+
5+
import other
6+
7+
public class C : P {
8+
public typealias T = Int
9+
}
10+
11+
public func takesInt(_: Int) {}
12+
13+
public func foo<T : C, S : Sequence>(_: T, _ xs: S) where S.Element == T.T {
14+
for x in xs {
15+
takesInt(x)
16+
}
17+
}

test/IDE/print_ast_tc_decls_errors.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ protocol AssociatedType1 {
192192
// TYREPR: {{^}} associatedtype AssociatedTypeDecl4 : FooNonExistentProtocol, BarNonExistentProtocol{{$}}
193193

194194
associatedtype AssociatedTypeDecl5 : FooClass
195-
// CHECK: {{^}} associatedtype AssociatedTypeDecl5 : FooClass{{$}}
195+
// CHECK: {{^}} associatedtype AssociatedTypeDecl5{{$}}
196196
}
197197

198198
//===---

test/decl/protocol/req/recursion.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public struct S<A: P> where A.T == S<A> { // expected-error {{circular reference
4848
// expected-error@-2 {{generic struct 'S' references itself}}
4949
func f(a: A.T) {
5050
g(a: id(t: a))
51-
// expected-error@-1 {{cannot convert value of type 'A.T' to expected argument type 'S<A>'}}
51+
// expected-error@-1 {{type of expression is ambiguous without more context}}
5252
_ = A.T.self
5353
}
5454

validation-test/compiler_crashers_2_fixed/0159-rdar40009245.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
protocol P {
44
associatedtype A : P where A.X == Self
5+
// expected-error@-1{{'X' is not a member type of 'Self.A}}
56
associatedtype X : P where P.A == Self
67
// expected-error@-1{{associated type 'A' can only be used with a concrete type or generic parameter base}}
78
}

validation-test/compiler_crashers_2_fixed/0163-sr8033.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ protocol P1 {
77
}
88
extension Foo: P1 where A : P1 {} // expected-error {{unsupported recursion for reference to associated type 'A' of type 'Foo<T>'}}
99
// expected-error@-1 {{type 'Foo<T>' does not conform to protocol 'P1'}}
10+
// expected-error@-2 {{type 'Foo<T>' in conformance requirement does not refer to a generic parameter or associated type}}

0 commit comments

Comments
 (0)