@@ -3093,6 +3093,12 @@ static bool isLiteralConvertibleType(Type fromType,
3093
3093
return false ;
3094
3094
}
3095
3095
3096
+ static bool isIntegerType (Type fromType, ConstraintSystem *CS) {
3097
+ return isLiteralConvertibleType (fromType,
3098
+ KnownProtocolKind::IntegerLiteralConvertible,
3099
+ CS);
3100
+ }
3101
+
3096
3102
// / Return true if the given type conforms to RawRepresentable, with an
3097
3103
// / underlying type conforming to the given known protocol.
3098
3104
static Type isRawRepresentable (Type fromType,
@@ -3141,7 +3147,6 @@ static bool isIntegerToStringIndexConversion(Type fromType, Type toType,
3141
3147
// / This helps migration with SDK changes.
3142
3148
static void tryRawRepresentableFixIts (InFlightDiagnostic &diag,
3143
3149
ConstraintSystem *CS,
3144
- Diag<Type, Type> diagID,
3145
3150
Type fromType,
3146
3151
Type toType,
3147
3152
KnownProtocolKind kind,
@@ -3182,6 +3187,54 @@ static void tryRawRepresentableFixIts(InFlightDiagnostic &diag,
3182
3187
}
3183
3188
}
3184
3189
3190
+ // / Attempts to add fix-its for these two mistakes:
3191
+ // /
3192
+ // / - Passing an integer with the right type but which is getting wrapped with a
3193
+ // / different integer type unnecessarily. The fixit removes the cast.
3194
+ // /
3195
+ // / - Passing an integer but expecting different integer type. The fixit adds
3196
+ // / a wrapping cast.
3197
+ // /
3198
+ // / This helps migration with SDK changes.
3199
+ static void tryIntegerCastFixIts (InFlightDiagnostic &diag,
3200
+ ConstraintSystem *CS,
3201
+ Type fromType,
3202
+ Type toType,
3203
+ Expr *expr) {
3204
+ if (!isIntegerType (fromType, CS) || !isIntegerType (toType, CS))
3205
+ return ;
3206
+
3207
+ auto getInnerCastedExpr = [&]() -> Expr* {
3208
+ CallExpr *CE = dyn_cast<CallExpr>(expr);
3209
+ if (!CE)
3210
+ return nullptr ;
3211
+ if (!isa<ConstructorRefCallExpr>(CE->getFn ()))
3212
+ return nullptr ;
3213
+ ParenExpr *parenE = dyn_cast<ParenExpr>(CE->getArg ());
3214
+ if (!parenE)
3215
+ return nullptr ;
3216
+ return parenE->getSubExpr ();
3217
+ };
3218
+
3219
+ if (Expr *innerE = getInnerCastedExpr ()) {
3220
+ Type innerTy = innerE->getType ();
3221
+ if (CS->TC .isConvertibleTo (innerTy, toType, CS->DC )) {
3222
+ // Remove the unnecessary cast.
3223
+ diag.fixItRemoveChars (expr->getLoc (), innerE->getStartLoc ())
3224
+ .fixItRemove (expr->getEndLoc ());
3225
+ return ;
3226
+ }
3227
+ }
3228
+
3229
+ // Add a wrapping integer cast.
3230
+ std::string convWrapBefore = toType.getString ();
3231
+ convWrapBefore += " (" ;
3232
+ std::string convWrapAfter = " )" ;
3233
+ SourceRange exprRange = expr->getSourceRange ();
3234
+ diag.fixItInsert (exprRange.Start , convWrapBefore);
3235
+ diag.fixItInsertAfter (exprRange.End , convWrapAfter);
3236
+ }
3237
+
3185
3238
bool FailureDiagnosis::diagnoseContextualConversionError () {
3186
3239
// If the constraint system has a contextual type, then we can test to see if
3187
3240
// this is the problem that prevents us from solving the system.
@@ -3420,12 +3473,13 @@ bool FailureDiagnosis::diagnoseContextualConversionError() {
3420
3473
case CTP_ArrayElement:
3421
3474
case CTP_DictionaryKey:
3422
3475
case CTP_DictionaryValue:
3423
- tryRawRepresentableFixIts (diag, CS, diagID, exprType, contextualType,
3476
+ tryRawRepresentableFixIts (diag, CS, exprType, contextualType,
3424
3477
KnownProtocolKind::IntegerLiteralConvertible,
3425
3478
expr);
3426
- tryRawRepresentableFixIts (diag, CS, diagID, exprType, contextualType,
3479
+ tryRawRepresentableFixIts (diag, CS, exprType, contextualType,
3427
3480
KnownProtocolKind::StringLiteralConvertible,
3428
3481
expr);
3482
+ tryIntegerCastFixIts (diag, CS, exprType, contextualType, expr);
3429
3483
break ;
3430
3484
3431
3485
default :
0 commit comments