Skip to content

Commit e0e13aa

Browse files
committed
[ConstraintSystem] Make ForceOptional fix a part of repairFailures
Instead of always attempting an optional unwrap fix if types differ in optionality, let's make it more targeted for each applicable locator and conversion. In addition adjust a couple of uses of `ForceOptional` fix to avoid recording the same fix multiple times and use appropriate `impact` instead.
1 parent 38a6cfa commit e0e13aa

File tree

1 file changed

+160
-80
lines changed

1 file changed

+160
-80
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 160 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -2552,6 +2552,103 @@ repairViaBridgingCast(ConstraintSystem &cs, Type fromType, Type toType,
25522552
return true;
25532553
}
25542554

2555+
static bool
2556+
repairViaOptionalUnwrap(ConstraintSystem &cs, Type fromType, Type toType,
2557+
ConstraintKind matchKind,
2558+
SmallVectorImpl<RestrictionOrFix> &conversionsOrFixes,
2559+
ConstraintLocatorBuilder locator) {
2560+
fromType = fromType->getWithoutSpecifierType();
2561+
2562+
if (!fromType->getOptionalObjectType() || toType->is<TypeVariableType>())
2563+
return false;
2564+
2565+
// If we have an optional type, try to force-unwrap it.
2566+
// FIXME: Should we also try '?'?
2567+
auto *anchor = locator.trySimplifyToExpr();
2568+
if (!anchor)
2569+
return false;
2570+
2571+
// `OptionalEvaluationExpr` doesn't add a new level of
2572+
// optionality but it could be hiding concrete types
2573+
// behind itself which we can use to better understand
2574+
// how many levels of optionality have to be unwrapped.
2575+
if (auto *OEE = dyn_cast<OptionalEvaluationExpr>(anchor)) {
2576+
auto type = cs.getType(OEE->getSubExpr());
2577+
// If the type of sub-expression is optional, type of the
2578+
// `OptionalEvaluationExpr` could be safely ignored because
2579+
// it doesn't add any type information.
2580+
if (type->getOptionalObjectType())
2581+
fromType = type;
2582+
2583+
// If this is a conversion from optional chain to some
2584+
// other type e.g. contextual type or a parameter type,
2585+
// let's use `Bind` to match object types because
2586+
// object type of the optinal chain is a type variable.
2587+
if (matchKind >= ConstraintKind::Conversion)
2588+
matchKind = ConstraintKind::Bind;
2589+
}
2590+
2591+
if (auto *DRE = dyn_cast<DeclRefExpr>(anchor)) {
2592+
if (DRE->getDecl()->isImplicit()) {
2593+
// The expression that provides the first type is implicit and never
2594+
// spelled out in source code, e.g. $match in an expression pattern.
2595+
// Thus we cannot force unwrap the first type
2596+
return false;
2597+
}
2598+
}
2599+
2600+
if (auto *optTryExpr = dyn_cast<OptionalTryExpr>(anchor)) {
2601+
auto subExprType = cs.getType(optTryExpr->getSubExpr());
2602+
const bool isSwift5OrGreater =
2603+
cs.getASTContext().LangOpts.isSwiftVersionAtLeast(5);
2604+
2605+
if (subExprType->getOptionalObjectType()) {
2606+
if (isSwift5OrGreater) {
2607+
// For 'try?' expressions, a ForceOptional fix converts 'try?'
2608+
// to 'try!'. If the sub-expression is optional, then a force-unwrap
2609+
// won't change anything in Swift 5+ because 'try?' already avoids
2610+
// adding an additional layer of Optional there.
2611+
return false;
2612+
}
2613+
} else {
2614+
// In cases when sub-expression isn't optional, 'try?'
2615+
// always adds one level of optinality regardless of
2616+
// language mode, so we can safely try to bind its
2617+
// object type to contextual type without risk of
2618+
// causing more optionality mismatches down the road.
2619+
matchKind = ConstraintKind::Bind;
2620+
}
2621+
}
2622+
2623+
auto getObjectTypeAndUnwraps = [](Type type) -> std::pair<Type, unsigned> {
2624+
SmallVector<Type, 2> optionals;
2625+
Type objType = type->lookThroughAllOptionalTypes(optionals);
2626+
return std::make_pair(objType, optionals.size());
2627+
};
2628+
2629+
Type fromObjectType, toObjectType;
2630+
unsigned fromUnwraps, toUnwraps;
2631+
2632+
std::tie(fromObjectType, fromUnwraps) = getObjectTypeAndUnwraps(fromType);
2633+
std::tie(toObjectType, toUnwraps) = getObjectTypeAndUnwraps(toType);
2634+
2635+
// If `from` is not less optional than `to`, force unwrap is
2636+
// not going to help here. In case of object type of `from`
2637+
// is a type variable, let's assume that it might be optional.
2638+
if (fromUnwraps <= toUnwraps && !fromObjectType->is<TypeVariableType>())
2639+
return false;
2640+
2641+
auto result =
2642+
cs.matchTypes(fromObjectType, toObjectType, matchKind,
2643+
ConstraintSystem::TypeMatchFlags::TMF_ApplyingFix, locator);
2644+
if (!result.isSuccess())
2645+
return false;
2646+
2647+
conversionsOrFixes.push_back(ForceOptional::create(
2648+
cs, fromType, toType, cs.getConstraintLocator(locator)));
2649+
return true;
2650+
}
2651+
25552652
/// Attempt to repair typing failures and record fixes if needed.
25562653
/// \return true if at least some of the failures has been repaired
25572654
/// successfully, which allows type matcher to continue.
@@ -2678,11 +2775,21 @@ bool ConstraintSystem::repairFailures(
26782775
if (!anchor)
26792776
return false;
26802777

2681-
// Repair a coercion ('as') with a forced checked cast ('as!').
2682-
if (auto *coerceToCheckCastFix = CoerceToCheckedCast::attempt(
2683-
*this, lhs, rhs, getConstraintLocator(locator))) {
2684-
conversionsOrFixes.push_back(coerceToCheckCastFix);
2685-
return true;
2778+
if (auto *coercion = dyn_cast<CoerceExpr>(anchor)) {
2779+
// Let's check whether the sub-expression is an optional type which
2780+
// is possible to unwrap (either by force or `??`) to satisfy the cast,
2781+
// otherwise we'd have to fallback to force downcast.
2782+
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind,
2783+
conversionsOrFixes,
2784+
getConstraintLocator(coercion->getSubExpr())))
2785+
return true;
2786+
2787+
// Repair a coercion ('as') with a forced checked cast ('as!').
2788+
if (auto *coerceToCheckCastFix = CoerceToCheckedCast::attempt(
2789+
*this, lhs, rhs, getConstraintLocator(locator))) {
2790+
conversionsOrFixes.push_back(coerceToCheckCastFix);
2791+
return true;
2792+
}
26862793
}
26872794

26882795
// This could be:
@@ -2805,6 +2912,10 @@ bool ConstraintSystem::repairFailures(
28052912
return true;
28062913
}
28072914

2915+
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind,
2916+
conversionsOrFixes, locator))
2917+
return true;
2918+
28082919
// Let's try to match source and destination types one more
28092920
// time to see whether they line up, if they do - the problem is
28102921
// related to immutability, otherwise it's a type mismatch.
@@ -3080,6 +3191,10 @@ bool ConstraintSystem::repairFailures(
30803191
if (lhs->hasHole() || rhs->hasHole())
30813192
return true;
30823193

3194+
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes,
3195+
locator))
3196+
break;
3197+
30833198
conversionsOrFixes.push_back(
30843199
AllowArgumentMismatch::create(*this, lhs, rhs, loc));
30853200
break;
@@ -3244,6 +3359,10 @@ bool ConstraintSystem::repairFailures(
32443359
if (lhs->is<InOutType>() || rhs->is<InOutType>())
32453360
break;
32463361

3362+
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes,
3363+
locator))
3364+
break;
3365+
32473366
// If there is a deep equality, superclass restriction
32483367
// already recorded, let's not add bother ignoring
32493368
// contextual type, because actual fix is going to
@@ -3376,6 +3495,10 @@ bool ConstraintSystem::repairFailures(
33763495
}
33773496

33783497
case ConstraintLocator::Condition: {
3498+
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes,
3499+
locator))
3500+
break;
3501+
33793502
conversionsOrFixes.push_back(IgnoreContextualType::create(
33803503
*this, lhs, rhs, getConstraintLocator(locator)));
33813504
break;
@@ -3390,6 +3513,10 @@ bool ConstraintSystem::repairFailures(
33903513
if (!(anchor && isa<UnresolvedMemberExpr>(anchor)))
33913514
break;
33923515

3516+
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes,
3517+
locator))
3518+
break;
3519+
33933520
// r-value adjustment is used to connect base type of
33943521
// unresolved member to its output type, if there is
33953522
// a type mismatch here it's contextual e.g.
@@ -3426,6 +3553,14 @@ bool ConstraintSystem::repairFailures(
34263553
break;
34273554
}
34283555

3556+
case ConstraintLocator::OptionalPayload: {
3557+
if (repairViaOptionalUnwrap(*this, lhs, rhs, matchKind, conversionsOrFixes,
3558+
locator))
3559+
return true;
3560+
3561+
break;
3562+
}
3563+
34293564
default:
34303565
break;
34313566
}
@@ -4239,55 +4374,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
42394374

42404375
// Attempt fixes iff it's allowed, both types are concrete and
42414376
// we are not in the middle of attempting one already.
4242-
bool attemptFixes =
4243-
shouldAttemptFixes() && !flags.contains(TMF_ApplyingFix);
4244-
4245-
// When we hit this point, we're committed to the set of potential
4246-
// conversions recorded thus far.
4247-
//
4248-
// If we should attempt fixes, add those to the list. They'll only be visited
4249-
// if there are no other possible solutions.
4250-
if (attemptFixes && kind >= ConstraintKind::Conversion) {
4251-
Type objectType1 = type1->getRValueType();
4252-
4253-
// If we have an optional type, try to force-unwrap it.
4254-
// FIXME: Should we also try '?'?
4255-
if (objectType1->getOptionalObjectType()) {
4256-
bool forceUnwrapPossible = true;
4257-
if (auto declRefExpr =
4258-
dyn_cast_or_null<DeclRefExpr>(locator.trySimplifyToExpr())) {
4259-
if (declRefExpr->getDecl()->isImplicit()) {
4260-
// The expression that provides the first type is implicit and never
4261-
// spelled out in source code, e.g. $match in an expression pattern.
4262-
// Thus we cannot force unwrap the first type
4263-
forceUnwrapPossible = false;
4264-
}
4265-
}
4266-
4267-
if (auto optTryExpr =
4268-
dyn_cast_or_null<OptionalTryExpr>(locator.trySimplifyToExpr())) {
4269-
auto subExprType = getType(optTryExpr->getSubExpr());
4270-
const bool isSwift5OrGreater =
4271-
getASTContext().LangOpts.isSwiftVersionAtLeast(5);
4272-
if (isSwift5OrGreater && (bool)subExprType->getOptionalObjectType()) {
4273-
// For 'try?' expressions, a ForceOptional fix converts 'try?'
4274-
// to 'try!'. If the sub-expression is optional, then a force-unwrap
4275-
// won't change anything in Swift 5+ because 'try?' already avoids
4276-
// adding an additional layer of Optional there.
4277-
forceUnwrapPossible = false;
4278-
}
4279-
}
4280-
4281-
if (forceUnwrapPossible) {
4282-
conversionsOrFixes.push_back(ForceOptional::create(
4283-
*this, objectType1, objectType1->getOptionalObjectType(),
4284-
getConstraintLocator(locator)));
4285-
}
4286-
}
4287-
}
4288-
4289-
// Attempt to repair any failures identifiable at this point.
4290-
if (attemptFixes) {
4377+
if (shouldAttemptFixes() && !flags.contains(TMF_ApplyingFix)) {
42914378
if (repairFailures(type1, type2, kind, conversionsOrFixes, locator)) {
42924379
if (conversionsOrFixes.empty())
42934380
return getTypeMatchSuccess();
@@ -4617,6 +4704,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
46174704
return SolutionKind::Error;
46184705

46194706
auto protocolTy = protocol->getDeclaredType();
4707+
46204708
// If this conformance has been fixed already, let's just consider this done.
46214709
if (hasFixedRequirement(type, RequirementKind::Conformance, protocolTy))
46224710
return SolutionKind::Solved;
@@ -4998,13 +5086,10 @@ ConstraintSystem::simplifyFunctionComponentConstraint(
49985086
}
49995087

50005088
if (unwrapCount > 0) {
5001-
auto *fix = ForceOptional::create(*this, simplifiedCopy,
5002-
simplifiedCopy->getOptionalObjectType(),
5089+
auto *fix = ForceOptional::create(*this, simplifiedCopy, second,
50035090
getConstraintLocator(locator));
5004-
while (unwrapCount-- > 0) {
5005-
if (recordFix(fix))
5006-
return SolutionKind::Error;
5007-
}
5091+
if (recordFix(fix, /*impact=*/unwrapCount))
5092+
return SolutionKind::Error;
50085093
}
50095094

50105095
return SolutionKind::Solved;
@@ -7308,13 +7393,10 @@ ConstraintSystem::simplifyApplicableFnConstraint(
73087393
return SolutionKind::Solved;
73097394

73107395
// Record any fixes we attempted to get to the correct solution.
7311-
auto *fix = ForceOptional::create(*this, origType2,
7312-
origType2->getOptionalObjectType(),
7396+
auto *fix = ForceOptional::create(*this, origType2, func1,
73137397
getConstraintLocator(locator));
7314-
while (unwrapCount-- > 0) {
7315-
if (recordFix(fix))
7316-
return SolutionKind::Error;
7317-
}
7398+
if (recordFix(fix, /*impact=*/unwrapCount))
7399+
return SolutionKind::Error;
73187400

73197401
return SolutionKind::Solved;
73207402
}
@@ -7336,13 +7418,10 @@ ConstraintSystem::simplifyApplicableFnConstraint(
73367418
if (unwrapCount == 0)
73377419
return SolutionKind::Solved;
73387420

7339-
auto *fix = ForceOptional::create(*this, origType2,
7340-
origType2->getOptionalObjectType(),
7421+
auto *fix = ForceOptional::create(*this, origType2, func1,
73417422
getConstraintLocator(locator));
7342-
while (unwrapCount-- > 0) {
7343-
if (recordFix(fix))
7344-
return SolutionKind::Error;
7345-
}
7423+
if (recordFix(fix, /*impact=*/unwrapCount))
7424+
return SolutionKind::Error;
73467425
}
73477426

73487427
return simplified;
@@ -8194,15 +8273,16 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
81948273
getDefaultDecompositionOptions(flags) | TMF_ApplyingFix;
81958274
switch (fix->getKind()) {
81968275
case FixKind::ForceOptional: {
8197-
// Assume that we've unwrapped the first type.
8198-
auto result =
8199-
matchTypes(type1->getRValueType()->getOptionalObjectType(), type2,
8200-
matchKind, subflags, locator);
8201-
if (result == SolutionKind::Solved)
8202-
if (recordFix(fix))
8203-
return SolutionKind::Error;
8276+
SmallVector<Type, 4> unwraps1;
8277+
type1->lookThroughAllOptionalTypes(unwraps1);
82048278

8205-
return result;
8279+
SmallVector<Type, 4> unwraps2;
8280+
type2->lookThroughAllOptionalTypes(unwraps2);
8281+
8282+
auto impact = unwraps1.size() != unwraps2.size()
8283+
? unwraps1.size() - unwraps2.size()
8284+
: 1;
8285+
return recordFix(fix, impact) ? SolutionKind::Error : SolutionKind::Solved;
82068286
}
82078287

82088288
case FixKind::UnwrapOptionalBase:

0 commit comments

Comments
 (0)