Skip to content

Commit 8d86619

Browse files
committed
IUO: Put the pieces in place to handle coercions and casts to IUO types.
For casts like 'x as T!' or 'x as! T!', generate a disjunction that attempts to bind both the optional and non-optional T, preferring the optional branch of the disjunction. Note that this should effectively be NFC at the moment because we're still generating the IUO type for T! rather than a plain optional, so we first attempt the IUO type (as opposed to an Optional<T>) which goes through existing logic that handles the IUOs as part of the type system. The new rewriting logic will actually do something once we switch over to generating Optional<T> when T! is uttered.
1 parent 406a025 commit 8d86619

File tree

2 files changed

+94
-5
lines changed

2 files changed

+94
-5
lines changed

lib/Sema/CSApply.cpp

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3170,7 +3170,7 @@ namespace {
31703170
cast->setImplicit();
31713171

31723172
// Type-check this conditional case.
3173-
Expr *result = visitConditionalCheckedCastExpr(cast, true);
3173+
Expr *result = handleConditionalCheckedCastExpr(cast, true);
31743174
if (!result)
31753175
return nullptr;
31763176

@@ -3409,7 +3409,28 @@ namespace {
34093409
return addFinalOptionalInjections(result);
34103410
}
34113411

3412+
bool hasForcedOptionalResult(ExplicitCastExpr *expr) {
3413+
auto *TR = expr->getCastTypeLoc().getTypeRepr();
3414+
if (TR && TR->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional) {
3415+
auto *locator = cs.getConstraintLocator(
3416+
expr, ConstraintLocator::ImplicitlyUnwrappedCoercionResult);
3417+
return solution.getDisjunctionChoice(locator);
3418+
}
3419+
return false;
3420+
}
3421+
34123422
Expr *visitCoerceExpr(CoerceExpr *expr) {
3423+
// If we need to insert a force-unwrap for coercions of the form
3424+
// 'as T!', do so now.
3425+
if (hasForcedOptionalResult(expr)) {
3426+
auto *coerced = visitCoerceExpr(expr, None);
3427+
if (!coerced)
3428+
return nullptr;
3429+
3430+
return coerceImplicitlyUnwrappedOptionalToValue(
3431+
coerced, cs.getType(coerced)->getOptionalObjectType());
3432+
}
3433+
34133434
return visitCoerceExpr(expr, None);
34143435
}
34153436

@@ -3482,7 +3503,24 @@ namespace {
34823503
return expr;
34833504
}
34843505

3506+
// Rewrite ForcedCheckedCastExpr based on what the solver computed.
34853507
Expr *visitForcedCheckedCastExpr(ForcedCheckedCastExpr *expr) {
3508+
// If we need to insert a force-unwrap for coercions of the form
3509+
// 'as! T!', do so now.
3510+
if (hasForcedOptionalResult(expr)) {
3511+
auto *coerced = handleForcedCheckedCastExpr(expr);
3512+
if (!coerced)
3513+
return nullptr;
3514+
3515+
return coerceImplicitlyUnwrappedOptionalToValue(
3516+
coerced, cs.getType(coerced)->getOptionalObjectType());
3517+
}
3518+
3519+
return handleForcedCheckedCastExpr(expr);
3520+
}
3521+
3522+
// Most of the logic for dealing with ForcedCheckedCastExpr.
3523+
Expr *handleForcedCheckedCastExpr(ForcedCheckedCastExpr *expr) {
34863524
// Simplify the type we're casting to.
34873525
auto toType = simplifyType(expr->getCastTypeLoc().getType());
34883526
expr->getCastTypeLoc().setType(toType, /*validated=*/true);
@@ -3546,8 +3584,23 @@ namespace {
35463584
OptionalBindingsCastKind::Forced);
35473585
}
35483586

3549-
Expr *visitConditionalCheckedCastExpr(ConditionalCheckedCastExpr *expr,
3550-
bool isInsideIsExpr = false) {
3587+
Expr *visitConditionalCheckedCastExpr(ConditionalCheckedCastExpr *expr) {
3588+
// If we need to insert a force-unwrap for coercions of the form
3589+
// 'as! T!', do so now.
3590+
if (hasForcedOptionalResult(expr)) {
3591+
auto *coerced = handleConditionalCheckedCastExpr(expr);
3592+
if (!coerced)
3593+
return nullptr;
3594+
3595+
return coerceImplicitlyUnwrappedOptionalToValue(
3596+
coerced, cs.getType(coerced)->getOptionalObjectType());
3597+
}
3598+
3599+
return handleConditionalCheckedCastExpr(expr);
3600+
}
3601+
3602+
Expr *handleConditionalCheckedCastExpr(ConditionalCheckedCastExpr *expr,
3603+
bool isInsideIsExpr = false) {
35513604
// Simplify the type we're casting to.
35523605
auto toType = simplifyType(expr->getCastTypeLoc().getType());
35533606
checkForImportedUsedConformances(toType);

lib/Sema/CSGen.cpp

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2494,6 +2494,18 @@ namespace {
24942494
llvm_unreachable("Already type-checked");
24952495
}
24962496

2497+
Type
2498+
createTypeVariableAndDisjunctionForIUOCoercion(Type toType,
2499+
ConstraintLocator *locator) {
2500+
auto implicitUnwrapLocator = CS.getConstraintLocator(
2501+
locator, ConstraintLocator::ImplicitlyUnwrappedCoercionResult);
2502+
auto typeVar =
2503+
CS.createTypeVariable(implicitUnwrapLocator, /*options=*/0);
2504+
CS.buildDisjunctionForImplicitlyUnwrappedOptional(typeVar, toType,
2505+
implicitUnwrapLocator);
2506+
return typeVar;
2507+
}
2508+
24972509
Type visitForcedCheckedCastExpr(ForcedCheckedCastExpr *expr) {
24982510
auto &tc = CS.getTypeChecker();
24992511
auto fromExpr = expr->getSubExpr();
@@ -2517,6 +2529,12 @@ namespace {
25172529
// The source type can be checked-cast to the destination type.
25182530
CS.addConstraint(ConstraintKind::CheckedCast, fromType, toType, locator);
25192531

2532+
// If the result type was declared IUO, add a disjunction for
2533+
// bindings for the result of the coercion.
2534+
auto *TR = expr->getCastTypeLoc().getTypeRepr();
2535+
if (TR && TR->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional)
2536+
return createTypeVariableAndDisjunctionForIUOCoercion(toType, locator);
2537+
25202538
return toType;
25212539
}
25222540

@@ -2537,8 +2555,17 @@ namespace {
25372555
auto fromType = CS.getType(expr->getSubExpr());
25382556
auto locator = CS.getConstraintLocator(expr);
25392557

2540-
CS.addExplicitConversionConstraint(fromType, toType, /*allowFixes=*/true,
2541-
locator);
2558+
// Add a conversion constraint for the direct conversion between
2559+
// types.
2560+
CS.addExplicitConversionConstraint(fromType, toType,
2561+
/*allowFixes=*/true, locator);
2562+
2563+
// If the result type was declared IUO, add a disjunction for
2564+
// bindings for the result of the coercion.
2565+
auto *TR = expr->getCastTypeLoc().getTypeRepr();
2566+
if (TR && TR->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional)
2567+
return createTypeVariableAndDisjunctionForIUOCoercion(toType, locator);
2568+
25422569
return toType;
25432570
}
25442571

@@ -2561,7 +2588,16 @@ namespace {
25612588

25622589
auto fromType = CS.getType(fromExpr);
25632590
auto locator = CS.getConstraintLocator(expr);
2591+
25642592
CS.addConstraint(ConstraintKind::CheckedCast, fromType, toType, locator);
2593+
2594+
// If the result type was declared IUO, add a disjunction for
2595+
// bindings for the result of the coercion.
2596+
auto *TR = expr->getCastTypeLoc().getTypeRepr();
2597+
if (TR && TR->getKind() == TypeReprKind::ImplicitlyUnwrappedOptional)
2598+
return createTypeVariableAndDisjunctionForIUOCoercion(
2599+
OptionalType::get(toType), locator);
2600+
25652601
return OptionalType::get(toType);
25662602
}
25672603

0 commit comments

Comments
 (0)