Skip to content

Commit 12698ba

Browse files
authored
Merge pull request #60484 from slavapestov/parameterized-protocol-mismatch-crash
Sema: Fix deep equality matching for parameterized protocol types
2 parents 9eb6dd3 + 11eb118 commit 12698ba

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
@@ -3286,7 +3286,41 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
32863286
}
32873287

32883288
// Handle existential types.
3289-
if (type1->isExistentialType() && type2->isExistentialType()) {
3289+
if (auto *existential1 = type1->getAs<ExistentialType>()) {
3290+
auto existential2 = type2->castTo<ExistentialType>();
3291+
3292+
auto result = matchTypes(existential1->getConstraintType(),
3293+
existential2->getConstraintType(),
3294+
ConstraintKind::Bind, subflags,
3295+
locator.withPathElement(
3296+
ConstraintLocator::ExistentialConstraintType));
3297+
3298+
if (result.isFailure())
3299+
return result;
3300+
3301+
return getTypeMatchSuccess();
3302+
}
3303+
3304+
// Arguments of parameterized protocol types have to match on the nose.
3305+
if (auto ppt1 = type1->getAs<ParameterizedProtocolType>()) {
3306+
auto ppt2 = type2->castTo<ParameterizedProtocolType>();
3307+
3308+
auto result = matchTypes(ppt1->getBaseType(),
3309+
ppt2->getBaseType(),
3310+
ConstraintKind::Bind, subflags,
3311+
locator.withPathElement(
3312+
ConstraintLocator::ParentType));
3313+
3314+
if (result.isFailure())
3315+
return result;
3316+
3317+
return matchDeepTypeArguments(*this, subflags,
3318+
ppt1->getArgs(),
3319+
ppt2->getArgs(),
3320+
locator);
3321+
}
3322+
3323+
if (type1->isExistentialType()) {
32903324
auto layout1 = type1->getExistentialLayout();
32913325
auto layout2 = type2->getExistentialLayout();
32923326

@@ -3309,24 +3343,16 @@ ConstraintSystem::matchDeepEqualityTypes(Type type1, Type type2,
33093343
if (!layout1.explicitSuperclass || !layout2.explicitSuperclass)
33103344
return getTypeMatchFailure(locator);
33113345

3346+
auto subLocator = locator.withPathElement(
3347+
ConstraintLocator::ProtocolCompositionSuperclassType);
33123348
auto result = matchTypes(layout1.explicitSuperclass,
33133349
layout2.explicitSuperclass,
33143350
ConstraintKind::Bind, subflags,
3315-
locator.withPathElement(
3316-
ConstraintLocator::ExistentialSuperclassType));
3351+
subLocator);
33173352
if (result.isFailure())
33183353
return result;
33193354
}
33203355

3321-
// Arguments of parameterized protocol types have to match on the nose.
3322-
if (auto ppt1 = type1->getAs<ParameterizedProtocolType>()) {
3323-
auto ppt2 = type2->castTo<ParameterizedProtocolType>();
3324-
return matchDeepTypeArguments(*this, subflags,
3325-
ppt1->getArgs(),
3326-
ppt2->getArgs(),
3327-
locator);
3328-
}
3329-
33303356
return getTypeMatchSuccess();
33313357
}
33323358

@@ -6367,7 +6393,8 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
63676393
// If we are matching types for equality, we might still have
63686394
// type variables inside the protocol composition's superclass
63696395
// constraint.
6370-
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
6396+
if (desugar1->getKind() == desugar2->getKind())
6397+
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
63716398
break;
63726399

63736400
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:
@@ -247,8 +248,12 @@ void LocatorPathElt::dump(raw_ostream &out) const {
247248
out << "parent type";
248249
break;
249250

250-
case ConstraintLocator::ExistentialSuperclassType:
251-
out << "existential superclass type";
251+
case ConstraintLocator::ExistentialConstraintType:
252+
out << "existential constraint type";
253+
break;
254+
255+
case ConstraintLocator::ProtocolCompositionSuperclassType:
256+
out << "protocol composition superclass type";
252257
break;
253258

254259
case ConstraintLocator::LValueConversion:

lib/Sema/ConstraintSystem.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5227,7 +5227,8 @@ void constraints::simplifyLocator(ASTNode &anchor,
52275227
case ConstraintLocator::PlaceholderType:
52285228
case ConstraintLocator::SequenceElementType:
52295229
case ConstraintLocator::ConstructorMemberType:
5230-
case ConstraintLocator::ExistentialSuperclassType:
5230+
case ConstraintLocator::ExistentialConstraintType:
5231+
case ConstraintLocator::ProtocolCompositionSuperclassType:
52315232
break;
52325233

52335234
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)