Skip to content

Commit b036889

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. (cherry picked from commit 5ed639f)
1 parent 0acd02d commit b036889

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
@@ -6981,17 +6981,24 @@ void GenericSignatureBuilder::checkSameTypeConstraints(
69816981
void GenericSignatureBuilder::checkConcreteTypeConstraints(
69826982
TypeArrayView<GenericTypeParamType> genericParams,
69836983
EquivalenceClass *equivClass) {
6984+
// Resolve any thus-far-unresolved dependent types.
6985+
Type resolvedConcreteType =
6986+
resolveDependentMemberTypes(*this, equivClass->concreteType);
6987+
69846988
checkConstraintList<Type>(
69856989
genericParams, equivClass->concreteTypeConstraints,
69866990
[&](const ConcreteConstraint &constraint) {
6987-
return constraint.value->isEqual(equivClass->concreteType);
6991+
if (constraint.value->isEqual(resolvedConcreteType))
6992+
return true;
6993+
6994+
auto resolvedType =
6995+
resolveDependentMemberTypes(*this, constraint.value);
6996+
return resolvedType->isEqual(resolvedConcreteType);
69886997
},
69896998
[&](const Constraint<Type> &constraint) {
69906999
Type concreteType = constraint.value;
69917000

69927001
// If the concrete type is equivalent, the constraint is redundant.
6993-
// FIXME: Should check this constraint after substituting in the
6994-
// archetype anchors for each dependent type.
69957002
if (concreteType->isEqual(equivClass->concreteType))
69967003
return ConstraintRelation::Redundant;
69977004

@@ -7006,33 +7013,28 @@ void GenericSignatureBuilder::checkConcreteTypeConstraints(
70067013
diag::redundant_same_type_to_concrete,
70077014
diag::same_type_redundancy_here);
70087015

7009-
// Resolve any thus-far-unresolved dependent types.
7010-
equivClass->concreteType =
7011-
resolveDependentMemberTypes(*this, equivClass->concreteType);
7016+
equivClass->concreteType = resolvedConcreteType;
70127017
}
70137018

70147019
void GenericSignatureBuilder::checkSuperclassConstraints(
70157020
TypeArrayView<GenericTypeParamType> genericParams,
70167021
EquivalenceClass *equivClass) {
70177022
assert(equivClass->superclass && "No superclass constraint?");
70187023

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

70317028
auto representativeConstraint =
70327029
checkConstraintList<Type>(
70337030
genericParams, equivClass->superclassConstraints,
70347031
[&](const ConcreteConstraint &constraint) {
7035-
return constraint.value->isEqual(equivClass->superclass);
7032+
if (constraint.value->isEqual(resolvedSuperclass))
7033+
return true;
7034+
7035+
Type resolvedType =
7036+
resolveDependentMemberTypes(*this, constraint.value);
7037+
return resolvedType->isEqual(equivClass->superclass);
70367038
},
70377039
[&](const Constraint<Type> &constraint) {
70387040
Type superclass = constraint.value;
@@ -7049,15 +7051,16 @@ void GenericSignatureBuilder::checkSuperclassConstraints(
70497051
diag::superclass_redundancy_here);
70507052

70517053
// Resolve any this-far-unresolved dependent types.
7052-
equivClass->superclass =
7053-
resolveDependentMemberTypes(*this, equivClass->superclass);
7054+
equivClass->superclass = resolvedSuperclass;
70547055

70557056
// If we have a concrete type, check it.
70567057
// FIXME: Substitute into the concrete type.
70577058
if (equivClass->concreteType) {
7059+
Type resolvedConcreteType =
7060+
resolveDependentMemberTypes(*this, equivClass->concreteType);
70587061
auto existing = equivClass->findAnyConcreteConstraintAsWritten();
70597062
// Make sure the concrete type fulfills the superclass requirement.
7060-
if (!equivClass->superclass->isExactSuperclassOf(equivClass->concreteType)){
7063+
if (!equivClass->superclass->isExactSuperclassOf(resolvedConcreteType)){
70617064
Impl->HadAnyError = true;
70627065
if (existing) {
70637066
Diags.diagnose(existing->source->getLoc(), diag::type_does_not_inherit,
@@ -7077,7 +7080,7 @@ void GenericSignatureBuilder::checkSuperclassConstraints(
70777080
diag::type_does_not_inherit,
70787081
representativeConstraint.getSubjectDependentType(
70797082
genericParams),
7080-
equivClass->concreteType, equivClass->superclass);
7083+
resolvedConcreteType, equivClass->superclass);
70817084
}
70827085
} else if (representativeConstraint.source->shouldDiagnoseRedundancy(true)
70837086
&& 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)