@@ -5963,6 +5963,98 @@ static CheckedCastKind getCheckedCastKind(ConstraintSystem *cs,
5963
5963
return CheckedCastKind::ValueCast;
5964
5964
}
5965
5965
5966
+ // Optional types always conform to `ExpressibleByNilLiteral`.
5967
+ static bool isCastToExpressibleByNilLiteral (ConstraintSystem &cs, Type fromType,
5968
+ Type toType) {
5969
+ auto &ctx = cs.getASTContext ();
5970
+ auto *nilLiteral =
5971
+ ctx.getProtocol (KnownProtocolKind::ExpressibleByNilLiteral);
5972
+ return toType->isEqual (nilLiteral->getDeclaredType ()) &&
5973
+ fromType->getOptionalObjectType ();
5974
+ }
5975
+
5976
+ static ConstraintFix *attemptFixForCheckedConvertibleTypes (
5977
+ ConstraintSystem &cs, Type origFromType, Type origToType, Type fromType,
5978
+ Type toType, SmallVector<Type, 4 > fromOptionals,
5979
+ SmallVector<Type, 4 > toOptionals, ConstraintSystem::TypeMatchOptions flags,
5980
+ ConstraintLocatorBuilder locator) {
5981
+
5982
+ if (flags.contains (ConstraintSystem::TypeMatchFlags::TMF_ApplyingFix))
5983
+ return nullptr ;
5984
+
5985
+ // Both types have to be fixed.
5986
+ if (fromType->hasTypeVariable () || toType->hasTypeVariable ())
5987
+ return nullptr ;
5988
+
5989
+ SmallVector<LocatorPathElt, 4 > path;
5990
+ auto anchor = locator.getLocatorParts (path);
5991
+
5992
+ auto *castExpr = getAsExpr<ExplicitCastExpr>(anchor);
5993
+ if (!castExpr)
5994
+ return nullptr ;
5995
+
5996
+ unsigned extraOptionals = fromOptionals.size () - toOptionals.size ();
5997
+ // Removing the optionality from to type when the force cast expr is an IUO.
5998
+ const auto *const TR = castExpr->getCastTypeRepr ();
5999
+ if (isExpr<ForcedCheckedCastExpr>(anchor) && TR &&
6000
+ TR->getKind () == TypeReprKind::ImplicitlyUnwrappedOptional) {
6001
+ extraOptionals++;
6002
+ }
6003
+
6004
+ // In cases of 'try?' where origFromType isn't optional that meaning
6005
+ // sub-expression isn't optional, always adds one level of optionality
6006
+ // because the result of the expression is always an optional type
6007
+ // regardless of language mode.
6008
+ auto *sub = castExpr->getSubExpr ()->getSemanticsProvidingExpr ();
6009
+ if (isExpr<OptionalTryExpr>(sub) && !origFromType->getOptionalObjectType ()) {
6010
+ origFromType = OptionalType::get (fromType);
6011
+ extraOptionals++;
6012
+ }
6013
+
6014
+ // Except for forced cast expressions, if optionals are more than a single
6015
+ // level difference, we don't need to record any fix.
6016
+ if (!isExpr<ForcedCheckedCastExpr>(anchor) && extraOptionals > 1 )
6017
+ return nullptr ;
6018
+
6019
+ // Always succeed
6020
+ if (isCastToExpressibleByNilLiteral (cs, origFromType, toType)) {
6021
+ return AllowAlwaysSucceedCheckedCast::create (
6022
+ cs, fromType, toType, CheckedCastKind::Coercion,
6023
+ cs.getConstraintLocator (locator));
6024
+ }
6025
+
6026
+ // If both original are metatypes we have to use them because most of the
6027
+ // logic on how correctly handle metatypes casting is on
6028
+ // typeCheckCheckedCast.
6029
+ if (origFromType->is <AnyMetatypeType>() &&
6030
+ origToType->is <AnyMetatypeType>()) {
6031
+ fromType = origFromType;
6032
+ toType = origToType;
6033
+ }
6034
+
6035
+ auto castKind = TypeChecker::typeCheckCheckedCast (
6036
+ fromType, toType, CheckedCastContextKind::None, cs.DC , SourceLoc (),
6037
+ nullptr , SourceRange ());
6038
+ if (!(castKind == CheckedCastKind::Coercion ||
6039
+ castKind == CheckedCastKind::BridgingCoercion))
6040
+ return nullptr ;
6041
+
6042
+ if (auto *fix = AllowUnsupportedRuntimeCheckedCast::attempt (
6043
+ cs, fromType, toType, castKind, cs.getConstraintLocator (locator))) {
6044
+ return fix;
6045
+ }
6046
+ if (extraOptionals > 0 ) {
6047
+ return AllowCheckedCastCoercibleOptionalType::create (
6048
+ cs, origFromType, origToType, castKind,
6049
+ cs.getConstraintLocator (locator));
6050
+ } else {
6051
+ // No optionals, just a trivial cast that always succeed.
6052
+ return AllowAlwaysSucceedCheckedCast::create (
6053
+ cs, origFromType, origToType, castKind,
6054
+ cs.getConstraintLocator (locator));
6055
+ }
6056
+ }
6057
+
5966
6058
ConstraintSystem::SolutionKind
5967
6059
ConstraintSystem::simplifyCheckedCastConstraint (
5968
6060
Type fromType, Type toType,
@@ -6041,100 +6133,14 @@ ConstraintSystem::simplifyCheckedCastConstraint(
6041
6133
break ;
6042
6134
} while (true );
6043
6135
6044
- auto fixForCheckedConvertibleTypes = [&]() -> ConstraintFix * {
6045
- // Both types are known.
6046
- if (fromType->hasTypeVariable () || toType->hasTypeVariable ())
6047
- return nullptr ;
6048
-
6049
- if (flags.contains (TMF_ApplyingFix))
6050
- return nullptr ;
6051
-
6052
- SmallVector<LocatorPathElt, 4 > path;
6053
- auto anchor = locator.getLocatorParts (path);
6054
- auto *castExpr = getAsExpr<ExplicitCastExpr>(anchor);
6055
- if (!castExpr)
6056
- return nullptr ;
6057
-
6058
- unsigned extraOptionals = fromOptionals.size () - toOptionals.size ();
6059
- // Removing the optionality from to type when the force cast expr is an IUO.
6060
- const auto *const TR = castExpr->getCastTypeRepr ();
6061
- if (isExpr<ForcedCheckedCastExpr>(anchor) && TR &&
6062
- TR->getKind () == TypeReprKind::ImplicitlyUnwrappedOptional) {
6063
- extraOptionals++;
6064
- }
6065
-
6066
- // In some special cases e.g.
6067
- // struct A {
6068
- // func opt() throws -> Int { return 3 }
6069
- // }
6070
- // let a: A? = A()
6071
- // let _ = (try? a?.opt()) as? Int
6072
- //
6073
- // If original from type is a non-optional and subExpr is an
6074
- // OptionalTryExpr, to make sure we handle this correctly lets add the
6075
- // optionality because the result of the expression is always an optional
6076
- // type regardless of language mode.
6077
- auto *sub = castExpr->getSubExpr ()->getSemanticsProvidingExpr ();
6078
- if (isExpr<OptionalTryExpr>(sub) &&
6079
- !origFromType->getOptionalObjectType ()) {
6080
- origFromType = OptionalType::get (fromType);
6081
- extraOptionals++;
6082
- }
6083
-
6084
- // Except for forced cast expressions, if optionals are more than a single
6085
- // level difference, we don't need to record the fix.
6086
- if (!isExpr<ForcedCheckedCastExpr>(anchor) && extraOptionals > 1 )
6087
- return nullptr ;
6088
-
6089
- // Explicit handling cast to ExpressibleByNilLiteral because
6090
- // optional types trivially satisfy the conformance.
6091
- auto &ctx = getASTContext ();
6092
- auto *nilLiteral =
6093
- ctx.getProtocol (KnownProtocolKind::ExpressibleByNilLiteral);
6094
- if (toType->isEqual (nilLiteral->getDeclaredType ()) &&
6095
- origFromType->getOptionalObjectType ()) {
6096
- return AllowAlwaysSucceedCheckedCast::create (
6097
- *this , fromType, toType, CheckedCastKind::Coercion,
6098
- getConstraintLocator (locator));
6099
- }
6100
-
6101
- // If both original are metatypes we have to use them because most of the
6102
- // logic on how correctly handle metatypes casting is on
6103
- // typeCheckCheckedCast.
6104
- if (origFromType->is <AnyMetatypeType>() &&
6105
- origToType->is <AnyMetatypeType>()) {
6106
- fromType = origFromType;
6107
- toType = origToType;
6108
- }
6109
-
6110
- auto castKind = TypeChecker::typeCheckCheckedCast (
6111
- fromType, toType, CheckedCastContextKind::None, DC, SourceLoc (),
6112
- nullptr , SourceRange ());
6113
- if (!(castKind == CheckedCastKind::Coercion ||
6114
- castKind == CheckedCastKind::BridgingCoercion))
6115
- return nullptr ;
6116
-
6117
- if (auto *fix = AllowUnsupportedRuntimeCheckedCast::attempt (
6118
- *this , fromType, toType, castKind, getConstraintLocator (locator))) {
6119
- return fix;
6120
- }
6121
- if (extraOptionals > 0 ) {
6122
- return AllowCheckedCastCoercibleOptionalType::create (
6123
- *this , origFromType, origToType, castKind,
6124
- getConstraintLocator (locator));
6125
- } else {
6126
- // No optionals, just a trivial cast that always succeed.
6127
- return AllowAlwaysSucceedCheckedCast::create (
6128
- *this , origFromType, origToType, castKind,
6129
- getConstraintLocator (locator));
6130
- }
6131
- };
6136
+ auto attemptRecordCastFixIfSolved = [&](SolutionKind result) {
6137
+ if (result != SolutionKind::Solved)
6138
+ return ;
6132
6139
6133
- auto recordCastFixIfNeeded = [&](SolutionKind result) {
6134
- if (result == SolutionKind::Solved) {
6135
- if (auto *fix = fixForCheckedConvertibleTypes ()) {
6136
- (void )recordFix (fix);
6137
- }
6140
+ if (auto *fix = attemptFixForCheckedConvertibleTypes (
6141
+ *this , origFromType, origToType, fromType, toType, fromOptionals,
6142
+ toOptionals, flags, locator)) {
6143
+ (void )recordFix (fix);
6138
6144
}
6139
6145
};
6140
6146
@@ -6146,9 +6152,10 @@ ConstraintSystem::simplifyCheckedCastConstraint(
6146
6152
6147
6153
auto result = simplifyCheckedCastConstraint (
6148
6154
fromBaseType, toBaseType, subflags | TMF_ApplyingFix, locator);
6149
- recordCastFixIfNeeded (result);
6155
+ attemptRecordCastFixIfSolved (result);
6150
6156
return result;
6151
6157
}
6158
+
6152
6159
case CheckedCastKind::DictionaryDowncast: {
6153
6160
Type fromKeyType, fromValueType;
6154
6161
std::tie (fromKeyType, fromValueType) = *isDictionaryType (fromType);
@@ -6163,7 +6170,7 @@ ConstraintSystem::simplifyCheckedCastConstraint(
6163
6170
6164
6171
auto result = simplifyCheckedCastConstraint (
6165
6172
fromValueType, toValueType, subflags | TMF_ApplyingFix, locator);
6166
- recordCastFixIfNeeded (result);
6173
+ attemptRecordCastFixIfSolved (result);
6167
6174
return result;
6168
6175
}
6169
6176
@@ -6172,7 +6179,7 @@ ConstraintSystem::simplifyCheckedCastConstraint(
6172
6179
auto toBaseType = *isSetType (toType);
6173
6180
auto result = simplifyCheckedCastConstraint (
6174
6181
fromBaseType, toBaseType, subflags | TMF_ApplyingFix, locator);
6175
- recordCastFixIfNeeded (result);
6182
+ attemptRecordCastFixIfSolved (result);
6176
6183
return result;
6177
6184
}
6178
6185
@@ -6187,7 +6194,12 @@ ConstraintSystem::simplifyCheckedCastConstraint(
6187
6194
getConstraintLocator (locator));
6188
6195
}
6189
6196
6190
- if (auto *fix = fixForCheckedConvertibleTypes ()) {
6197
+ // Attempts to record warning fixes when both types are known by the
6198
+ // compiler and we can infer that the runtime checked cast will always
6199
+ // succeed or fail.
6200
+ if (auto *fix = attemptFixForCheckedConvertibleTypes (
6201
+ *this , origFromType, origToType, fromType, toType, fromOptionals,
6202
+ toOptionals, flags, locator)) {
6191
6203
(void )recordFix (fix);
6192
6204
}
6193
6205
0 commit comments