Skip to content

Commit b6de061

Browse files
committedAug 22, 2015
Rework assignment diagnostics to be built in terms of contextual types,
where we type check the destination first, then apply its type to the source. This allows us to get diagnostics for assignments that are as good as PBD initializers and other cases. Swift SVN r31404
1 parent 6402fda commit b6de061

35 files changed

+122
-118
lines changed
 

‎include/swift/AST/DiagnosticsSema.def

+9-5
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,6 @@ ERROR(cannot_subscript_base,sema,none,
150150
"cannot subscript a value of type %0",
151151
(Type))
152152

153-
154-
ERROR(cannot_assign_values,sema,none,
155-
"cannot assign a value of type %0 to a value of type %1",
156-
(Type, Type))
157-
158153
ERROR(cannot_pass_rvalue_inout_subelement,sema_tcs,none,
159154
"cannot pass immutable value as inout argument: %0",
160155
(StringRef))
@@ -297,6 +292,15 @@ ERROR(cannot_convert_coerce_protocol,sema_tcd,none,
297292
ERROR(cannot_convert_coerce_nil,sema,none,
298293
"nil is not compatible with type %0 in coercion", (Type))
299294

295+
// Assign Expr
296+
ERROR(cannot_convert_assign,sema,none,
297+
"cannot assign value of type %0 to type %1",
298+
(Type,Type))
299+
ERROR(cannot_convert_assign_protocol,sema_tcd,none,
300+
"value of type %0 does not conform to %1 in assignment",
301+
(Type, Type))
302+
ERROR(cannot_convert_assign_nil,sema,none,
303+
"nil cannot be assigned to type %0", (Type))
300304

301305

302306
ERROR(throws_functiontype_mismatch,sema_tcc,none,

‎lib/Sema/CSDiag.cpp

+13-17
Original file line numberDiff line numberDiff line change
@@ -2975,6 +2975,11 @@ bool FailureDiagnosis::diagnoseContextualConversionError() {
29752975
diagIDProtocol = diag::cannot_convert_coerce_protocol;
29762976
nilDiag = diag::cannot_convert_coerce_nil;
29772977
break;
2978+
case CTP_AssignSource:
2979+
diagID = diag::cannot_convert_assign;
2980+
diagIDProtocol = diag::cannot_convert_assign_protocol;
2981+
nilDiag = diag::cannot_convert_assign_nil;
2982+
break;
29782983
}
29792984

29802985
// If we're diagnostic an issue with 'nil', produce a specific diagnostic,
@@ -3554,34 +3559,25 @@ bool FailureDiagnosis::visitAssignExpr(AssignExpr *assignExpr) {
35543559
return true;
35553560
}
35563561

3557-
// FIXME: Should check dest expr first, then contextually convert the source
3558-
// to it.
3559-
3560-
// If the source type is already an error type, we've already posted an error.
3561-
auto srcExpr = typeCheckChildIndependently(assignExpr->getSrc());
3562-
if (!srcExpr) return true;
3563-
3562+
// Type check the destination first, so we can coerce the source to it.
35643563
auto destExpr = typeCheckChildIndependently(assignExpr->getDest(),
35653564
TCC_AllowLValue);
35663565
if (!destExpr) return true;
35673566

3568-
auto destType = destExpr->getType();
3569-
auto srcType = srcExpr->getType();
3570-
35713567
// If the result type is a non-lvalue, then we are failing because it is
35723568
// immutable and that's not a great thing to assign to.
3569+
auto destType = destExpr->getType();
35733570
if (!destType->isLValueType()) {
35743571
CS->diagnoseAssignmentFailure(destExpr, destType, assignExpr->getLoc());
35753572
return true;
35763573
}
35773574

3578-
// If the two types are ok, it must be a contextual problem.
3579-
if (srcType->isEqual(destType->getRValueType()))
3580-
return false;
3581-
3582-
diagnose(srcExpr->getLoc(), diag::cannot_assign_values, srcType,
3583-
destType->getRValueType());
3584-
return true;
3575+
// If the source type is already an error type, we've already posted an error.
3576+
auto srcExpr = typeCheckChildIndependently(assignExpr->getSrc(),
3577+
destType->getLValueOrInOutObjectType(),
3578+
CTP_AssignSource);
3579+
if (!srcExpr) return true;
3580+
return false;
35853581
}
35863582

35873583
bool FailureDiagnosis::visitInOutExpr(InOutExpr *IOE) {

‎lib/Sema/TypeChecker.h

+1
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ enum ContextualTypePurpose {
155155
CTP_DictionaryKey, ///< DictionaryExpr keys should have a specific type.
156156
CTP_DictionaryValue, ///< DictionaryExpr values should have a specific type.
157157
CTP_CoerceOperand, ///< CoerceExpr operand coerced to specific type.
158+
CTP_AssignSource, ///< AssignExpr source operand coerced to result type.
158159

159160
CTP_CannotFail, ///< Conversion can never fail. abort() if it does.
160161
};

‎test/ClangModules/ctypes_parse.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ func testFunctionPointers() {
256256
= getFunctionPointer2()
257257

258258
useFunctionPointer2(anotherFP)
259-
anotherFP = fp // expected-error {{cannot assign a value of type 'fptr!' to a value of type '@convention(c) (CInt, CLong, UnsafeMutablePointer<Void>) -> Void'}}
259+
anotherFP = fp // expected-error {{cannot assign value of type 'fptr!' to type '@convention(c) (CInt, CLong, UnsafeMutablePointer<Void>) -> Void'}}
260260
}
261261

262262
func testStructDefaultInit() {

‎test/ClangModules/objc_parse.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ func testProtocols(b: B, bp: BProto) {
193193
var c1 : Cat1Proto = b
194194
var bcat1 = b.getAsProtoWithCat()
195195
c1 = bcat1
196-
bcat1 = c1 // expected-error{{cannot assign a value of type 'Cat1Proto' to a value of type 'protocol<BProto, Cat1Proto>!'}}
196+
bcat1 = c1 // expected-error{{cannot assign value of type 'Cat1Proto' to type 'protocol<BProto, Cat1Proto>!'}}
197197
}
198198

199199
// Methods only defined in a protocol

‎test/Constraints/assignment.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ i = j
4040
_ = (i, f)
4141
slice[7] = i
4242

43-
slice[7] = f // expected-error{{cannot assign a value of type 'Y' to a value of type 'X'}}
43+
slice[7] = f // expected-error{{cannot assign value of type 'Y' to type 'X'}}
4444

4545
slice[7] = _ // expected-error{{'_' can only appear in a pattern or on the left side of an assignment}}
4646

‎test/Constraints/bridging.swift

+6-6
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func arrayToNSArray() {
8282
nsa = [BridgedClass]()
8383
nsa = [OtherClass]()
8484
nsa = [BridgedStruct]()
85-
nsa = [NotBridgedStruct]() // expected-error{{cannot assign a value of type '[NotBridgedStruct]' to a value of type 'NSArray'}}
85+
nsa = [NotBridgedStruct]() // expected-error{{cannot assign value of type '[NotBridgedStruct]' to type 'NSArray'}}
8686

8787
nsa = [AnyObject]() as NSArray
8888
nsa = [BridgedClass]() as NSArray
@@ -124,12 +124,12 @@ func dictionaryToNSDictionary() {
124124
nsd = [NSObject : OtherClass]() as NSDictionary
125125
nsd = [NSObject : BridgedStruct]()
126126
nsd = [NSObject : BridgedStruct]() as NSDictionary
127-
nsd = [NSObject : NotBridgedStruct]() // expected-error{{cannot assign a value of type '[NSObject : NotBridgedStruct]' to a value of type 'NSDictionary'}}
127+
nsd = [NSObject : NotBridgedStruct]() // expected-error{{cannot assign value of type '[NSObject : NotBridgedStruct]' to type 'NSDictionary'}}
128128
nsd = [NSObject : NotBridgedStruct]() as NSDictionary // expected-error{{cannot convert value of type '[NSObject : NotBridgedStruct]' to type 'NSDictionary' in coercion}}
129129

130-
nsd = [NSObject : BridgedClass?]() // expected-error{{cannot assign a value of type '[NSObject : BridgedClass?]' to a value of type 'NSDictionary'}}
130+
nsd = [NSObject : BridgedClass?]() // expected-error{{cannot assign value of type '[NSObject : BridgedClass?]' to type 'NSDictionary'}}
131131
nsd = [NSObject : BridgedClass?]() as NSDictionary // expected-error{{cannot convert value of type '[NSObject : BridgedClass?]' to type 'NSDictionary' in coercion}}
132-
nsd = [NSObject : BridgedStruct?]() // expected-error{{cannot assign a value of type '[NSObject : BridgedStruct?]' to a value of type 'NSDictionary'}}
132+
nsd = [NSObject : BridgedStruct?]() // expected-error{{cannot assign value of type '[NSObject : BridgedStruct?]' to type 'NSDictionary'}}
133133
nsd = [NSObject : BridgedStruct?]() as NSDictionary //expected-error{{cannot convert value of type '[NSObject : BridgedStruct?]' to type 'NSDictionary' in coercion}}
134134

135135
nsd = [BridgedClass : AnyObject]()
@@ -138,12 +138,12 @@ func dictionaryToNSDictionary() {
138138
nsd = [OtherClass : AnyObject]() as NSDictionary
139139
nsd = [BridgedStruct : AnyObject]()
140140
nsd = [BridgedStruct : AnyObject]() as NSDictionary
141-
nsd = [NotBridgedStruct : AnyObject]() // expected-error{{cannot assign a value of type '[NotBridgedStruct : AnyObject]' to a value of type 'NSDictionary'}}
141+
nsd = [NotBridgedStruct : AnyObject]() // expected-error{{cannot assign value of type '[NotBridgedStruct : AnyObject]' to type 'NSDictionary'}}
142142
nsd = [NotBridgedStruct : AnyObject]() as NSDictionary // expected-error{{cannot convert value of type '[NotBridgedStruct : AnyObject]' to type 'NSDictionary' in coercion}}
143143

144144
// <rdar://problem/17134986>
145145
var bcOpt: BridgedClass?
146-
nsd = [BridgedStruct() : bcOpt] // expected-error{{cannot assign a value of type '[BridgedStruct : BridgedClass?]' to a value of type 'NSDictionary'}}
146+
nsd = [BridgedStruct() : bcOpt] // expected-error{{value of optional type 'BridgedClass?' not unwrapped; did you mean to use '!' or '?'?}}
147147
bcOpt = nil
148148
_ = nsd
149149
}

‎test/Constraints/diagnostics.swift

+4-4
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ var afterMessageCount : Int? = nil
376376
func uintFunc() -> UInt {}
377377
func takeVoidVoidFn(a : () -> ()) {}
378378
takeVoidVoidFn { () -> Void in
379-
afterMessageCount = uintFunc() // expected-error {{cannot assign a value of type 'UInt' to a value of type 'Int?'}}
379+
afterMessageCount = uintFunc() // expected-error {{cannot assign value of type 'UInt' to type 'Int?'}}
380380
}
381381

382382
// <rdar://problem/19997471> Swift: Incorrect compile error when calling a function inside a closure
@@ -425,7 +425,7 @@ zip(numbers, numbers).filter { $0.2 > 1 } // expected-error {{value of tuple ty
425425
func foo20868864(callback: ([String]) -> ()) { }
426426
func rdar20868864(var s: String) {
427427
foo20868864 { (strings: [String]) in
428-
s = strings // expected-error {{cannot assign a value of type '[String]' to a value of type 'String'}}
428+
s = strings // expected-error {{cannot assign value of type '[String]' to type 'String'}}
429429
}
430430
}
431431

@@ -459,8 +459,8 @@ let _: Color = .overload(1) // expected-error {{ambiguous reference to member '
459459
let _: Color = .frob(1.0, &i) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
460460
let _: Color = .frob(1, i) // expected-error {{passing value of type 'Int' to an inout parameter requires explicit '&'}}
461461
let _: Color = .frob(1, &d) // expected-error {{cannot convert value of type 'inout Double' to expected argument type 'inout Int'}}
462-
let _ : Color = .red // expected-error {{type 'Color' has no member 'red'}}
463-
462+
var someColor : Color = .red // expected-error {{type 'Color' has no member 'red'}}
463+
someColor = .red // expected-error {{type 'Color' has no member 'red'}}
464464

465465
func testTypeSugar(a : Int) {
466466
typealias Stride = Int

‎test/Constraints/errortype_bridging.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ var ns4 = compo as NSError
3434

3535
// NSError conversion must be explicit.
3636
// TODO: fixit to insert 'as NSError'
37-
ns4 = compo // expected-error{{cannot assign a value of type 'protocol<HairyErrorType, Runcible>' to a value of type 'NSError'}}
37+
ns4 = compo // expected-error{{cannot assign value of type 'protocol<HairyErrorType, Runcible>' to type 'NSError'}}
3838

3939
let e1 = ns1 as? FooError
4040
let e1fix = ns1 as FooError // expected-error{{did you mean to use 'as!'}} {{17-19=as!}}

‎test/Constraints/existential_metatypes.swift

+9-9
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,23 @@ var qp: Q.Protocol
1010
var pp: P.Protocol = qp // expected-error{{cannot convert value of type 'Q.Protocol' to specified type 'P.Protocol'}}
1111

1212
var qt: Q.Type
13-
qt = qp // expected-error{{cannot assign a value of type 'Q.Protocol' to a value of type 'Q.Type'}}
14-
qp = qt // expected-error{{cannot assign a value of type 'Q.Type' to a value of type 'Q.Protocol'}}
13+
qt = qp // expected-error{{cannot assign value of type 'Q.Protocol' to type 'Q.Type'}}
14+
qp = qt // expected-error{{cannot assign value of type 'Q.Type' to type 'Q.Protocol'}}
1515
var pt: P.Type = qt // expected-error{{cannot convert value of type 'Q.Type' to specified type 'P.Type'}}
16-
pt = pp // expected-error{{cannot assign a value of type 'P.Protocol' to a value of type 'P.Type'}}
17-
pp = pt // expected-error{{cannot assign a value of type 'P.Type' to a value of type 'P.Protocol'}}
16+
pt = pp // expected-error{{cannot assign value of type 'P.Protocol' to type 'P.Type'}}
17+
pp = pt // expected-error{{cannot assign value of type 'P.Type' to type 'P.Protocol'}}
1818

1919
var pqt: protocol<P, Q>.Type
2020
pt = pqt
2121
qt = pqt
2222

2323

2424
var pqp: protocol<P, Q>.Protocol
25-
pp = pqp // expected-error{{cannot assign}}
26-
qp = pqp // expected-error{{cannot assign}}
25+
pp = pqp // expected-error{{cannot assign value of type 'protocol<P, Q>.Protocol' to type 'P.Protocol'}}
26+
qp = pqp // expected-error{{cannot assign value of type 'protocol<P, Q>.Protocol' to type 'Q.Protocol'}}
2727

2828
var ppp: PP.Protocol
29-
pp = ppp // expected-error{{cannot assign}}
29+
pp = ppp // expected-error{{cannot assign value of type 'PP.Protocol' to type 'P.Protocol'}}
3030

3131
var ppt: PP.Type
3232
pt = ppt
@@ -35,8 +35,8 @@ var at: Any.Type
3535
at = pt
3636

3737
var ap: Any.Protocol
38-
ap = pp // expected-error{{cannot assign}}
39-
ap = pt // expected-error{{cannot assign}}
38+
ap = pp // expected-error{{cannot assign value of type 'P.Protocol' to type 'Any.Protocol' (aka 'protocol<>.Protocol')}}
39+
ap = pt // expected-error{{cannot assign value of type 'P.Type' to type 'Any.Protocol' (aka 'protocol<>.Protocol')}}
4040

4141
// Meta-metatypes
4242

‎test/Generics/deduction.swift

+6-4
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
func identity<T>(value: T) -> T { return value }
88

9-
func identity2<T>(value: T) -> T { return value } // expected-note {{found this candidate}}
10-
func identity2<T>(value: T) -> Int { return 0 } // expected-note {{found this candidate}}
9+
func identity2<T>(value: T) -> T { return value }
10+
func identity2<T>(value: T) -> Int { return 0 }
1111

1212
struct X { }
1313
struct Y { }
@@ -24,8 +24,10 @@ func useIdentity(x: Int, y: Float, i32: Int32) {
2424
// FIXME: Is this actually the behavior we want? It's strange that these
2525
// two have different behavior.
2626
var xx : X, yy : Y
27-
xx = identity(yy) // expected-error{{cannot assign a value of type 'Y' to a value of type 'X'}}
28-
xx = identity2(yy) // expected-error{{ambiguous use of 'identity2'}}
27+
xx = identity(yy) // expected-error{{cannot invoke 'identity' with an argument list of type '(Y)'}}
28+
// expected-note @-1 {{expected an argument list of type '(T)'}}
29+
xx = identity2(yy) // expected-error{{cannot invoke 'identity2' with an argument list of type '(Y)'}}
30+
// expected-note @-1 {{expected an argument list of type '(T)'}}
2931
}
3032

3133
// FIXME: Crummy diagnostic!

‎test/Generics/function_defs.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ protocol OtherEqualComparable {
4848

4949
func otherExistential<T : EqualComparable>(t1: T) {
5050
var otherEqComp : OtherEqualComparable = t1 // expected-error{{value of type 'T' does not conform to specified type 'OtherEqualComparable'}} expected-error{{protocol 'OtherEqualComparable' can only be used as a generic constraint}}
51-
otherEqComp = t1 // expected-error{{cannot assign a value of type 'T' to a value of type 'OtherEqualComparable'}}
51+
otherEqComp = t1 // expected-error{{value of type 'T' does not conform to 'OtherEqualComparable' in assignment}}
5252
_ = otherEqComp
5353

5454
var otherEqComp2 : OtherEqualComparable // expected-error{{protocol 'OtherEqualComparable' can only be used as a generic constraint}}
55-
otherEqComp2 = t1 // expected-error{{cannot assign a value of type 'T' to a value of type 'OtherEqualComparable'}}
55+
otherEqComp2 = t1 // expected-error{{value of type 'T' does not conform to 'OtherEqualComparable' in assignment}}
5656
_ = otherEqComp2
5757

5858
_ = t1 as protocol<EqualComparable, OtherEqualComparable> // expected-error{{'T' is not convertible to 'protocol<EqualComparable, OtherEqualComparable>'; did you mean to use 'as!' to force downcast?}} {{10-12=as!}} expected-error{{protocol 'OtherEqualComparable' can only be used as a generic constraint}} expected-error{{protocol 'EqualComparable' can only be used as a generic constraint}}

‎test/Generics/generic_types.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ func useNested(ii: Int, hni: HasNested<Int>,
205205
var ids = xis.g(1, u: "Hello", v: 3.14159)
206206
ids = (2, "world", 2.71828)
207207

208-
xis = xfs // expected-error{{cannot assign a value of type 'HasNested<Float>.InnerGeneric<String>' to a value of type 'HasNested<Int>.InnerGeneric<String>'}}
208+
xis = xfs // expected-error{{cannot assign value of type 'HasNested<Float>.InnerGeneric<String>' to type 'HasNested<Int>.InnerGeneric<String>'}}
209209
}
210210

211211
var dfail : Dictionary<Int> // expected-error{{generic type 'Dictionary' specialized with too few type parameters (got 1, but expected 2)}}

‎test/Generics/inheritance.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ func f0<T : A>(obji: T, _ ai: A, _ bi: B) {
2525
a = obj
2626

2727
// Invalid assignments
28-
obj = a // expected-error{{cannot assign a value of type 'A' to a value of type 'T'}}
29-
obj = b // expected-error{{cannot assign a value of type 'B' to a value of type 'T'}}
28+
obj = a // expected-error{{'A' is not convertible to 'T'}}
29+
obj = b // expected-error{{'B' is not convertible to 'T'}}
3030

3131
// Downcast that is actually a coercion
3232
a = (obj as? A)! // expected-warning{{conditional cast from 'T' to 'A' always succeeds}}

‎test/NameBinding/import-resolution-overload.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ ambiguousWithVar(true) // no-warning
3232

3333
var localVar : Bool
3434
localVar = false
35-
localVar = 42 // expected-error {{cannot assign a value of type 'Int' to a value of type 'Bool'}}
35+
localVar = 42 // expected-error {{cannot assign value of type 'Int' to type 'Bool'}}
3636
localVar(42) // expected-error {{cannot call value of non-function type 'Bool'}}
3737
var _ : localVar // should still work
3838

‎test/NameBinding/name_lookup.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ struct DefaultArgumentFromExtension {
460460
func g(x: (DefaultArgumentFromExtension) -> () -> () = f) {
461461
let f = 42
462462
var x2 = x
463-
x2 = f // expected-error{{cannot assign a value of type 'Int' to a value of type '(DefaultArgumentFromExtension) -> () -> ()'}}
463+
x2 = f // expected-error{{cannot assign value of type 'Int' to type '(DefaultArgumentFromExtension) -> () -> ()'}}
464464
_ = x2
465465
}
466466
var x : (DefaultArgumentFromExtension) -> () -> () = f

0 commit comments

Comments
 (0)
Please sign in to comment.