mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Sema: Relax primary associated type matching in matchExistentialTypes()
Recently I found a soundness hole here, where we would allow conversion between `any P<T>` and `any Q<T>` even if P and Q have different primary associated types. However, the fix was too strict, because we still want to allow the conversion when the associated types have the same name. Fixes rdar://141968103.
This commit is contained in:
@@ -4221,7 +4221,7 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
|
||||
|
||||
// Finally, check parameterized protocol requirements.
|
||||
if (!layout.getParameterizedProtocols().empty()) {
|
||||
SmallVector<std::pair<AssociatedTypeDecl *, Type>, 4> fromReqs;
|
||||
SmallVector<std::pair<Identifier, Type>, 4> fromReqs;
|
||||
|
||||
if (type1->isExistentialType()) {
|
||||
auto fromLayout = type1->getExistentialLayout();
|
||||
@@ -4232,8 +4232,7 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
|
||||
|
||||
for (unsigned i : indices(argTypes)) {
|
||||
auto argType = argTypes[i];
|
||||
auto *assocType = assocTypes[i]->getAssociatedTypeAnchor();
|
||||
fromReqs.push_back(std::make_pair(assocType, argType));
|
||||
fromReqs.push_back(std::make_pair(assocTypes[i]->getName(), argType));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4248,10 +4247,9 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
|
||||
|
||||
for (unsigned i : indices(argTypes)) {
|
||||
auto argType = argTypes[i];
|
||||
auto *assocType = assocTypes[i]->getAssociatedTypeAnchor();
|
||||
bool found = false;
|
||||
for (auto fromReq : fromReqs) {
|
||||
if (fromReq.first == assocType) {
|
||||
if (fromReq.first == assocTypes[i]->getName()) {
|
||||
// FIXME: Extend the locator path to point to the argument
|
||||
// inducing the requirement.
|
||||
auto result = matchTypes(fromReq.second, argType,
|
||||
|
||||
@@ -31,4 +31,25 @@ var q: any Q<String> = p // expected-error {{cannot convert value of type 'any P
|
||||
// Previously we accepted the above conversion, and then getB()
|
||||
// would return something that was dynamically Array<String>
|
||||
// and not String as expected.
|
||||
print(q.getB())
|
||||
// print(q.getB())
|
||||
|
||||
|
||||
// However, this is OK -- the two A's have the same name, so by the
|
||||
// semantics of the generics system they must be equivalent as type
|
||||
// parameters.
|
||||
|
||||
protocol P1<A> {
|
||||
associatedtype A
|
||||
}
|
||||
|
||||
protocol P2<A> {
|
||||
associatedtype A
|
||||
}
|
||||
|
||||
protocol P3<A>: P1, P2 {
|
||||
associatedtype A
|
||||
}
|
||||
|
||||
func f<T>(_ value: any P3<T>) -> (any P1<T>, any P2<T>) {
|
||||
return (value, value)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user