Skip to content

Commit 3a9211a

Browse files
authored
Merge pull request #60516 from slavapestov/parameterized-protocol-mismatch-crash-5.7
Sema: Fix deep equality matching for parameterized protocol types [5.7]
2 parents b871292 + 77c8322 commit 3a9211a

File tree

5 files changed

+103
-19
lines changed

5 files changed

+103
-19
lines changed

include/swift/Sema/ConstraintLocatorPathElts.def

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,11 @@ CUSTOM_LOCATOR_PATH_ELT(ContextualType)
7272
/// A result of an expression involving dynamic lookup.
7373
SIMPLE_LOCATOR_PATH_ELT(DynamicLookupResult)
7474

75-
/// The superclass of a protocol existential type.
76-
SIMPLE_LOCATOR_PATH_ELT(ExistentialSuperclassType)
75+
/// The superclass of a protocol composition type.
76+
SIMPLE_LOCATOR_PATH_ELT(ProtocolCompositionSuperclassType)
77+
78+
/// The constraint of an existential type.
79+
SIMPLE_LOCATOR_PATH_ELT(ExistentialConstraintType)
7780

7881
/// The argument type of a function.
7982
SIMPLE_LOCATOR_PATH_ELT(FunctionArgument)

lib/Sema/CSSimplify.cpp

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3328,7 +3328,41 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
33283328
}
33293329

33303330
// Handle existential types.
3331-
if (type1->isExistentialType() && type2->isExistentialType()) {
3331+
if (auto *existential1 = type1->getAs<ExistentialType>()) {
3332+
auto existential2 = type2->castTo<ExistentialType>();
3333+
3334+
auto result = matchTypes(existential1->getConstraintType(),
3335+
existential2->getConstraintType(),
3336+
ConstraintKind::Bind, subflags,
3337+
locator.withPathElement(
3338+
ConstraintLocator::ExistentialConstraintType));
3339+
3340+
if (result.isFailure())
3341+
return result;
3342+
3343+
return getTypeMatchSuccess();
3344+
}
3345+
3346+
// Arguments of parameterized protocol types have to match on the nose.
3347+
if (auto ppt1 = type1->getAs<ParameterizedProtocolType>()) {
3348+
auto ppt2 = type2->castTo<ParameterizedProtocolType>();
3349+
3350+
auto result = matchTypes(ppt1->getBaseType(),
3351+
ppt2->getBaseType(),
3352+
ConstraintKind::Bind, subflags,
3353+
locator.withPathElement(
3354+
ConstraintLocator::ParentType));
3355+
3356+
if (result.isFailure())
3357+
return result;
3358+
3359+
return matchDeepTypeArguments(*this, subflags,
3360+
ppt1->getArgs(),
3361+
ppt2->getArgs(),
3362+
locator);
3363+
}
3364+
3365+
if (type1->isExistentialType()) {
33323366
auto layout1 = type1->getExistentialLayout();
33333367
auto layout2 = type2->getExistentialLayout();
33343368

@@ -3351,24 +3385,16 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
33513385
if (!layout1.explicitSuperclass || !layout2.explicitSuperclass)
33523386
return getTypeMatchFailure(locator);
33533387

3388+
auto subLocator = locator.withPathElement(
3389+
ConstraintLocator::ProtocolCompositionSuperclassType);
33543390
auto result = matchTypes(layout1.explicitSuperclass,
33553391
layout2.explicitSuperclass,
33563392
ConstraintKind::Bind, subflags,
3357-
locator.withPathElement(
3358-
ConstraintLocator::ExistentialSuperclassType));
3393+
subLocator);
33593394
if (result.isFailure())
33603395
return result;
33613396
}
33623397

3363-
// Arguments of parameterized protocol types have to match on the nose.
3364-
if (auto ppt1 = type1->getAs<ParameterizedProtocolType>()) {
3365-
auto ppt2 = type2->castTo<ParameterizedProtocolType>();
3366-
return matchDeepTypeArguments(*this, subflags,
3367-
ppt1->getArgs(),
3368-
ppt2->getArgs(),
3369-
locator);
3370-
}
3371-
33723398
return getTypeMatchSuccess();
33733399
}
33743400

@@ -6423,7 +6449,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
64236449
// If we are matching types for equality, we might still have
64246450
// type variables inside the protocol composition's superclass
64256451
// constraint.
6426-
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
6452+
if (desugar1->getKind() == desugar2->getKind())
6453+
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
64276454
break;
64286455

64296456
default:

lib/Sema/ConstraintLocator.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ unsigned LocatorPathElt::getNewSummaryFlags() const {
5656
case ConstraintLocator::MemberRefBase:
5757
case ConstraintLocator::UnresolvedMember:
5858
case ConstraintLocator::ParentType:
59-
case ConstraintLocator::ExistentialSuperclassType:
59+
case ConstraintLocator::ExistentialConstraintType:
60+
case ConstraintLocator::ProtocolCompositionSuperclassType:
6061
case ConstraintLocator::LValueConversion:
6162
case ConstraintLocator::DynamicType:
6263
case ConstraintLocator::SubscriptMember:
@@ -391,8 +392,12 @@ void ConstraintLocator::dump(SourceManager *sm, raw_ostream &out) const {
391392
out << "parent type";
392393
break;
393394

394-
case ExistentialSuperclassType:
395-
out << "existential superclass type";
395+
case ProtocolCompositionSuperclassType:
396+
out << "protocol composition superclass type";
397+
break;
398+
399+
case ExistentialConstraintType:
400+
out << "existential constraint type";
396401
break;
397402

398403
case LValueConversion:

lib/Sema/ConstraintSystem.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5191,7 +5191,8 @@ void constraints::simplifyLocator(ASTNode &anchor,
51915191
case ConstraintLocator::PlaceholderType:
51925192
case ConstraintLocator::SequenceElementType:
51935193
case ConstraintLocator::ConstructorMemberType:
5194-
case ConstraintLocator::ExistentialSuperclassType:
5194+
case ConstraintLocator::ExistentialConstraintType:
5195+
case ConstraintLocator::ProtocolCompositionSuperclassType:
51955196
break;
51965197

51975198
case ConstraintLocator::GenericArgument:
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: %target-typecheck-verify-swift -disable-availability-checking
2+
3+
protocol P<A> {
4+
associatedtype A
5+
}
6+
7+
func f1(x: any P) -> any P<Int> {
8+
// FIXME: Bad diagnostic
9+
return x // expected-error {{type of expression is ambiguous without more context}}
10+
}
11+
12+
func f2(x: any P<Int>) -> any P {
13+
return x // okay
14+
}
15+
16+
func f3(x: any P<Int>) -> any P<String> {
17+
// FIXME: Misleading diagnostic
18+
return x // expected-error {{cannot convert return expression of type 'String' to return type 'Int'}}
19+
}
20+
21+
struct G<T> {}
22+
// expected-note@-1 {{arguments to generic parameter 'T' ('any P<Int>' and 'any P') are expected to be equal}}
23+
// expected-note@-2 {{arguments to generic parameter 'T' ('any P' and 'any P<Int>') are expected to be equal}}
24+
// expected-note@-3 {{arguments to generic parameter 'T' ('any P<Int>' and 'any P<String>') are expected to be equal}}
25+
26+
func g1(x: G<any P>) -> G<any P<Int>> {
27+
return x // expected-error {{cannot convert return expression of type 'G<any P>' to return type 'G<any P<Int>>'}}
28+
}
29+
30+
func g2(x: G<any P<Int>>) -> G<any P> {
31+
return x // expected-error {{cannot convert return expression of type 'G<any P<Int>>' to return type 'G<any P>'}}
32+
}
33+
34+
func g3(x: G<any P<Int>>) -> G<any P<String>> {
35+
return x // expected-error {{cannot convert return expression of type 'G<any P<Int>>' to return type 'G<any P<String>>'}}
36+
}
37+
38+
func h1(x: (any P)?) -> (any P<Int>)? {
39+
return x // expected-error {{cannot convert return expression of type '(any P)?' to return type '(any P<Int>)?'}}
40+
}
41+
42+
func h2(x: (any P<Int>)?) -> (any P)? {
43+
return x // okay
44+
}
45+
46+
func h3(x: (any P<Int>)?) -> (any P<String>)? {
47+
return x // expected-error {{cannot convert return expression of type '(any P<Int>)?' to return type '(any P<String>)?'}}
48+
}

0 commit comments

Comments
 (0)