Skip to content

Commit 5ed639f

Browse files
committed
[GSB] Canonicalize types when checking concrete and superclass constraints.
Concrete and superclass constraints may be written involving type parameters that are later resolved to concrete types. Perform the substitution to ensure that type equality within constraint checking accounts for other same-type constraints. Fixes assertion in rdar://problem/40428709.
1 parent b0aeae4 commit 5ed639f

File tree

2 files changed

+41
-22
lines changed

2 files changed

+41
-22
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6988,17 +6988,24 @@ void GenericSignatureBuilder::checkSameTypeConstraints(
69886988
void GenericSignatureBuilder::checkConcreteTypeConstraints(
69896989
TypeArrayView<GenericTypeParamType> genericParams,
69906990
EquivalenceClass *equivClass) {
6991+
// Resolve any thus-far-unresolved dependent types.
6992+
Type resolvedConcreteType =
6993+
resolveDependentMemberTypes(*this, equivClass->concreteType);
6994+
69916995
checkConstraintList<Type>(
69926996
genericParams, equivClass->concreteTypeConstraints,
69936997
[&](const ConcreteConstraint &constraint) {
6994-
return constraint.value->isEqual(equivClass->concreteType);
6998+
if (constraint.value->isEqual(resolvedConcreteType))
6999+
return true;
7000+
7001+
auto resolvedType =
7002+
resolveDependentMemberTypes(*this, constraint.value);
7003+
return resolvedType->isEqual(resolvedConcreteType);
69957004
},
69967005
[&](const Constraint<Type> &constraint) {
69977006
Type concreteType = constraint.value;
69987007

69997008
// If the concrete type is equivalent, the constraint is redundant.
7000-
// FIXME: Should check this constraint after substituting in the
7001-
// archetype anchors for each dependent type.
70027009
if (concreteType->isEqual(equivClass->concreteType))
70037010
return ConstraintRelation::Redundant;
70047011

@@ -7013,33 +7020,28 @@ void GenericSignatureBuilder::checkConcreteTypeConstraints(
70137020
diag::redundant_same_type_to_concrete,
70147021
diag::same_type_redundancy_here);
70157022

7016-
// Resolve any thus-far-unresolved dependent types.
7017-
equivClass->concreteType =
7018-
resolveDependentMemberTypes(*this, equivClass->concreteType);
7023+
equivClass->concreteType = resolvedConcreteType;
70197024
}
70207025

70217026
void GenericSignatureBuilder::checkSuperclassConstraints(
70227027
TypeArrayView<GenericTypeParamType> genericParams,
70237028
EquivalenceClass *equivClass) {
70247029
assert(equivClass->superclass && "No superclass constraint?");
70257030

7026-
// FIXME: We should be substituting in the canonical type in context so
7027-
// we can resolve superclass requirements, e.g., if you had:
7028-
//
7029-
// class Foo<T>
7030-
// class Bar: Foo<Int>
7031-
//
7032-
// func foo<T, U where U: Bar, U: Foo<T>>(...) { ... }
7033-
//
7034-
// then the second `U: Foo<T>` constraint introduces a `T == Int`
7035-
// constraint, and we will need to perform that substitution for this final
7036-
// check.
7031+
// Resolve any this-far-unresolved dependent types.
7032+
Type resolvedSuperclass =
7033+
resolveDependentMemberTypes(*this, equivClass->superclass);
70377034

70387035
auto representativeConstraint =
70397036
checkConstraintList<Type>(
70407037
genericParams, equivClass->superclassConstraints,
70417038
[&](const ConcreteConstraint &constraint) {
7042-
return constraint.value->isEqual(equivClass->superclass);
7039+
if (constraint.value->isEqual(resolvedSuperclass))
7040+
return true;
7041+
7042+
Type resolvedType =
7043+
resolveDependentMemberTypes(*this, constraint.value);
7044+
return resolvedType->isEqual(equivClass->superclass);
70437045
},
70447046
[&](const Constraint<Type> &constraint) {
70457047
Type superclass = constraint.value;
@@ -7056,15 +7058,16 @@ void GenericSignatureBuilder::checkSuperclassConstraints(
70567058
diag::superclass_redundancy_here);
70577059

70587060
// Resolve any this-far-unresolved dependent types.
7059-
equivClass->superclass =
7060-
resolveDependentMemberTypes(*this, equivClass->superclass);
7061+
equivClass->superclass = resolvedSuperclass;
70617062

70627063
// If we have a concrete type, check it.
70637064
// FIXME: Substitute into the concrete type.
70647065
if (equivClass->concreteType) {
7066+
Type resolvedConcreteType =
7067+
resolveDependentMemberTypes(*this, equivClass->concreteType);
70657068
auto existing = equivClass->findAnyConcreteConstraintAsWritten();
70667069
// Make sure the concrete type fulfills the superclass requirement.
7067-
if (!equivClass->superclass->isExactSuperclassOf(equivClass->concreteType)){
7070+
if (!equivClass->superclass->isExactSuperclassOf(resolvedConcreteType)){
70687071
Impl->HadAnyError = true;
70697072
if (existing) {
70707073
Diags.diagnose(existing->source->getLoc(), diag::type_does_not_inherit,
@@ -7084,7 +7087,7 @@ void GenericSignatureBuilder::checkSuperclassConstraints(
70847087
diag::type_does_not_inherit,
70857088
representativeConstraint.getSubjectDependentType(
70867089
genericParams),
7087-
equivClass->concreteType, equivClass->superclass);
7090+
resolvedConcreteType, equivClass->superclass);
70887091
}
70897092
} else if (representativeConstraint.source->shouldDiagnoseRedundancy(true)
70907093
&& existing &&

test/Generics/same_type_constraints.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,3 +378,19 @@ typealias NotAnInt = Double
378378
extension X11 where NotAnInt == Int { }
379379
// expected-warning@-1{{neither type in same-type constraint ('NotAnInt' (aka 'Double') or 'Int') refers to a generic parameter or associated type}}
380380
// expected-error@-2{{generic signature requires types 'NotAnInt' (aka 'Double') and 'Int' to be the same}}
381+
382+
383+
struct X12<T> { }
384+
385+
protocol P12 {
386+
associatedtype A
387+
associatedtype B
388+
}
389+
390+
func testP12a<T: P12>(_: T) where T.A == X12<Int>, T.A == X12<T.B>, T.B == Int { }
391+
// expected-warning@-1{{redundant same-type constraint 'T.B' == 'Int'}}
392+
// expected-note@-2{{same-type constraint 'T.B' == 'Int' written here}}
393+
394+
func testP12b<T: P12>(_: T) where T.B == Int, T.A == X12<T.B>, X12<T.B> == T.A { }
395+
// expected-warning@-1{{redundant same-type constraint 'T.A' == 'X12<Int>'}}
396+
// expected-note@-2{{same-type constraint 'T.A' == 'X12<Int>' written here}}

0 commit comments

Comments
 (0)