Skip to content

Commit 0103041

Browse files
committed
[ConstraintSystem] Tidy up restriction handling in contextual failures
Delay "fixing" contextual conversion failures until restriction is applied this helps to tidy up logic for superclass and existential conversions. Too bad we have to "fix" in `simplifyRestrictedConstraintImpl` now but we can't really do much about that because diagnostics need both top-level types to be useful.
1 parent 9a05827 commit 0103041

File tree

3 files changed

+85
-29
lines changed

3 files changed

+85
-29
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 84 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,8 +2077,11 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
20772077
// will also fail (because type can't satisfy it), and it's
20782078
// more interesting for diagnostics.
20792079
auto req = last->getAs<LocatorPathElt::AnyRequirement>();
2080-
if (type1->isHole() || (req &&
2081-
req->getRequirementKind() == RequirementKind::Superclass))
2080+
if (!req)
2081+
return getTypeMatchFailure(locator);
2082+
2083+
if (type1->isHole() ||
2084+
req->getRequirementKind() == RequirementKind::Superclass)
20822085
return getTypeMatchSuccess();
20832086

20842087
auto *fix = fixRequirementFailure(*this, type1, type2, locator);
@@ -2171,6 +2174,11 @@ ConstraintSystem::matchExistentialTypes(Type type1, Type type2,
21712174
if (last->is<LocatorPathElt::FunctionResult>())
21722175
return getTypeMatchFailure(locator);
21732176

2177+
// If instance types didn't line up correctly, let's produce a
2178+
// diagnostic which mentions them together with their metatypes.
2179+
if (last->is<LocatorPathElt::InstanceType>())
2180+
return getTypeMatchFailure(locator);
2181+
21742182
} else { // There are no elements in the path
21752183
auto *anchor = locator.getAnchor();
21762184
if (!(anchor &&
@@ -2814,6 +2822,14 @@ bool ConstraintSystem::repairFailures(
28142822
return false;
28152823

28162824
if (auto *coercion = dyn_cast<CoerceExpr>(anchor)) {
2825+
// Coercion from T.Type to T.Protocol.
2826+
if (hasConversionOrRestriction(
2827+
ConversionRestrictionKind::MetatypeToExistentialMetatype))
2828+
return false;
2829+
2830+
if (hasConversionOrRestriction(ConversionRestrictionKind::Superclass))
2831+
return false;
2832+
28172833
// Let's check whether the sub-expression is an optional type which
28182834
// is possible to unwrap (either by force or `??`) to satisfy the cast,
28192835
// otherwise we'd have to fallback to force downcast.
@@ -2839,10 +2855,11 @@ bool ConstraintSystem::repairFailures(
28392855

28402856
if (hasConversionOrRestriction(ConversionRestrictionKind::Existential))
28412857
return false;
2842-
2858+
28432859
auto *fix = ContextualMismatch::create(*this, lhs, rhs,
28442860
getConstraintLocator(locator));
28452861
conversionsOrFixes.push_back(fix);
2862+
return true;
28462863
}
28472864

28482865
// This could be:
@@ -3486,15 +3503,17 @@ bool ConstraintSystem::repairFailures(
34863503
// If there is a deep equality, superclass restriction
34873504
// already recorded, let's not add bother ignoring
34883505
// contextual type, because actual fix is going to
3489-
// be perform once restriction is applied.
3490-
if (llvm::any_of(conversionsOrFixes,
3491-
[](const RestrictionOrFix &entry) -> bool {
3492-
return entry.IsRestriction &&
3493-
(entry.getRestriction() ==
3494-
ConversionRestrictionKind::Superclass ||
3495-
entry.getRestriction() ==
3496-
ConversionRestrictionKind::DeepEquality);
3497-
}))
3506+
// be performed once restriction is applied.
3507+
if (hasConversionOrRestriction(ConversionRestrictionKind::Superclass))
3508+
break;
3509+
3510+
if (hasConversionOrRestriction(
3511+
ConversionRestrictionKind::MetatypeToExistentialMetatype))
3512+
break;
3513+
3514+
if (hasConversionOrRestriction(ConversionRestrictionKind::DeepEquality) &&
3515+
!hasConversionOrRestriction(
3516+
ConversionRestrictionKind::OptionalToOptional))
34983517
break;
34993518

35003519
conversionsOrFixes.push_back(IgnoreContextualType::create(
@@ -8232,15 +8251,42 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
82328251
return recordFix(fix) ? SolutionKind::Error : SolutionKind::Solved;
82338252
};
82348253

8254+
auto fixContextualFailure = [&](Type fromType, Type toType,
8255+
ConstraintLocatorBuilder locator) -> bool {
8256+
auto *loc = getConstraintLocator(locator);
8257+
if (loc->isForAssignment() || loc->isForCoercion() ||
8258+
loc->isForContextualType()) {
8259+
if (restriction == ConversionRestrictionKind::Superclass) {
8260+
if (auto *fix =
8261+
CoerceToCheckedCast::attempt(*this, fromType, toType, loc))
8262+
return !recordFix(fix);
8263+
}
8264+
8265+
auto *fix = ContextualMismatch::create(*this, fromType, toType, loc);
8266+
return !recordFix(fix);
8267+
}
8268+
8269+
return false;
8270+
};
8271+
82358272
switch (restriction) {
82368273
// for $< in { <, <c, <oc }:
82378274
// T_i $< U_i ===> (T_i...) $< (U_i...)
82388275
case ConversionRestrictionKind::DeepEquality:
82398276
return matchDeepEqualityTypes(type1, type2, locator);
82408277

8241-
case ConversionRestrictionKind::Superclass:
8278+
case ConversionRestrictionKind::Superclass: {
82428279
addContextualScore();
8243-
return matchSuperclassTypes(type1, type2, subflags, locator);
8280+
8281+
auto result = matchSuperclassTypes(type1, type2, subflags, locator);
8282+
8283+
if (!(shouldAttemptFixes() && result.isFailure()))
8284+
return result;
8285+
8286+
return fixContextualFailure(type1, type2, locator)
8287+
? getTypeMatchSuccess()
8288+
: getTypeMatchFailure(locator);
8289+
}
82448290

82458291
// for $< in { <, <c, <oc }:
82468292
// T $< U, U : P_i ===> T $< protocol<P_i...>
@@ -8255,15 +8301,23 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
82558301
// P : Q ===> T.Protocol $< Q.Type
82568302
// for P protocol, Q protocol,
82578303
// P $< Q ===> P.Type $< Q.Type
8258-
case ConversionRestrictionKind::MetatypeToExistentialMetatype:
8304+
case ConversionRestrictionKind::MetatypeToExistentialMetatype: {
82598305
addContextualScore();
82608306

8261-
return matchExistentialTypes(
8262-
type1->castTo<MetatypeType>()->getInstanceType(),
8263-
type2->castTo<ExistentialMetatypeType>()->getInstanceType(),
8264-
ConstraintKind::ConformsTo,
8265-
subflags,
8266-
locator.withPathElement(ConstraintLocator::InstanceType));
8307+
auto instanceTy1 = type1->getMetatypeInstanceType();
8308+
auto instanceTy2 = type2->getMetatypeInstanceType();
8309+
8310+
auto result = matchExistentialTypes(
8311+
instanceTy1, instanceTy2, ConstraintKind::ConformsTo, subflags,
8312+
locator.withPathElement(ConstraintLocator::InstanceType));
8313+
8314+
if (!(shouldAttemptFixes() && result.isFailure()))
8315+
return result;
8316+
8317+
return fixContextualFailure(type1, type2, locator)
8318+
? getTypeMatchSuccess()
8319+
: getTypeMatchFailure(locator);
8320+
}
82678321

82688322
// for $< in { <, <c, <oc }:
82698323
// for P protocol, C class, D class,
@@ -8278,13 +8332,16 @@ ConstraintSystem::simplifyRestrictedConstraintImpl(
82788332
if (!superclass1)
82798333
return SolutionKind::Error;
82808334

8281-
return matchTypes(
8282-
superclass1,
8283-
instance2,
8284-
ConstraintKind::Subtype,
8285-
subflags,
8286-
locator.withPathElement(ConstraintLocator::InstanceType));
8335+
auto result =
8336+
matchTypes(superclass1, instance2, ConstraintKind::Subtype, subflags,
8337+
locator.withPathElement(ConstraintLocator::InstanceType));
8338+
8339+
if (!(shouldAttemptFixes() && result.isFailure()))
8340+
return result;
82878341

8342+
return fixContextualFailure(type1, type2, locator)
8343+
? getTypeMatchSuccess()
8344+
: getTypeMatchFailure(locator);
82888345
}
82898346
// for $< in { <, <c, <oc }:
82908347
// T $< U ===> T $< U?

test/Parse/try.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,6 @@ let _: String = try? optProducer?.produceInt() // expected-error {{cannot conver
243243
let _: Int?? = try? optProducer?.produceInt() // good
244244

245245
let _: Int? = try? optProducer?.produceIntNoThrowing() // expected-error {{cannot convert value of type 'Int??' to specified type 'Int?'}}
246-
// expected-warning@-1 {{no calls to throwing functions occur within 'try' expression}}
247246
let _: Int?? = try? optProducer?.produceIntNoThrowing() // expected-warning {{no calls to throwing functions occur within 'try' expression}}
248247

249248
let _: Int? = (try? optProducer?.produceAny()) as? Int // good

test/type/subclass_composition.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func basicSubtyping(
103103
let _: P3 = baseAndP2 // expected-error {{value of type 'Base<Int> & P2' does not conform to specified type 'P3'}}
104104
let _: Derived = baseAndP1 // expected-error {{cannot convert value of type 'Base<Int> & P1' to specified type 'Derived'}}
105105
let _: Derived = baseAndP2 // expected-error {{cannot convert value of type 'Base<Int> & P2' to specified type 'Derived'}}
106-
let _: Derived & P2 = baseAndP2 // expected-error {{value of type 'Base<Int> & P2' does not conform to specified type 'Derived & P2'}}
106+
let _: Derived & P2 = baseAndP2 // expected-error {{cannot convert value of type 'Base<Int> & P2' to specified type 'Derived'}}
107107

108108
let _ = Unrelated() as Derived & P2 // expected-error {{value of type 'Unrelated' does not conform to 'Derived & P2' in coercion}}
109109
let _ = Unrelated() as? Derived & P2 // expected-warning {{always fails}}

0 commit comments

Comments
 (0)