Skip to content

Commit 6636baf

Browse files
committed
Fix <rdar://problem/23272739> Poor diagnostic due to contextual constraint
Previously we erroneously complained: error: cannot invoke 'contains' with an argument list of type '(String)' now we correctly complain: error: unexpected non-void return value in void function This enhances CSDiags to use "getTypeOfMember" when analyzing method candidates that are applied to a known base type. Using it allows us to substitute information about the base, resolving archetypes that exist in subsequent argument positions. In the testcase, this means that we use information about Set<String> to know that the argument to "contains" is a String. This allows us to generate much better diagnostics in some cases, and works around some limitations in the existing stuff for handling unresolved archetypes. One unfortunate change is the notes in Misc/misc_diagnostics.swift. Because we don't track argument lists very well, we are flattening an argument list that is actually ((Int,Int)) into (Int, Int) so we get a bogus looking diagnostic. This was possible before this patch though, it is just one more case that triggers the issue.
1 parent a35699b commit 6636baf

File tree

5 files changed

+46
-10
lines changed

5 files changed

+46
-10
lines changed

lib/Sema/CSDiag.cpp

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,12 +1104,22 @@ namespace {
11041104
/// func f(a:Int)(b:Double) -> Int
11051105
/// Uncurry level of 0 indicates that we're looking at the "a" argument, an
11061106
/// uncurry level of 1 indicates that we're looking at the "b" argument.
1107+
///
1108+
/// The declType specifies a specific type to use for this decl that may be
1109+
/// more resolved than the decls type. For example, it may have generic
1110+
/// arguments substituted in.
11071111
struct UncurriedCandidate {
11081112
ValueDecl *decl;
11091113
unsigned level;
1114+
Type declType;
1115+
1116+
UncurriedCandidate(ValueDecl *decl, unsigned level)
1117+
: decl(decl), level(level), declType(decl->getType()) {
1118+
}
11101119

11111120
AnyFunctionType *getUncurriedFunctionType() const {
1112-
auto type = decl->getType();
1121+
// Start with the known type of the decl.
1122+
auto type = declType;
11131123

11141124
// If this is an operator func decl in a type context, the 'self' isn't
11151125
// actually going to be applied.
@@ -1491,11 +1501,29 @@ void CalleeCandidateInfo::collectCalleeCandidates(Expr *fn) {
14911501
if (auto AE = dyn_cast<ApplyExpr>(fn)) {
14921502
collectCalleeCandidates(AE->getFn());
14931503

1504+
// If this is a DotSyntaxCallExpr, then the callee is a method, and the
1505+
// argument list of this apply is the base being applied to the method.
1506+
// If we have a type for that, capture it so that we can calculate a
1507+
// substituted type, which resolves many generic arguments.
1508+
Type baseType;
1509+
1510+
// TODO: What about ConstructorRefCallExpr?
1511+
if (isa<DotSyntaxCallExpr>(AE) &&
1512+
!isUnresolvedOrTypeVarType(AE->getArg()->getType()))
1513+
baseType = AE->getArg()->getType()->getLValueOrInOutObjectType();
1514+
14941515
// If we found a candidate list with a recursive walk, try adjust the curry
14951516
// level for the applied subexpression in this call.
14961517
if (!candidates.empty()) {
1497-
for (auto &C : candidates)
1518+
for (auto &C : candidates) {
14981519
C.level += 1;
1520+
1521+
// Compute a new substituted type if we have a base type to apply.
1522+
if (baseType && C.level == 1)
1523+
C.declType = baseType->getTypeOfMember(CS->DC->getParentModule(),
1524+
C.decl, nullptr);
1525+
}
1526+
14991527
return;
15001528
}
15011529
}

test/Constraints/diagnostics.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,8 @@ func f20371273() {
406406
// FIXME: Should complain about not having a return type annotation in the closure.
407407
[0].map { _ in let r = (1,2).0; return r }
408408
// expected-error @-1 {{cannot invoke 'map' with an argument list of type '(@noescape (Int) throws -> _)'}}
409-
// expected-note @-2 {{expected an argument list of type '(@noescape (Self.Generator.Element) throws -> T)'}}
409+
// expected-error @-2 {{cannot convert return expression of type 'Int' to return type 'T'}}
410+
// expected-note @-3 {{expected an argument list of type '(@noescape Int throws -> T)'}}
410411

411412
// <rdar://problem/21078316> Less than useful error message when using map on optional dictionary type
412413
func rdar21078316() {
@@ -649,3 +650,10 @@ func r22058555() {
649650
}
650651
}
651652

653+
// <rdar://problem/23272739> Poor diagnostic due to contextual constraint
654+
func r23272739(contentType: String) {
655+
let actualAcceptableContentTypes: Set<String> = []
656+
return actualAcceptableContentTypes.contains(contentType) // expected-error {{unexpected non-void return value in void function}}
657+
}
658+
659+

test/Constraints/subscript.swift

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

7474
// rdar://17687826 - QoI: error message when reducing to an untyped dictionary isn't helpful
7575
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, Self.Generator.Element) throws -> T)'}}
76+
// expected-note @-1 {{expected an argument list of type '(T, combine: @noescape (T, Int) throws -> T)'}}
7777
var dict = dict // expected-error {{type of expression is ambiguous without more context}}
7878

7979
dict[n] = n * n

test/Generics/function_defs.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func doCompare<T : EqualComparable, U : EqualComparable>(t1: T, t2: T, u: U) ->
1818
}
1919

2020
return t1.isEqual(u) // expected-error {{cannot invoke 'isEqual' with an argument list of type '(U)'}}
21-
// expected-note @-1 {{expected an argument list of type '(Self)'}}
21+
// expected-note @-1 {{expected an argument list of type '(T)'}}
2222
}
2323

2424
protocol MethodLessComparable {
@@ -38,7 +38,7 @@ func existential<T : EqualComparable, U : EqualComparable>(t1: T, t2: T, u: U) {
3838
var eqComp : EqualComparable = t1 // expected-error{{protocol 'EqualComparable' can only be used as a generic constraint}}
3939
eqComp = u
4040
if t1.isEqual(eqComp) {} // expected-error{{cannot invoke 'isEqual' with an argument list of type '(EqualComparable)'}}
41-
// expected-note @-1 {{expected an argument list of type '(Self)'}}
41+
// expected-note @-1 {{expected an argument list of type '(T)'}}
4242
if eqComp.isEqual(t2) {} // expected-error{{member 'isEqual' cannot be used on value of protocol type 'EqualComparable'; use a generic constraint instead}}
4343
}
4444

@@ -172,7 +172,7 @@ func staticEqCheck<T : StaticEq, U : StaticEq>(t: T, u: U) {
172172
if T.isEqual(t, y: t) { return }
173173
if U.isEqual(u, y: u) { return }
174174
T.isEqual(t, y: u) // expected-error{{cannot invoke 'isEqual' with an argument list of type '(T, y: U)'}}
175-
// expected-note @-1 {{expected an argument list of type '(Self, y: Self)'}}
175+
// expected-note @-1 {{expected an argument list of type '(T, y: T)'}}
176176
}
177177

178178
//===----------------------------------------------------------------------===//

test/Misc/misc_diagnostics.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ let _: String = testIS1() // expected-error {{cannot convert value of type 'Int'
9292

9393
func insertA<T>(inout array : [T], elt : T) {
9494
array.append(T); // expected-error {{cannot invoke 'append' with an argument list of type '((T).Type)'}}
95-
// expected-note @-1 {{expected an argument list of type '(Element)'}}
95+
// expected-note @-1 {{expected an argument list of type '(T)'}}
9696
}
9797

9898
// <rdar://problem/17875634> can't append to array of tuples
@@ -112,10 +112,10 @@ func test17875634() {
112112
// expected-note @-1 {{overloads for '+=' exist with these partially matching parameter lists:}}
113113

114114
match.append(row, col) // expected-error{{cannot invoke 'append' with an argument list of type '(Int, Int)'}}
115-
// expected-note @-1 {{expected an argument list of type '(Element)'}}
115+
// expected-note @-1 {{expected an argument list of type '(Int, Int)'}}
116116

117117
match.append(1, 2) // expected-error{{cannot invoke 'append' with an argument list of type '(Int, Int)'}}
118-
// expected-note @-1 {{expected an argument list of type '(Element)'}}
118+
// expected-note @-1 {{expected an argument list of type '(Int, Int)'}}
119119

120120
match.append(coord)
121121
match.append((1, 2))

0 commit comments

Comments
 (0)