Skip to content

Commit 55bf215

Browse files
committed
[sema] When the error is "cannot convert value of type <integer> to expected argument type <RawRepresentable>" add a fixit.
The fixit constructs the raw-representable type from the value. This helps with SDK changes.
1 parent 19f72c8 commit 55bf215

File tree

3 files changed

+84
-2
lines changed

3 files changed

+84
-2
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3096,6 +3096,63 @@ static bool isIntegerToStringIndexConversion(Type fromType, Type toType,
30963096
return false;
30973097
}
30983098

3099+
static void tryConversionFixit(InFlightDiagnostic &diag,
3100+
ConstraintSystem *CS,
3101+
Diag<Type, Type> diagID,
3102+
Type exprType,
3103+
Type contextualType,
3104+
Expr *expr) {
3105+
if (!CS || !expr || !exprType || !contextualType)
3106+
return;
3107+
if (diagID.ID != diag::cannot_convert_argument_value.ID)
3108+
return;
3109+
3110+
auto integerType =
3111+
CS->TC.getProtocol(SourceLoc(),
3112+
KnownProtocolKind::IntegerLiteralConvertible);
3113+
if (!integerType) return;
3114+
3115+
auto isIntegerType = [&](Type ty) -> bool {
3116+
return CS->TC.conformsToProtocol(exprType, integerType, CS->DC,
3117+
ConformanceCheckFlags::InExpression);
3118+
};
3119+
3120+
// When the error is "cannot convert value of type <integer> to expected
3121+
// argument type <RawRepresentable>", add a fixit that constructs the
3122+
// raw-representable type from the value. This helps with SDK changes.
3123+
3124+
if (!isIntegerType(exprType))
3125+
return;
3126+
3127+
auto rawReprType =
3128+
CS->TC.getProtocol(SourceLoc(), KnownProtocolKind::RawRepresentable);
3129+
if (!rawReprType) return;
3130+
3131+
ProtocolConformance *rawReprConformance;
3132+
if (!CS->TC.conformsToProtocol(contextualType, rawReprType, CS->DC,
3133+
ConformanceCheckFlags::InExpression,
3134+
&rawReprConformance))
3135+
return;
3136+
3137+
Type rawTy = ProtocolConformance::getTypeWitnessByName(contextualType,
3138+
rawReprConformance,
3139+
CS->getASTContext().getIdentifier("RawValue"),
3140+
&CS->TC);
3141+
if (!rawTy || !isIntegerType(rawTy))
3142+
return;
3143+
3144+
std::string convWrapBefore = contextualType.getString();
3145+
convWrapBefore += "(rawValue: ";
3146+
std::string convWrapAfter = ")";
3147+
if (rawTy->getCanonicalType() != exprType->getCanonicalType()) {
3148+
convWrapBefore += rawTy->getString();
3149+
convWrapBefore += "(";
3150+
convWrapAfter += ")";
3151+
}
3152+
SourceRange exprRange = expr->getSourceRange();
3153+
diag.fixItInsert(exprRange.Start, convWrapBefore);
3154+
diag.fixItInsertAfter(exprRange.End, convWrapAfter);
3155+
}
30993156

31003157
bool FailureDiagnosis::diagnoseContextualConversionError() {
31013158
// If the constraint system has a contextual type, then we can test to see if
@@ -3325,8 +3382,9 @@ bool FailureDiagnosis::diagnoseContextualConversionError() {
33253382
diagID = diag::noescape_functiontype_mismatch;
33263383
}
33273384

3328-
diagnose(expr->getLoc(), diagID, exprType, contextualType)
3329-
.highlight(expr->getSourceRange());
3385+
InFlightDiagnostic diag = diagnose(expr->getLoc(), diagID, exprType, contextualType);
3386+
diag.highlight(expr->getSourceRange());
3387+
tryConversionFixit(diag, CS, diagID, exprType, contextualType, expr);
33303388
return true;
33313389
}
33323390

test/FixCode/fixits-apply.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@ func supported() -> MyMask {
3131
return Int(MyMask.Bingo.rawValue)
3232
}
3333

34+
struct MyEventMask2 : OptionSet {
35+
init(rawValue: UInt64) {}
36+
var rawValue: UInt64 { return 0 }
37+
}
38+
func sendIt(_: MyEventMask2) {}
39+
func testMask1(a: Int) {
40+
sendIt(a)
41+
}
42+
func testMask2(a: UInt64) {
43+
sendIt(a)
44+
}
45+
3446
func goo(var e : ErrorProtocol) {
3547
}
3648
func goo2(var e: ErrorProtocol) {}

test/FixCode/fixits-apply.swift.result

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@ func supported() -> MyMask {
3131
return MyMask.Bingo
3232
}
3333

34+
struct MyEventMask2 : OptionSet {
35+
init(rawValue: UInt64) {}
36+
var rawValue: UInt64 { return 0 }
37+
}
38+
func sendIt(_: MyEventMask2) {}
39+
func testMask1(a: Int) {
40+
sendIt(MyEventMask2(rawValue: UInt64(a)))
41+
}
42+
func testMask2(a: UInt64) {
43+
sendIt(MyEventMask2(rawValue: a))
44+
}
45+
3446
func goo(e : ErrorProtocol) {
3547
var e = e
3648
}

0 commit comments

Comments
 (0)