Skip to content

Commit 0a79beb

Browse files
authored
Merge pull request swiftlang#31871 from slavapestov/superclass-nested-type-fix
GSB: Fix maybeResolveEquivalenceClass() with member type of superclass-constrained type
2 parents f11f8f0 + 653fa07 commit 0a79beb

File tree

9 files changed

+113
-129
lines changed

9 files changed

+113
-129
lines changed

lib/AST/GenericSignatureBuilder.cpp

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

2393-
/// If there is a same-type requirement to be added for the given nested type
2394-
/// due to a superclass constraint on the parent type, add it now.
2395-
static void maybeAddSameTypeRequirementForNestedType(
2396-
ResolvedType nested,
2397-
const RequirementSource *superSource,
2398-
GenericSignatureBuilder &builder) {
2399-
// If there's no super conformance, we're done.
2400-
if (!superSource) return;
2401-
2402-
// If the nested type is already concrete, we're done.
2403-
if (nested.getAsConcreteType()) return;
2404-
2405-
// Dig out the associated type.
2406-
AssociatedTypeDecl *assocType = nullptr;
2407-
if (auto depMemTy =
2408-
nested.getDependentType(builder)->getAs<DependentMemberType>())
2409-
assocType = depMemTy->getAssocType();
2410-
else
2411-
return;
2412-
2413-
// Dig out the type witness.
2414-
auto superConformance = superSource->getProtocolConformance().getConcrete();
2415-
auto concreteType = superConformance->getTypeWitness(assocType);
2416-
if (!concreteType) return;
2417-
2418-
// We should only have interface types here.
2419-
assert(!superConformance->getType()->hasArchetype());
2420-
assert(!concreteType->hasArchetype());
2421-
2422-
// Add the same-type constraint.
2423-
auto nestedSource = superSource->viaParent(builder, assocType);
2424-
2425-
builder.addSameTypeRequirement(
2426-
nested.getUnresolvedType(), concreteType, nestedSource,
2427-
GenericSignatureBuilder::UnresolvedHandlingKind::GenerateConstraints);
2428-
}
2429-
24302393
auto PotentialArchetype::getOrCreateEquivalenceClass(
24312394
GenericSignatureBuilder &builder) const
24322395
-> EquivalenceClass * {
@@ -2562,7 +2525,9 @@ static void concretizeNestedTypeFromConcreteParent(
25622525
// If we don't already have a conformance of the parent to this protocol,
25632526
// add it now; it was elided earlier.
25642527
if (parentEquiv->conformsTo.count(proto) == 0) {
2565-
auto source = parentEquiv->concreteTypeConstraints.front().source;
2528+
auto source = (!isSuperclassConstrained
2529+
? parentEquiv->concreteTypeConstraints.front().source
2530+
: parentEquiv->superclassConstraints.front().source);
25662531
parentEquiv->recordConformanceConstraint(builder, parent, proto, source);
25672532
}
25682533

@@ -2592,7 +2557,7 @@ static void concretizeNestedTypeFromConcreteParent(
25922557
if (conformance.isConcrete()) {
25932558
witnessType =
25942559
conformance.getConcrete()->getTypeWitness(assocType);
2595-
if (!witnessType || witnessType->hasError())
2560+
if (!witnessType)
25962561
return; // FIXME: should we delay here?
25972562
} else if (auto archetype = concreteParent->getAs<ArchetypeType>()) {
25982563
witnessType = archetype->getNestedType(assocType->getName());
@@ -2657,20 +2622,11 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance(
26572622

26582623
// If we have a potential archetype that requires more processing, do so now.
26592624
if (shouldUpdatePA) {
2660-
// If there's a superclass constraint that conforms to the protocol,
2661-
// add the appropriate same-type relationship.
2662-
const auto proto = assocType->getProtocol();
2663-
if (proto) {
2664-
if (auto superSource = builder.resolveSuperConformance(this, proto)) {
2665-
maybeAddSameTypeRequirementForNestedType(resultPA, superSource,
2666-
builder);
2667-
}
2668-
}
2669-
26702625
// We know something concrete about the parent PA, so we need to propagate
26712626
// that information to this new archetype.
2672-
if (isConcreteType()) {
2673-
concretizeNestedTypeFromConcreteParent(this, resultPA, builder);
2627+
if (auto equivClass = getEquivalenceClassIfPresent()) {
2628+
if (equivClass->concreteType || equivClass->superclass)
2629+
concretizeNestedTypeFromConcreteParent(this, resultPA, builder);
26742630
}
26752631
}
26762632

@@ -3618,50 +3574,29 @@ static Type getStructuralType(TypeDecl *typeDecl, bool keepSugar) {
36183574
return typeDecl->getDeclaredInterfaceType();
36193575
}
36203576

3621-
static Type substituteConcreteType(GenericSignatureBuilder &builder,
3622-
PotentialArchetype *basePA,
3577+
static Type substituteConcreteType(Type parentType,
36233578
TypeDecl *concreteDecl) {
3579+
if (parentType->is<ErrorType>())
3580+
return parentType;
3581+
36243582
assert(concreteDecl);
36253583

36263584
auto *dc = concreteDecl->getDeclContext();
3627-
auto *proto = dc->getSelfProtocolDecl();
36283585

36293586
// Form an unsubstituted type referring to the given type declaration,
36303587
// for use in an inferred same-type requirement.
36313588
auto type = getStructuralType(concreteDecl, /*keepSugar=*/true);
36323589

3633-
SubstitutionMap subMap;
3634-
if (proto) {
3635-
// Substitute in the type of the current PotentialArchetype in
3636-
// place of 'Self' here.
3637-
auto parentType = basePA->getDependentType(builder.getGenericParams());
3638-
3639-
subMap = SubstitutionMap::getProtocolSubstitutions(
3640-
proto, parentType, ProtocolConformanceRef(proto));
3641-
} else {
3642-
// Substitute in the superclass type.
3643-
auto parentPA = basePA->getEquivalenceClassIfPresent();
3644-
auto parentType =
3645-
parentPA->concreteType ? parentPA->concreteType : parentPA->superclass;
3646-
auto parentDecl = parentType->getAnyNominal();
3647-
3648-
subMap = parentType->getContextSubstitutionMap(
3649-
parentDecl->getParentModule(), dc);
3650-
}
3590+
auto subMap = parentType->getContextSubstitutionMap(
3591+
dc->getParentModule(), dc);
36513592

36523593
return type.subst(subMap);
3653-
};
3594+
}
36543595

36553596
ResolvedType GenericSignatureBuilder::maybeResolveEquivalenceClass(
36563597
Type type,
36573598
ArchetypeResolutionKind resolutionKind,
36583599
bool wantExactPotentialArchetype) {
3659-
// An error type is best modeled as an unresolved potential archetype, since
3660-
// there's no way to be sure what it is actually meant to be.
3661-
if (type->is<ErrorType>()) {
3662-
return ResolvedType::forUnresolved(nullptr);
3663-
}
3664-
36653600
// The equivalence class of a generic type is known directly.
36663601
if (auto genericParam = type->getAs<GenericTypeParamType>()) {
36673602
unsigned index = GenericParamKey(genericParam).findIndexIn(
@@ -3683,8 +3618,11 @@ ResolvedType GenericSignatureBuilder::maybeResolveEquivalenceClass(
36833618
wantExactPotentialArchetype);
36843619
if (!resolvedBase) return resolvedBase;
36853620
// If the base is concrete, so is this member.
3686-
if (resolvedBase.getAsConcreteType())
3687-
return ResolvedType::forConcrete(type);
3621+
if (auto parentType = resolvedBase.getAsConcreteType()) {
3622+
auto concreteType = substituteConcreteType(parentType,
3623+
depMemTy->getAssocType());
3624+
return ResolvedType::forConcrete(concreteType);
3625+
}
36883626

36893627
// Find the nested type declaration for this.
36903628
auto baseEquivClass = resolvedBase.getEquivalenceClass(*this);
@@ -3701,59 +3639,84 @@ ResolvedType GenericSignatureBuilder::maybeResolveEquivalenceClass(
37013639
basePA = baseEquivClass->members.front();
37023640
}
37033641

3704-
AssociatedTypeDecl *nestedTypeDecl = nullptr;
37053642
if (auto assocType = depMemTy->getAssocType()) {
37063643
// Check whether this associated type references a protocol to which
3707-
// the base conforms. If not, it's unresolved.
3708-
if (baseEquivClass->conformsTo.find(assocType->getProtocol())
3644+
// the base conforms. If not, it's either concrete or unresolved.
3645+
auto *proto = assocType->getProtocol();
3646+
if (baseEquivClass->conformsTo.find(proto)
37093647
== baseEquivClass->conformsTo.end()) {
3710-
if (!baseEquivClass->concreteType ||
3711-
!lookupConformance(type->getCanonicalType(),
3712-
baseEquivClass->concreteType,
3713-
assocType->getProtocol())) {
3648+
if (baseEquivClass->concreteType &&
3649+
lookupConformance(type->getCanonicalType(),
3650+
baseEquivClass->concreteType,
3651+
proto)) {
3652+
// Fall through
3653+
} else if (baseEquivClass->superclass &&
3654+
lookupConformance(type->getCanonicalType(),
3655+
baseEquivClass->superclass,
3656+
proto)) {
3657+
// Fall through
3658+
} else {
37143659
return ResolvedType::forUnresolved(baseEquivClass);
37153660
}
3661+
3662+
// FIXME: Instead of falling through, we ought to return a concrete
3663+
// type here, but then we fail to update a nested PotentialArchetype
3664+
// if one happens to already exist. It would be cleaner if concrete
3665+
// types never had nested PotentialArchetypes.
37163666
}
37173667

3718-
nestedTypeDecl = assocType;
3668+
auto nestedPA =
3669+
basePA->updateNestedTypeForConformance(*this, assocType,
3670+
resolutionKind);
3671+
if (!nestedPA)
3672+
return ResolvedType::forUnresolved(baseEquivClass);
3673+
3674+
// If base resolved to the anchor, then the nested potential archetype
3675+
// we found is the resolved potential archetype. Return it directly,
3676+
// so it doesn't need to be resolved again.
3677+
if (basePA == resolvedBase.getPotentialArchetypeIfKnown())
3678+
return ResolvedType(nestedPA);
3679+
3680+
// Compute the resolved dependent type to return.
3681+
Type resolvedBaseType = resolvedBase.getDependentType(*this);
3682+
Type resolvedMemberType =
3683+
DependentMemberType::get(resolvedBaseType, assocType);
3684+
3685+
return ResolvedType(resolvedMemberType,
3686+
nestedPA->getOrCreateEquivalenceClass(*this));
37193687
} else {
3720-
auto *typeAlias =
3688+
auto *concreteDecl =
37213689
baseEquivClass->lookupNestedType(*this, depMemTy->getName());
37223690

3723-
if (!typeAlias)
3691+
if (!concreteDecl)
37243692
return ResolvedType::forUnresolved(baseEquivClass);
37253693

3726-
auto type = substituteConcreteType(*this, basePA, typeAlias);
3727-
return maybeResolveEquivalenceClass(type, resolutionKind,
3728-
wantExactPotentialArchetype);
3729-
}
3694+
Type parentType;
3695+
auto *proto = concreteDecl->getDeclContext()->getSelfProtocolDecl();
3696+
if (!proto) {
3697+
parentType = (baseEquivClass->concreteType
3698+
? baseEquivClass->concreteType
3699+
: baseEquivClass->superclass);
3700+
} else {
3701+
if (baseEquivClass->concreteType &&
3702+
lookupConformance(type->getCanonicalType(),
3703+
baseEquivClass->concreteType,
3704+
proto)) {
3705+
parentType = baseEquivClass->concreteType;
3706+
} else if (baseEquivClass->superclass &&
3707+
lookupConformance(type->getCanonicalType(),
3708+
baseEquivClass->superclass,
3709+
proto)) {
3710+
parentType = baseEquivClass->superclass;
3711+
} else {
3712+
parentType = basePA->getDependentType(getGenericParams());
3713+
}
3714+
}
37303715

3731-
auto nestedPA =
3732-
basePA->updateNestedTypeForConformance(*this, nestedTypeDecl,
3733-
resolutionKind);
3734-
if (!nestedPA)
3735-
return ResolvedType::forUnresolved(baseEquivClass);
3736-
3737-
// If base resolved to the anchor, then the nested potential archetype
3738-
// we found is the resolved potential archetype. Return it directly,
3739-
// so it doesn't need to be resolved again.
3740-
if (basePA == resolvedBase.getPotentialArchetypeIfKnown())
3741-
return ResolvedType(nestedPA);
3742-
3743-
// Compute the resolved dependent type to return.
3744-
Type resolvedBaseType = resolvedBase.getDependentType(*this);
3745-
Type resolvedMemberType;
3746-
if (auto assocType = dyn_cast<AssociatedTypeDecl>(nestedTypeDecl)) {
3747-
resolvedMemberType =
3748-
DependentMemberType::get(resolvedBaseType, assocType);
3749-
} else {
3750-
// Note: strange case that might not even really be dependent.
3751-
resolvedMemberType =
3752-
DependentMemberType::get(resolvedBaseType, depMemTy->getName());
3716+
auto concreteType = substituteConcreteType(parentType, concreteDecl);
3717+
return maybeResolveEquivalenceClass(concreteType, resolutionKind,
3718+
wantExactPotentialArchetype);
37533719
}
3754-
3755-
return ResolvedType(resolvedMemberType,
3756-
nestedPA->getOrCreateEquivalenceClass(*this));
37573720
}
37583721

37593722
// If it's not a type parameter, it won't directly resolve to one.
@@ -5556,7 +5519,8 @@ GenericSignatureBuilder::finalize(SourceLoc loc,
55565519
// Don't allow a generic parameter to be equivalent to a concrete type,
55575520
// because then we don't actually have a parameter.
55585521
auto equivClass = rep->getOrCreateEquivalenceClass(*this);
5559-
if (equivClass->concreteType) {
5522+
if (equivClass->concreteType &&
5523+
!equivClass->concreteType->is<ErrorType>()) {
55605524
if (auto constraint = equivClass->findAnyConcreteConstraintAsWritten()){
55615525
Impl->HadAnyError = true;
55625526

test/AutoDiff/compiler_crashers/sr12744-unhandled-pullback-indirect-result.swift renamed to test/AutoDiff/compiler_crashers_fixed/sr12744-unhandled-pullback-indirect-result.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// RUN: not --crash %target-swift-frontend -emit-sil -verify %s
2-
// REQUIRES: asserts
1+
// RUN: %target-swift-frontend -emit-sil -verify %s
32

43
// SR-12744: Pullback generation crash for unhandled indirect result.
54
// May be due to inconsistent derivative function type calculation logic in

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
@@ -49,7 +49,7 @@ public struct S<A: P> where A.T == S<A> { // expected-error {{circular reference
4949
// expected-note@-3 {{while resolving type 'S<A>'}}
5050
func f(a: A.T) {
5151
g(a: id(t: a))
52-
// expected-error@-1 {{cannot convert value of type 'A.T' to expected argument type 'S<A>'}}
52+
// expected-error@-1 {{type of expression is ambiguous without more context}}
5353
_ = A.T.self
5454
}
5555

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)