@@ -3076,87 +3076,110 @@ bool FailureDiagnosis::diagnoseCalleeResultContextualConversionError() {
3076
3076
}
3077
3077
3078
3078
3079
- // / Return true if the conversion from fromType to toType is an invalid string
3080
- // / index operation.
3081
- static bool isIntegerToStringIndexConversion (Type fromType, Type toType ,
3082
- ConstraintSystem *CS) {
3079
+ // / Return true if the given type conforms to a known protocol type.
3080
+ static bool isLiteralConvertibleType (Type fromType,
3081
+ KnownProtocolKind kind ,
3082
+ ConstraintSystem *CS) {
3083
3083
auto integerType =
3084
- CS->TC .getProtocol (SourceLoc (),
3085
- KnownProtocolKind::IntegerLiteralConvertible);
3086
- if (!integerType) return false ;
3084
+ CS->TC .getProtocol (SourceLoc (), kind);
3085
+ if (!integerType)
3086
+ return false ;
3087
3087
3088
- // If the from type is an integer type, and the to type is
3089
- // String.CharacterView.Index, then we found one.
3090
3088
if (CS->TC .conformsToProtocol (fromType, integerType, CS->DC ,
3091
3089
ConformanceCheckFlags::InExpression)) {
3092
- if (toType->getCanonicalType ().getString () == " String.CharacterView.Index" )
3093
- return true ;
3090
+ return true ;
3094
3091
}
3095
3092
3096
3093
return false ;
3097
3094
}
3098
3095
3099
- // / Attempts to add a fixit to correct the compiler error.
3100
- // /
3101
- // / Corrects the error is "cannot convert value of type <integer> to expected
3102
- // / argument type <RawRepresentable>", by adding a fixit that constructs the
3103
- // / raw-representable type from the value. This helps with SDK changes.
3104
- static void tryConversionFixit (InFlightDiagnostic &diag,
3105
- ConstraintSystem *CS,
3106
- Diag<Type, Type> diagID,
3107
- Type exprType,
3108
- Type contextualType,
3109
- Expr *expr) {
3110
- if (!CS || !expr || !exprType || !contextualType)
3111
- return ;
3112
- if (diagID.ID != diag::cannot_convert_argument_value.ID )
3113
- return ;
3114
-
3115
- auto integerType =
3116
- CS->TC .getProtocol (SourceLoc (),
3117
- KnownProtocolKind::IntegerLiteralConvertible);
3118
- if (!integerType) return ;
3119
-
3120
- auto isIntegerType = [&](Type ty) -> bool {
3121
- return CS->TC .conformsToProtocol (exprType, integerType, CS->DC ,
3122
- ConformanceCheckFlags::InExpression);
3123
- };
3124
-
3125
- // When the error is "cannot convert value of type <integer> to expected
3126
- // argument type <RawRepresentable>", add a fixit that constructs the
3127
- // raw-representable type from the value.
3128
-
3129
- if (!isIntegerType (exprType))
3130
- return ;
3131
-
3096
+ // / Return true if the given type conforms to RawRepresentable, with an
3097
+ // / underlying type conforming to the given known protocol.
3098
+ static Type isRawRepresentable (Type fromType,
3099
+ KnownProtocolKind kind,
3100
+ ConstraintSystem *CS) {
3132
3101
auto rawReprType =
3133
3102
CS->TC .getProtocol (SourceLoc (), KnownProtocolKind::RawRepresentable);
3134
- if (!rawReprType) return ;
3103
+ if (!rawReprType)
3104
+ return Type ();
3135
3105
3136
- ProtocolConformance *rawReprConformance ;
3137
- if (!CS->TC .conformsToProtocol (contextualType , rawReprType, CS->DC ,
3106
+ ProtocolConformance *conformance ;
3107
+ if (!CS->TC .conformsToProtocol (fromType , rawReprType, CS->DC ,
3138
3108
ConformanceCheckFlags::InExpression,
3139
- &rawReprConformance ))
3140
- return ;
3109
+ &conformance ))
3110
+ return Type () ;
3141
3111
3142
- Type rawTy = ProtocolConformance::getTypeWitnessByName (contextualType ,
3143
- rawReprConformance ,
3112
+ Type rawTy = ProtocolConformance::getTypeWitnessByName (fromType ,
3113
+ conformance ,
3144
3114
CS->getASTContext ().getIdentifier (" RawValue" ),
3145
- &CS->TC );
3146
- if (!rawTy || !isIntegerType (rawTy))
3147
- return ;
3115
+ &CS->TC );
3116
+ if (!rawTy || !isLiteralConvertibleType (rawTy, kind, CS))
3117
+ return Type ();
3118
+
3119
+ return rawTy;
3120
+ }
3121
+
3122
+ // / Return true if the conversion from fromType to toType is an invalid string
3123
+ // / index operation.
3124
+ static bool isIntegerToStringIndexConversion (Type fromType, Type toType,
3125
+ ConstraintSystem *CS) {
3126
+ auto kind = KnownProtocolKind::IntegerLiteralConvertible;
3127
+ return (isLiteralConvertibleType (fromType, kind, CS) &&
3128
+ toType->getCanonicalType ().getString () == " String.CharacterView.Index" );
3129
+ }
3148
3130
3149
- std::string convWrapBefore = contextualType.getString ();
3150
- convWrapBefore += " (rawValue: " ;
3151
- std::string convWrapAfter = " )" ;
3152
- if (rawTy->getCanonicalType () != exprType->getCanonicalType ()) {
3153
- convWrapBefore += rawTy->getString ();
3154
- convWrapBefore += " (" ;
3155
- convWrapAfter += " )" ;
3156
- }
3157
- SourceRange exprRange = expr->getSourceRange ();
3158
- diag.fixItInsert (exprRange.Start , convWrapBefore);
3159
- diag.fixItInsertAfter (exprRange.End , convWrapAfter);
3131
+ // / Attempts to add fix-its for these two mistakes:
3132
+ // /
3133
+ // / - Passing an integer where a type conforming to RawRepresentable is
3134
+ // / expected, by wrapping the expression in a call to the contextual
3135
+ // / type's initializer
3136
+ // /
3137
+ // / - Passing a type conforming to RawRepresentable where an integer is
3138
+ // / expected, by wrapping the expression in a call to the rawValue
3139
+ // / accessor
3140
+ // /
3141
+ // / This helps migration with SDK changes.
3142
+ static void tryRawRepresentableFixIts (InFlightDiagnostic &diag,
3143
+ ConstraintSystem *CS,
3144
+ Diag<Type, Type> diagID,
3145
+ Type fromType,
3146
+ Type toType,
3147
+ KnownProtocolKind kind,
3148
+ Expr *expr) {
3149
+ if (isLiteralConvertibleType (fromType, kind, CS)) {
3150
+ if (auto rawTy = isRawRepresentable (toType, kind, CS)) {
3151
+ // Produce before/after strings like 'Result(rawValue: RawType(<expr>))'
3152
+ // or just 'Result(rawValue: <expr>)'.
3153
+ std::string convWrapBefore = toType.getString ();
3154
+ convWrapBefore += " (rawValue: " ;
3155
+ std::string convWrapAfter = " )" ;
3156
+ if (rawTy->getCanonicalType () != fromType->getCanonicalType ()) {
3157
+ convWrapBefore += rawTy->getString ();
3158
+ convWrapBefore += " (" ;
3159
+ convWrapAfter += " )" ;
3160
+ }
3161
+ SourceRange exprRange = expr->getSourceRange ();
3162
+ diag.fixItInsert (exprRange.Start , convWrapBefore);
3163
+ diag.fixItInsertAfter (exprRange.End , convWrapAfter);
3164
+ return ;
3165
+ }
3166
+ }
3167
+
3168
+ if (auto rawTy = isRawRepresentable (fromType, kind, CS)) {
3169
+ if (isLiteralConvertibleType (toType, kind, CS)) {
3170
+ std::string convWrapBefore;
3171
+ std::string convWrapAfter = " .rawValue" ;
3172
+ if (rawTy->getCanonicalType () != toType->getCanonicalType ()) {
3173
+ convWrapBefore += rawTy->getString ();
3174
+ convWrapBefore += " (" ;
3175
+ convWrapAfter += " )" ;
3176
+ }
3177
+ SourceRange exprRange = expr->getSourceRange ();
3178
+ diag.fixItInsert (exprRange.Start , convWrapBefore);
3179
+ diag.fixItInsertAfter (exprRange.End , convWrapAfter);
3180
+ return ;
3181
+ }
3182
+ }
3160
3183
}
3161
3184
3162
3185
bool FailureDiagnosis::diagnoseContextualConversionError () {
@@ -3387,10 +3410,29 @@ bool FailureDiagnosis::diagnoseContextualConversionError() {
3387
3410
diagID = diag::noescape_functiontype_mismatch;
3388
3411
}
3389
3412
3390
- InFlightDiagnostic diag = diagnose (expr->getLoc (), diagID, exprType, contextualType);
3413
+ InFlightDiagnostic diag = diagnose (expr->getLoc (), diagID,
3414
+ exprType, contextualType);
3391
3415
diag.highlight (expr->getSourceRange ());
3416
+
3392
3417
// Attempt to add a fixit for the error.
3393
- tryConversionFixit (diag, CS, diagID, exprType, contextualType, expr);
3418
+ switch (CS->getContextualTypePurpose ()) {
3419
+ case CTP_CallArgument:
3420
+ case CTP_ArrayElement:
3421
+ case CTP_DictionaryKey:
3422
+ case CTP_DictionaryValue:
3423
+ tryRawRepresentableFixIts (diag, CS, diagID, exprType, contextualType,
3424
+ KnownProtocolKind::IntegerLiteralConvertible,
3425
+ expr);
3426
+ tryRawRepresentableFixIts (diag, CS, diagID, exprType, contextualType,
3427
+ KnownProtocolKind::StringLiteralConvertible,
3428
+ expr);
3429
+ break ;
3430
+
3431
+ default :
3432
+ // FIXME: Other contextual conversions too?
3433
+ break ;
3434
+ }
3435
+
3394
3436
return true ;
3395
3437
}
3396
3438
0 commit comments