Skip to content

Commit 821cdf3

Browse files
authored
Merge pull request #4910 from jrose-apple/fix-it-swift_newtype-rawValue
Use the existing '.rawValue' fix-it to handle unwrapping objects too. rdar://problem/26678862
2 parents 00d0b55 + 693fd9d commit 821cdf3

File tree

3 files changed

+85
-19
lines changed

3 files changed

+85
-19
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3582,15 +3582,14 @@ bool FailureDiagnosis::diagnoseCalleeResultContextualConversionError() {
35823582

35833583

35843584
/// Return true if the given type conforms to a known protocol type.
3585-
static bool isExpressibleByLiteralType(Type fromType,
3586-
KnownProtocolKind kind,
3587-
ConstraintSystem *CS) {
3588-
auto integerType =
3589-
CS->TC.getProtocol(SourceLoc(), kind);
3590-
if (!integerType)
3585+
static bool conformsToKnownProtocol(Type fromType,
3586+
KnownProtocolKind kind,
3587+
ConstraintSystem *CS) {
3588+
auto proto = CS->TC.getProtocol(SourceLoc(), kind);
3589+
if (!proto)
35913590
return false;
35923591

3593-
if (CS->TC.conformsToProtocol(fromType, integerType, CS->DC,
3592+
if (CS->TC.conformsToProtocol(fromType, proto, CS->DC,
35943593
ConformanceCheckFlags::InExpression)) {
35953594
return true;
35963595
}
@@ -3599,9 +3598,9 @@ static bool isExpressibleByLiteralType(Type fromType,
35993598
}
36003599

36013600
static bool isIntegerType(Type fromType, ConstraintSystem *CS) {
3602-
return isExpressibleByLiteralType(fromType,
3603-
KnownProtocolKind::ExpressibleByIntegerLiteral,
3604-
CS);
3601+
return conformsToKnownProtocol(fromType,
3602+
KnownProtocolKind::ExpressibleByIntegerLiteral,
3603+
CS);
36053604
}
36063605

36073606
/// Return true if the given type conforms to RawRepresentable.
@@ -3631,7 +3630,7 @@ static Type isRawRepresentable(Type fromType,
36313630
KnownProtocolKind kind,
36323631
ConstraintSystem *CS) {
36333632
Type rawTy = isRawRepresentable(fromType, CS);
3634-
if (!rawTy || !isExpressibleByLiteralType(rawTy, kind, CS))
3633+
if (!rawTy || !conformsToKnownProtocol(rawTy, kind, CS))
36353634
return Type();
36363635

36373636
return rawTy;
@@ -3642,7 +3641,7 @@ static Type isRawRepresentable(Type fromType,
36423641
static bool isIntegerToStringIndexConversion(Type fromType, Type toType,
36433642
ConstraintSystem *CS) {
36443643
auto kind = KnownProtocolKind::ExpressibleByIntegerLiteral;
3645-
return (isExpressibleByLiteralType(fromType, kind, CS) &&
3644+
return (conformsToKnownProtocol(fromType, kind, CS) &&
36463645
toType->getCanonicalType().getString() == "String.CharacterView.Index");
36473646
}
36483647

@@ -3697,14 +3696,23 @@ static bool tryRawRepresentableFixIts(InFlightDiagnostic &diag,
36973696
}
36983697
};
36993698

3700-
if (isExpressibleByLiteralType(fromType, kind, CS)) {
3699+
if (conformsToKnownProtocol(fromType, kind, CS)) {
37013700
if (auto rawTy = isRawRepresentable(toType, kind, CS)) {
37023701
// Produce before/after strings like 'Result(rawValue: RawType(<expr>))'
37033702
// or just 'Result(rawValue: <expr>)'.
37043703
std::string convWrapBefore = toType.getString();
37053704
convWrapBefore += "(rawValue: ";
37063705
std::string convWrapAfter = ")";
3707-
if (rawTy->getCanonicalType() != fromType->getCanonicalType()) {
3706+
if (!CS->TC.isConvertibleTo(fromType, rawTy, CS->DC)) {
3707+
// Only try to insert a converting construction if the protocol is a
3708+
// literal protocol and not some other known protocol.
3709+
switch (kind) {
3710+
#define EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME(name, _) \
3711+
case KnownProtocolKind::name: break;
3712+
#define PROTOCOL_WITH_NAME(name, _) \
3713+
case KnownProtocolKind::name: return false;
3714+
#include "swift/AST/KnownProtocols.def"
3715+
}
37083716
convWrapBefore += rawTy->getString();
37093717
convWrapBefore += "(";
37103718
convWrapAfter += ")";
@@ -3715,11 +3723,20 @@ static bool tryRawRepresentableFixIts(InFlightDiagnostic &diag,
37153723
}
37163724

37173725
if (auto rawTy = isRawRepresentable(fromType, kind, CS)) {
3718-
if (isExpressibleByLiteralType(toType, kind, CS)) {
3726+
if (conformsToKnownProtocol(toType, kind, CS)) {
37193727
std::string convWrapBefore;
37203728
std::string convWrapAfter = ".rawValue";
3721-
if (rawTy->getCanonicalType() != toType->getCanonicalType()) {
3722-
convWrapBefore += rawTy->getString();
3729+
if (!CS->TC.isConvertibleTo(rawTy, toType, CS->DC)) {
3730+
// Only try to insert a converting construction if the protocol is a
3731+
// literal protocol and not some other known protocol.
3732+
switch (kind) {
3733+
#define EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME(name, _) \
3734+
case KnownProtocolKind::name: break;
3735+
#define PROTOCOL_WITH_NAME(name, _) \
3736+
case KnownProtocolKind::name: return false;
3737+
#include "swift/AST/KnownProtocols.def"
3738+
}
3739+
convWrapBefore += toType->getString();
37233740
convWrapBefore += "(";
37243741
convWrapAfter += ")";
37253742
}
@@ -4180,6 +4197,9 @@ bool FailureDiagnosis::diagnoseContextualConversionError() {
41804197
tryRawRepresentableFixIts(diag, CS, exprType, contextualType,
41814198
KnownProtocolKind::ExpressibleByStringLiteral,
41824199
expr) ||
4200+
tryRawRepresentableFixIts(diag, CS, exprType, contextualType,
4201+
KnownProtocolKind::AnyObject,
4202+
expr) ||
41834203
tryIntegerCastFixIts(diag, CS, exprType, contextualType, expr) ||
41844204
addTypeCoerceFixit(diag, CS, exprType, contextualType, expr);
41854205
break;

test/FixCode/fixits-apply.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,29 @@ func testConvertSomeName(s: String) {
9696
testPassSomeName("\(s)}")
9797
}
9898

99+
class WrappedClass {}
100+
class WrappedClassSub: WrappedClass {}
101+
struct ClassWrapper : RawRepresentable {
102+
var rawValue: WrappedClass
103+
}
104+
func testPassAnyObject(_: AnyObject) {}
105+
func testPassAnyObjectOpt(_: AnyObject?) {}
106+
func testPassWrappedSub(_: WrappedClassSub) {}
107+
func testConvertClassWrapper(_ x: ClassWrapper, _ sub: WrappedClassSub) {
108+
testPassAnyObject(x)
109+
testPassAnyObjectOpt(x)
110+
testPassWrappedSub(x)
111+
112+
let iuo: ClassWrapper! = x
113+
testPassAnyObject(iuo)
114+
testPassAnyObjectOpt(iuo)
115+
116+
let _: ClassWrapper = sub
117+
let _: ClassWrapper = x.rawValue
118+
// FIXME: This one inserts 'as!', which is incorrect.
119+
let _: ClassWrapper = sub as AnyObject
120+
}
121+
99122
enum MyEnumType : UInt32 {
100123
case invalid
101124
}

test/FixCode/fixits-apply.swift.result

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func testMask2(a: UInt64) {
4545
sendIt(MyEventMask2(rawValue: a))
4646
}
4747
func testMask3(a: MyEventMask2) {
48-
testMask1(a: UInt64(a.rawValue))
48+
testMask1(a: Int(a.rawValue))
4949
}
5050
func testMask4(a: MyEventMask2) {
5151
testMask2(a: a.rawValue)
@@ -69,7 +69,7 @@ func testMask10(a: Int?) {
6969
sendIt(a) // no fix, nullability mismatch.
7070
}
7171
func testMask11(a: MyEventMask2?) {
72-
testMask7(a: a.map { UInt64($0.rawValue) })
72+
testMask7(a: a.map { Int($0.rawValue) })
7373
}
7474
func testMask12(a: MyEventMask2?) {
7575
testMask8(a: a.map { $0.rawValue })
@@ -96,6 +96,29 @@ func testConvertSomeName(s: String) {
9696
testPassSomeName(SomeName(rawValue: "\(s)}"))
9797
}
9898

99+
class WrappedClass {}
100+
class WrappedClassSub: WrappedClass {}
101+
struct ClassWrapper : RawRepresentable {
102+
var rawValue: WrappedClass
103+
}
104+
func testPassAnyObject(_: AnyObject) {}
105+
func testPassAnyObjectOpt(_: AnyObject?) {}
106+
func testPassWrappedSub(_: WrappedClassSub) {}
107+
func testConvertClassWrapper(_ x: ClassWrapper, _ sub: WrappedClassSub) {
108+
testPassAnyObject(x.rawValue)
109+
testPassAnyObjectOpt(x.rawValue)
110+
testPassWrappedSub(x)
111+
112+
let iuo: ClassWrapper! = x
113+
testPassAnyObject(iuo)
114+
testPassAnyObjectOpt(iuo.map { $0.rawValue })
115+
116+
let _: ClassWrapper = ClassWrapper(rawValue: sub)
117+
let _: ClassWrapper = ClassWrapper(rawValue: x.rawValue)
118+
// FIXME: This one inserts 'as!', which is incorrect.
119+
let _: ClassWrapper = sub as AnyObject as! ClassWrapper
120+
}
121+
99122
enum MyEnumType : UInt32 {
100123
case invalid
101124
}

0 commit comments

Comments
 (0)