@@ -3037,7 +3037,9 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
30373037 Expr *fromExpr,
30383038 SourceRange diagToRange) {
30393039 // 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;
30413043 assert ((suppressDiagnostics || diagLoc.isValid ()) &&
30423044 " diagnostics require a valid source location" );
30433045
@@ -3133,6 +3135,7 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
31333135
31343136 switch (contextKind) {
31353137 case CheckedCastContextKind::None:
3138+ case CheckedCastContextKind::Coercion:
31363139 llvm_unreachable (" suppressing diagnostics" );
31373140
31383141 case CheckedCastContextKind::ForcedCast: {
@@ -3264,7 +3267,15 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
32643267 return castKind;
32653268
32663269 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;
32683279 }
32693280 llvm_unreachable (" invalid cast type" );
32703281 };
@@ -3295,15 +3306,19 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
32953306 BridgingCoercion);
32963307 break ;
32973308
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+
32983316 case CheckedCastKind::ArrayDowncast:
32993317 case CheckedCastKind::DictionaryDowncast:
33003318 case CheckedCastKind::SetDowncast:
33013319 case CheckedCastKind::ValueCast:
33023320 hasCast = true ;
33033321 break ;
3304-
3305- case CheckedCastKind::Unresolved:
3306- return failed ();
33073322 }
33083323
33093324 switch (typeCheckCheckedCast (fromKeyValue->second , toKeyValue->second ,
@@ -3318,15 +3333,19 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
33183333 BridgingCoercion);
33193334 break ;
33203335
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+
33213343 case CheckedCastKind::ArrayDowncast:
33223344 case CheckedCastKind::DictionaryDowncast:
33233345 case CheckedCastKind::SetDowncast:
33243346 case CheckedCastKind::ValueCast:
33253347 hasCast = true ;
33263348 break ;
3327-
3328- case CheckedCastKind::Unresolved:
3329- return failed ();
33303349 }
33313350
33323351 if (hasCast) return CheckedCastKind::DictionaryDowncast;
@@ -3357,7 +3376,7 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
33573376 const auto &fromElt = fromTuple->getElement (i);
33583377 const auto &toElt = toTuple->getElement (i);
33593378
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,
33613380 // because unlabeled tuple elements can be converted to labeled ones
33623381 // e.g.
33633382 //
@@ -3423,6 +3442,7 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
34233442 case CheckedCastContextKind::EnumElementPattern:
34243443 case CheckedCastContextKind::IsExpr:
34253444 case CheckedCastContextKind::None:
3445+ case CheckedCastContextKind::Coercion:
34263446 break ;
34273447 }
34283448 }
@@ -3554,6 +3574,19 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
35543574 if (!couldDynamicallyConformToProtocol (toType, protocolDecl, dc)) {
35553575 return failed ();
35563576 }
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+ }
35573590 }
35583591
35593592 // If neither type is class-constrained, anything goes.
0 commit comments