Skip to content

Commit a5a988e

Browse files
committed
Fix rdar://22509125 QoI: Error when unable to infer generic archetype lacks greatness
Rearrange diagnoseGeneralConversionFailure to diagnose structural problems even if we have some UnresolvedTypes floating around, then reject constraint failures with UnresolvedTypes in them even harder. This keeps us giving good errors about failures where we have a structural problem (with buried irrelevant details) while not complaining about cases that are actually ambiguous. The end result of this is that we produce a lot better error messages in the case of failed archetype inference. This also highlights the poor job we do handling multi-stmt closureexprs...
1 parent 13d96b3 commit a5a988e

File tree

8 files changed

+68
-58
lines changed

8 files changed

+68
-58
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 43 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2443,15 +2443,6 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){
24432443

24442444
fromType = fromType->getRValueType();
24452445
auto toType = CS->simplifyType(constraint->getSecondType());
2446-
2447-
// If the second type is a type variable, the expression itself is
2448-
// ambiguous. Bail out so the general ambiguity diagnosing logic can handle
2449-
// it.
2450-
if (fromType->hasUnresolvedType() || fromType->hasTypeVariable() ||
2451-
isUnresolvedOrTypeVarType(toType) ||
2452-
// FIXME: Why reject unbound generic types here?
2453-
fromType->is<UnboundGenericType>())
2454-
return false;
24552446

24562447
// Try to simplify irrelevant details of function types. For example, if
24572448
// someone passes a "() -> Float" function to a "() throws -> Int"
@@ -2489,19 +2480,49 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){
24892480
// a failed conversion constraint of "A -> B" to "_ -> C", where the error is
24902481
// that B isn't convertible to C.
24912482
if (CS->getContextualTypePurpose() == CTP_CalleeResult) {
2492-
if (auto destFT = toType->getAs<FunctionType>()) {
2493-
auto srcFT = fromType->getAs<FunctionType>();
2494-
if (!isUnresolvedOrTypeVarType(srcFT->getResult())) {
2495-
// Otherwise, the error is that the result types mismatch.
2496-
diagnose(expr->getLoc(), diag::invalid_callee_result_type,
2497-
srcFT->getResult(), destFT->getResult())
2498-
.highlight(expr->getSourceRange());
2499-
return true;
2500-
}
2483+
auto destFT = toType->getAs<FunctionType>();
2484+
auto srcFT = fromType->getAs<FunctionType>();
2485+
if (destFT && srcFT && !isUnresolvedOrTypeVarType(srcFT->getResult())) {
2486+
// Otherwise, the error is that the result types mismatch.
2487+
diagnose(expr->getLoc(), diag::invalid_callee_result_type,
2488+
srcFT->getResult(), destFT->getResult())
2489+
.highlight(expr->getSourceRange());
2490+
return true;
25012491
}
25022492
}
25032493

2494+
2495+
// If simplification has turned this into the same types, then this isn't the
2496+
// broken constraint that we're looking for.
2497+
if (fromType->isEqual(toType) &&
2498+
constraint->getKind() != ConstraintKind::ConformsTo)
2499+
return false;
2500+
2501+
2502+
// If we have two tuples with mismatching types, produce a tailored
2503+
// diagnostic.
2504+
if (auto fromTT = fromType->getAs<TupleType>())
2505+
if (auto toTT = toType->getAs<TupleType>())
2506+
if (fromTT->getNumElements() != toTT->getNumElements()) {
2507+
diagnose(anchor->getLoc(), diag::tuple_types_not_convertible,
2508+
fromTT, toTT)
2509+
.highlight(anchor->getSourceRange());
2510+
return true;
2511+
}
2512+
2513+
2514+
// If the second type is a type variable, the expression itself is
2515+
// ambiguous. Bail out so the general ambiguity diagnosing logic can handle
2516+
// it.
2517+
if (fromType->hasUnresolvedType() || fromType->hasTypeVariable() ||
2518+
toType->hasUnresolvedType() || toType->hasTypeVariable() ||
2519+
// FIXME: Why reject unbound generic types here?
2520+
fromType->is<UnboundGenericType>())
2521+
return false;
2522+
2523+
25042524
if (auto PT = toType->getAs<ProtocolType>()) {
2525+
25052526
// Check for "=" converting to BooleanType. The user probably meant ==.
25062527
if (auto *AE = dyn_cast<AssignExpr>(expr->getValueProvidingExpr()))
25072528
if (PT->getDecl()->isSpecificProtocol(KnownProtocolKind::BooleanType)) {
@@ -2530,23 +2551,6 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){
25302551
}
25312552
return true;
25322553
}
2533-
2534-
// If simplification has turned this into the same types, then this isn't the
2535-
// broken constraint that we're looking for.
2536-
if (fromType->isEqual(toType))
2537-
return false;
2538-
2539-
2540-
// If we have two tuples with mismatching types, produce a tailored
2541-
// diagnostic.
2542-
if (auto fromTT = fromType->getAs<TupleType>())
2543-
if (auto toTT = toType->getAs<TupleType>())
2544-
if (fromTT->getNumElements() != toTT->getNumElements()) {
2545-
diagnose(anchor->getLoc(), diag::tuple_types_not_convertible,
2546-
fromTT, toTT)
2547-
.highlight(anchor->getSourceRange());
2548-
return true;
2549-
}
25502554

25512555
diagnose(anchor->getLoc(), diag::types_not_convertible,
25522556
constraint->getKind() == ConstraintKind::Subtype,
@@ -3871,6 +3875,10 @@ bool FailureDiagnosis::visitApplyExpr(ApplyExpr *callExpr) {
38713875
return true;
38723876
}
38733877

3878+
if (argExpr->getType()->hasUnresolvedType())
3879+
return false;
3880+
3881+
38743882
std::string argString = getTypeListString(argExpr->getType());
38753883

38763884
// If we couldn't get the name of the callee, then it must be something of a

test/Constraints/bridging.swift

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -186,16 +186,13 @@ func rdar19551164b(s: NSString, _ a: NSArray) {
186186
}
187187

188188
// rdar://problem/19695671
189-
func takesSet<T: Hashable>(p: Set<T>) {}
190-
func takesDictionary<K: Hashable, V>(p: Dictionary<K, V>) {}
191-
func takesArray<T>(t: Array<T>) {}
189+
func takesSet<T: Hashable>(p: Set<T>) {} // expected-note {{in call to function 'takesSet'}}
190+
func takesDictionary<K: Hashable, V>(p: Dictionary<K, V>) {} // expected-note {{in call to function 'takesDictionary'}}
191+
func takesArray<T>(t: Array<T>) {} // expected-note {{in call to function 'takesArray'}}
192192
func rdar19695671() {
193-
takesSet(NSSet() as! Set) // expected-error{{cannot invoke 'takesSet' with an argument list of type '(Set<_>)'}}
194-
// expected-note @-1 {{expected an argument list of type '(Set<T>)'}}
195-
takesDictionary(NSDictionary() as! Dictionary) // expected-error{{cannot invoke 'takesDictionary' with an argument list of type '(Dictionary<_, _>)'}}
196-
// expected-note @-1 {{expected an argument list of type '(Dictionary<K, V>)'}}
197-
takesArray(NSArray() as! Array) // expected-error{{cannot invoke 'takesArray' with an argument list of type '(Array<_>)'}}
198-
// expected-note @-1 {{expected an argument list of type '(Array<T>)'}}
193+
takesSet(NSSet() as! Set) // expected-error{{generic parameter 'T' could not be inferred}}
194+
takesDictionary(NSDictionary() as! Dictionary) // expected-error{{generic parameter 'K' could not be inferred}}
195+
takesArray(NSArray() as! Array) // expected-error{{generic parameter 'T' could not be inferred}}
199196
}
200197

201198

test/Constraints/closures.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,12 @@ var _: (Int,Int) -> Int = {$0+$1+$2} // expected-error {{contextual closure typ
165165
// Crash when re-typechecking bodies of non-single expression closures
166166

167167
struct CC {}
168+
// expected-note @+1 {{in call to function 'callCC'}}
168169
func callCC<U>(f: CC -> U) -> () {}
169170

170171
func typeCheckMultiStmtClosureCrash() {
171-
callCC { // expected-error {{cannot invoke 'callCC' with an argument list of type '((CC) -> _)'}}
172-
_ = $0 // expected-note@-1 {{expected an argument list of type '(CC -> U)'}}
172+
callCC { // expected-error {{generic parameter 'U' could not be inferred}}
173+
_ = $0
173174
return 1
174175
}
175176
}

test/Constraints/diagnostics.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,7 @@ i ***~ i // expected-error{{cannot convert value of type 'Int' to expected argum
114114
// FIXME: poor diagnostic, to be fixed in 20142462. For now, we just want to
115115
// make sure that it doesn't crash.
116116
func rdar20142523() {
117-
map(0..<10, { x in // expected-error{{cannot invoke 'map' with an argument list of type '(Range<Int>, (_) -> _)'}}
118-
// expected-note @-1 {{overloads for 'map' exist with these partially matching parameter lists: (C, (C.Generator.Element) -> T), (T?, @noescape (T) -> U)}}
117+
map(0..<10, { x in // expected-error{{ambiguous reference to member '..<'}}
119118
()
120119
return x
121120
})
@@ -424,8 +423,7 @@ func f20371273() {
424423
// <rdar://problem/20921068> Swift fails to compile: [0].map() { _ in let r = (1,2).0; return r }
425424
// FIXME: Should complain about not having a return type annotation in the closure.
426425
[0].map { _ in let r = (1,2).0; return r }
427-
// expected-error @-1 {{cannot invoke 'map' with an argument list of type '(@noescape (Int) throws -> _)'}}
428-
// expected-note @-2 {{expected an argument list of type '(@noescape Int throws -> T)'}}
426+
// expected-error @-1 {{expression type '[_]' is ambiguous without more context}}
429427

430428
// <rdar://problem/21078316> Less than useful error message when using map on optional dictionary type
431429
func rdar21078316() {
@@ -615,7 +613,8 @@ extension Array {
615613
}
616614

617615
// <rdar://problem/22519983> QoI: Weird error when failing to infer archetype
618-
func safeAssign<T: RawRepresentable>(inout lhs: T) -> Bool {} // expected-note {{in call to function 'safeAssign'}}
616+
func safeAssign<T: RawRepresentable>(inout lhs: T) -> Bool {}
617+
// expected-note @-1 {{in call to function 'safeAssign'}}
619618
let a = safeAssign // expected-error {{generic parameter 'T' could not be inferred}}
620619

621620

test/Constraints/generics.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,11 @@ func r22459135() {
175175

176176
// <rdar://problem/19710848> QoI: Friendlier error message for "[] as Set"
177177
_ = [] as Set // expected-error {{generic parameter 'Element' could not be inferred}}
178+
179+
180+
//<rdar://problem/22509125> QoI: Error when unable to infer generic archetype lacks greatness
181+
func r22509125<T>(a : T?) { // expected-note {{in call to function 'r22509125'}}
182+
r22509125(nil) // expected-error {{generic parameter 'T' could not be inferred}}
183+
}
184+
185+

test/Constraints/patterns.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,16 +209,14 @@ func good(a: A<EE>) -> Int {
209209
}
210210

211211
func bad(a: A<EE>) {
212-
a.map { // expected-error {{cannot invoke 'map' with an argument list of type '((EE) -> _)'}}
213-
// expected-note@-1 {{expected an argument list of type '(EE -> T)'}}
212+
a.map { // expected-error {{generic parameter 'T' could not be inferred}}
214213
let _: EE = $0
215214
return 1
216215
}
217216
}
218217

219218
func ugly(a: A<EE>) {
220-
a.map { // expected-error {{cannot invoke 'map' with an argument list of type '((EE) -> _)'}}
221-
// expected-note@-1 {{expected an argument list of type '(EE -> T)'}}
219+
a.map { // expected-error {{generic parameter 'T' could not be inferred}}
222220
switch $0 {
223221
case .A:
224222
return 1

test/Constraints/subscript.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,7 @@ let _ = 1["1"] // expected-error {{ambiguous use of 'subscript'}}
7272

7373

7474
// rdar://17687826 - QoI: error message when reducing to an untyped dictionary isn't helpful
75-
let squares = [ 1, 2, 3 ].reduce([:]) { (dict, n) in // expected-error {{cannot invoke 'reduce' with an argument list of type '([_ : _], @noescape (_, Int) throws -> _)'}}
76-
// expected-note @-1 {{expected an argument list of type '(T, combine: @noescape (T, Int) throws -> T)'}}
75+
let squares = [ 1, 2, 3 ].reduce([:]) { (dict, n) in // expected-error {{expression type '[_ : _]' is ambiguous without more context}}
7776
var dict = dict
7877

7978
dict[n] = n * n

test/decl/var/variables.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func tuplePatternDestructuring(x : Int, y : Int) {
8484
_ = i+j
8585

8686
// FIXME: This diagnostic isn't right: rdar://20395243
87-
let (x: g1, a: h1) = (b: x, a: y) // expected-error {{'(b: Int, a: Int)' is not convertible to '(x: (b: Int, a: Int), a: (b: Int, a: Int))'}}
87+
let (x: g1, a: h1) = (b: x, a: y) // expected-error {{expression type '(b: Int, a: Int)' is ambiguous without more context}}
8888
}
8989

9090
// <rdar://problem/21057425> Crash while compiling attached test-app.

0 commit comments

Comments
 (0)