@@ -3037,7 +3037,9 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
3037
3037
Expr *fromExpr,
3038
3038
SourceRange diagToRange) {
3039
3039
// Determine whether we should suppress diagnostics.
3040
- const bool suppressDiagnostics = contextKind == CheckedCastContextKind::None;
3040
+ const bool suppressDiagnostics =
3041
+ contextKind == CheckedCastContextKind::None ||
3042
+ contextKind == CheckedCastContextKind::Coercion;
3041
3043
assert ((suppressDiagnostics || diagLoc.isValid ()) &&
3042
3044
" diagnostics require a valid source location" );
3043
3045
@@ -3133,6 +3135,7 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
3133
3135
3134
3136
switch (contextKind) {
3135
3137
case CheckedCastContextKind::None:
3138
+ case CheckedCastContextKind::Coercion:
3136
3139
llvm_unreachable (" suppressing diagnostics" );
3137
3140
3138
3141
case CheckedCastContextKind::ForcedCast: {
@@ -3264,7 +3267,15 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
3264
3267
return castKind;
3265
3268
3266
3269
case CheckedCastKind::Unresolved:
3267
- return failed ();
3270
+ // Even though we know the elements cannot be downcast, we cannot return
3271
+ // failed() here as it's possible for an empty Array, Set or Dictionary to
3272
+ // be cast to any element type at runtime (SR-6192). The one exception to
3273
+ // this is when we're checking whether we can treat a coercion as a checked
3274
+ // cast because we don't want to tell the user to use as!, as it's probably
3275
+ // the wrong suggestion.
3276
+ if (contextKind == CheckedCastContextKind::Coercion)
3277
+ return failed ();
3278
+ return castKind;
3268
3279
}
3269
3280
llvm_unreachable (" invalid cast type" );
3270
3281
};
@@ -3295,15 +3306,19 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
3295
3306
BridgingCoercion);
3296
3307
break ;
3297
3308
3309
+ case CheckedCastKind::Unresolved:
3310
+ // Handled the same as in checkElementCast; see comment there for
3311
+ // rationale.
3312
+ if (contextKind == CheckedCastContextKind::Coercion)
3313
+ return failed ();
3314
+ LLVM_FALLTHROUGH;
3315
+
3298
3316
case CheckedCastKind::ArrayDowncast:
3299
3317
case CheckedCastKind::DictionaryDowncast:
3300
3318
case CheckedCastKind::SetDowncast:
3301
3319
case CheckedCastKind::ValueCast:
3302
3320
hasCast = true ;
3303
3321
break ;
3304
-
3305
- case CheckedCastKind::Unresolved:
3306
- return failed ();
3307
3322
}
3308
3323
3309
3324
switch (typeCheckCheckedCast (fromKeyValue->second , toKeyValue->second ,
@@ -3318,15 +3333,19 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
3318
3333
BridgingCoercion);
3319
3334
break ;
3320
3335
3336
+ case CheckedCastKind::Unresolved:
3337
+ // Handled the same as in checkElementCast; see comment there for
3338
+ // rationale.
3339
+ if (contextKind == CheckedCastContextKind::Coercion)
3340
+ return failed ();
3341
+ LLVM_FALLTHROUGH;
3342
+
3321
3343
case CheckedCastKind::ArrayDowncast:
3322
3344
case CheckedCastKind::DictionaryDowncast:
3323
3345
case CheckedCastKind::SetDowncast:
3324
3346
case CheckedCastKind::ValueCast:
3325
3347
hasCast = true ;
3326
3348
break ;
3327
-
3328
- case CheckedCastKind::Unresolved:
3329
- return failed ();
3330
3349
}
3331
3350
3332
3351
if (hasCast) return CheckedCastKind::DictionaryDowncast;
@@ -3357,7 +3376,7 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
3357
3376
const auto &fromElt = fromTuple->getElement (i);
3358
3377
const auto &toElt = toTuple->getElement (i);
3359
3378
3360
- // We should only perform name validation if both element have a label,
3379
+ // We should only perform name validation if both elements have a label,
3361
3380
// because unlabeled tuple elements can be converted to labeled ones
3362
3381
// e.g.
3363
3382
//
@@ -3423,6 +3442,7 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
3423
3442
case CheckedCastContextKind::EnumElementPattern:
3424
3443
case CheckedCastContextKind::IsExpr:
3425
3444
case CheckedCastContextKind::None:
3445
+ case CheckedCastContextKind::Coercion:
3426
3446
break ;
3427
3447
}
3428
3448
}
@@ -3554,6 +3574,19 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
3554
3574
if (!couldDynamicallyConformToProtocol (toType, protocolDecl, dc)) {
3555
3575
return failed ();
3556
3576
}
3577
+ } else if (auto protocolComposition =
3578
+ fromType->getAs <ProtocolCompositionType>()) {
3579
+ if (llvm::any_of (protocolComposition->getMembers (),
3580
+ [&](Type protocolType) {
3581
+ if (auto protocolDecl = dyn_cast_or_null<ProtocolDecl>(
3582
+ protocolType->getAnyNominal ())) {
3583
+ return !couldDynamicallyConformToProtocol (
3584
+ toType, protocolDecl, dc);
3585
+ }
3586
+ return false ;
3587
+ })) {
3588
+ return failed ();
3589
+ }
3557
3590
}
3558
3591
3559
3592
// If neither type is class-constrained, anything goes.
0 commit comments