Skip to content

Commit fa92152

Browse files
authored
Merge pull request #4912 from jrose-apple/swift-3-fix-it-swift_newtype-rawValue
Use the existing '.rawValue' fix-it to handle unwrapping objects too.
2 parents ff8fa07 + 65d6432 commit fa92152

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
@@ -3569,15 +3569,14 @@ bool FailureDiagnosis::diagnoseCalleeResultContextualConversionError() {
35693569

35703570

35713571
/// Return true if the given type conforms to a known protocol type.
3572-
static bool isExpressibleByLiteralType(Type fromType,
3573-
KnownProtocolKind kind,
3574-
ConstraintSystem *CS) {
3575-
auto integerType =
3576-
CS->TC.getProtocol(SourceLoc(), kind);
3577-
if (!integerType)
3572+
static bool conformsToKnownProtocol(Type fromType,
3573+
KnownProtocolKind kind,
3574+
ConstraintSystem *CS) {
3575+
auto proto = CS->TC.getProtocol(SourceLoc(), kind);
3576+
if (!proto)
35783577
return false;
35793578

3580-
if (CS->TC.conformsToProtocol(fromType, integerType, CS->DC,
3579+
if (CS->TC.conformsToProtocol(fromType, proto, CS->DC,
35813580
ConformanceCheckFlags::InExpression)) {
35823581
return true;
35833582
}
@@ -3586,9 +3585,9 @@ static bool isExpressibleByLiteralType(Type fromType,
35863585
}
35873586

35883587
static bool isIntegerType(Type fromType, ConstraintSystem *CS) {
3589-
return isExpressibleByLiteralType(fromType,
3590-
KnownProtocolKind::ExpressibleByIntegerLiteral,
3591-
CS);
3588+
return conformsToKnownProtocol(fromType,
3589+
KnownProtocolKind::ExpressibleByIntegerLiteral,
3590+
CS);
35923591
}
35933592

35943593
/// Return true if the given type conforms to RawRepresentable.
@@ -3618,7 +3617,7 @@ static Type isRawRepresentable(Type fromType,
36183617
KnownProtocolKind kind,
36193618
ConstraintSystem *CS) {
36203619
Type rawTy = isRawRepresentable(fromType, CS);
3621-
if (!rawTy || !isExpressibleByLiteralType(rawTy, kind, CS))
3620+
if (!rawTy || !conformsToKnownProtocol(rawTy, kind, CS))
36223621
return Type();
36233622

36243623
return rawTy;
@@ -3629,7 +3628,7 @@ static Type isRawRepresentable(Type fromType,
36293628
static bool isIntegerToStringIndexConversion(Type fromType, Type toType,
36303629
ConstraintSystem *CS) {
36313630
auto kind = KnownProtocolKind::ExpressibleByIntegerLiteral;
3632-
return (isExpressibleByLiteralType(fromType, kind, CS) &&
3631+
return (conformsToKnownProtocol(fromType, kind, CS) &&
36333632
toType->getCanonicalType().getString() == "String.CharacterView.Index");
36343633
}
36353634

@@ -3684,14 +3683,23 @@ static bool tryRawRepresentableFixIts(InFlightDiagnostic &diag,
36843683
}
36853684
};
36863685

3687-
if (isExpressibleByLiteralType(fromType, kind, CS)) {
3686+
if (conformsToKnownProtocol(fromType, kind, CS)) {
36883687
if (auto rawTy = isRawRepresentable(toType, kind, CS)) {
36893688
// Produce before/after strings like 'Result(rawValue: RawType(<expr>))'
36903689
// or just 'Result(rawValue: <expr>)'.
36913690
std::string convWrapBefore = toType.getString();
36923691
convWrapBefore += "(rawValue: ";
36933692
std::string convWrapAfter = ")";
3694-
if (rawTy->getCanonicalType() != fromType->getCanonicalType()) {
3693+
if (!CS->TC.isConvertibleTo(fromType, rawTy, CS->DC)) {
3694+
// Only try to insert a converting construction if the protocol is a
3695+
// literal protocol and not some other known protocol.
3696+
switch (kind) {
3697+
#define EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME(name, _) \
3698+
case KnownProtocolKind::name: break;
3699+
#define PROTOCOL_WITH_NAME(name, _) \
3700+
case KnownProtocolKind::name: return false;
3701+
#include "swift/AST/KnownProtocols.def"
3702+
}
36953703
convWrapBefore += rawTy->getString();
36963704
convWrapBefore += "(";
36973705
convWrapAfter += ")";
@@ -3702,11 +3710,20 @@ static bool tryRawRepresentableFixIts(InFlightDiagnostic &diag,
37023710
}
37033711

37043712
if (auto rawTy = isRawRepresentable(fromType, kind, CS)) {
3705-
if (isExpressibleByLiteralType(toType, kind, CS)) {
3713+
if (conformsToKnownProtocol(toType, kind, CS)) {
37063714
std::string convWrapBefore;
37073715
std::string convWrapAfter = ".rawValue";
3708-
if (rawTy->getCanonicalType() != toType->getCanonicalType()) {
3709-
convWrapBefore += rawTy->getString();
3716+
if (!CS->TC.isConvertibleTo(rawTy, toType, CS->DC)) {
3717+
// Only try to insert a converting construction if the protocol is a
3718+
// literal protocol and not some other known protocol.
3719+
switch (kind) {
3720+
#define EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME(name, _) \
3721+
case KnownProtocolKind::name: break;
3722+
#define PROTOCOL_WITH_NAME(name, _) \
3723+
case KnownProtocolKind::name: return false;
3724+
#include "swift/AST/KnownProtocols.def"
3725+
}
3726+
convWrapBefore += toType->getString();
37103727
convWrapBefore += "(";
37113728
convWrapAfter += ")";
37123729
}
@@ -4167,6 +4184,9 @@ bool FailureDiagnosis::diagnoseContextualConversionError() {
41674184
tryRawRepresentableFixIts(diag, CS, exprType, contextualType,
41684185
KnownProtocolKind::ExpressibleByStringLiteral,
41694186
expr) ||
4187+
tryRawRepresentableFixIts(diag, CS, exprType, contextualType,
4188+
KnownProtocolKind::AnyObject,
4189+
expr) ||
41704190
tryIntegerCastFixIts(diag, CS, exprType, contextualType, expr) ||
41714191
addTypeCoerceFixit(diag, CS, exprType, contextualType, expr);
41724192
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)