Skip to content

Commit d111f11

Browse files
committed
[ConstraintSystem] Detect and diagnose inability to infer type of closure parameter(s)
Detect situation when it's impossible to determine types for closure parameters used in the body from the context. E.g. when a call closure is associated with refers to a missing member. ```swift struct S { } S.foo { a, b in } // `S` doesn't have static member `foo` let _ = { v in } // not enough context to infer type of `v` _ = .foo { v in } // base type for `.foo` couldn't be determined ``` Resolves: [SR-12815](https://bugs.swift.org/browse/SR-12815) Resolves: rdar://problem/63230293
1 parent 2f91f21 commit d111f11

File tree

11 files changed

+46
-33
lines changed

11 files changed

+46
-33
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,32 +1087,27 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const {
10871087
// resolved and had to be bound to a placeholder "hole" type.
10881088
cs.increaseScore(SK_Hole);
10891089

1090+
ConstraintFix *fix = nullptr;
10901091
if (auto *GP = TypeVar->getImpl().getGenericParameter()) {
10911092
auto path = dstLocator->getPath();
10921093
// Drop `generic parameter` locator element so that all missing
10931094
// generic parameters related to the same path can be coalesced later.
1094-
auto *fix = DefaultGenericArgument::create(
1095+
fix = DefaultGenericArgument::create(
10951096
cs, GP,
10961097
cs.getConstraintLocator(dstLocator->getAnchor(), path.drop_back()));
1097-
if (cs.recordFix(fix))
1098-
return true;
1098+
} else if (TypeVar->getImpl().isClosureParameterType()) {
1099+
fix = SpecifyClosureParameterType::create(cs, dstLocator);
10991100
} else if (TypeVar->getImpl().isClosureResultType()) {
1100-
auto *fix = SpecifyClosureReturnType::create(
1101-
cs, TypeVar->getImpl().getLocator());
1102-
if (cs.recordFix(fix))
1103-
return true;
1101+
fix = SpecifyClosureReturnType::create(cs, dstLocator);
11041102
} else if (srcLocator->getAnchor() &&
11051103
isExpr<ObjectLiteralExpr>(srcLocator->getAnchor())) {
1106-
auto *fix = SpecifyObjectLiteralTypeImport::create(
1107-
cs, TypeVar->getImpl().getLocator());
1108-
if (cs.recordFix(fix))
1109-
return true;
1104+
fix = SpecifyObjectLiteralTypeImport::create(cs, dstLocator);
11101105
} else if (srcLocator->isKeyPathRoot()) {
1111-
auto *fix =
1112-
SpecifyKeyPathRootType::create(cs, TypeVar->getImpl().getLocator());
1113-
if (cs.recordFix(fix))
1114-
return true;
1106+
fix = SpecifyKeyPathRootType::create(cs, dstLocator);
11151107
}
1108+
1109+
if (fix && cs.recordFix(fix))
1110+
return true;
11161111
}
11171112
}
11181113

lib/Sema/CSFix.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1252,7 +1252,8 @@ std::string SpecifyClosureParameterType::getName() const {
12521252

12531253
bool SpecifyClosureParameterType::diagnose(const Solution &solution,
12541254
bool asNote) const {
1255-
return false;
1255+
UnableToInferClosureParameterType failure(solution, getLocator());
1256+
return failure.diagnose(asNote);
12561257
}
12571258

12581259
SpecifyClosureParameterType *

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9609,6 +9609,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
96099609
case FixKind::AllowTupleSplatForSingleParameter:
96109610
case FixKind::AllowInvalidUseOfTrailingClosure:
96119611
case FixKind::AllowNonClassTypeToConvertToAnyObject:
9612+
case FixKind::SpecifyClosureParameterType:
96129613
case FixKind::SpecifyClosureReturnType:
96139614
case FixKind::AddQualifierToAccessTopLevelName:
96149615
llvm_unreachable("handled elsewhere");

test/Constraints/closures.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ struct S_3520 {
504504
func sr3520_set_via_closure<S, T>(_ closure: (inout S, T) -> ()) {} // expected-note {{in call to function 'sr3520_set_via_closure'}}
505505
sr3520_set_via_closure({ $0.number1 = $1 })
506506
// expected-error@-1 {{generic parameter 'S' could not be inferred}}
507-
// expected-error@-2 {{generic parameter 'T' could not be inferred}}
507+
// expected-error@-2 {{unable to infer type of a closure parameter $1 in the current context}}
508508

509509
// SR-3073: UnresolvedDotExpr in single expression closure
510510

@@ -1017,3 +1017,21 @@ func overloaded_with_default_and_autoclosure<T>(b: Int = 0, c: @escaping () -> T
10171017

10181018
overloaded_with_default_and_autoclosure { 42 } // Ok
10191019
overloaded_with_default_and_autoclosure(42) // Ok
1020+
1021+
// SR-12815 - `error: type of expression is ambiguous without more context` in many cases where methods are missing
1022+
func sr12815() {
1023+
let _ = { a, b in }
1024+
// expected-error@-1 {{unable to infer type of a closure parameter 'a' in the current context}}
1025+
// expected-error@-2 {{unable to infer type of a closure parameter 'b' in the current context}}
1026+
1027+
_ = .a { b in } // expected-error {{cannot infer contextual base in reference to member 'a'}}
1028+
1029+
struct S {}
1030+
1031+
func test(s: S) {
1032+
S.doesntExist { b in } // expected-error {{type 'S' has no member 'doesntExist'}}
1033+
s.doesntExist { b in } // expected-error {{value of type 'S' has no member 'doesntExist'}}
1034+
s.doesntExist1 { v in } // expected-error {{value of type 'S' has no member 'doesntExist1'}}
1035+
.doesntExist2() { $0 }
1036+
}
1037+
}

test/Constraints/diagnostics.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,7 @@ struct Toe {
255255
let toenail: Nail // expected-error {{cannot find type 'Nail' in scope}}
256256

257257
func clip() {
258-
// TODO(diagnostics): Solver should stop once it has detected that `toenail` doesn't exist and report that.
259-
toenail.inspect { x in // expected-error {{type of expression is ambiguous without more context}}
258+
toenail.inspect { x in
260259
toenail.inspect { y in }
261260
}
262261
}
@@ -297,7 +296,7 @@ func r18800223(_ i : Int) {
297296
}
298297

299298
// <rdar://problem/21883806> Bogus "'_' can only appear in a pattern or on the left side of an assignment" is back
300-
_ = { $0 } // expected-error {{unable to infer closure type in the current context}}
299+
_ = { $0 } // expected-error {{unable to infer type of a closure parameter $0 in the current context}}
301300

302301

303302

test/Sema/diag_ambiguous_overloads.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ fe(.baz) // expected-error {{reference to member 'baz' cannot be resolved withou
1515
fe(.nope, .nyet) // expected-error {{type 'Int' has no member 'nope'}}
1616
// expected-error@-1 {{reference to member 'nyet' cannot be resolved without a contextual type}}
1717

18-
func fg<T>(_ f: (T) -> T) -> Void {} // expected-note {{in call to function 'fg'}}
19-
fg({x in x}) // expected-error {{generic parameter 'T' could not be inferred}}
18+
func fg<T>(_ f: (T) -> T) -> Void {}
19+
fg({x in x}) // expected-error {{unable to infer type of a closure parameter 'x' in the current context}}
2020

2121

2222
struct S {
23-
func f<T>(_ i: (T) -> T, _ j: Int) -> Void {} // expected-note {{in call to function 'f'}}
23+
func f<T>(_ i: (T) -> T, _ j: Int) -> Void {}
2424
func f(_ d: (Double) -> Double) -> Void {}
2525
func test() -> Void {
26-
f({x in x}, 2) // expected-error {{generic parameter 'T' could not be inferred}}
26+
f({x in x}, 2) // expected-error {{unable to infer type of a closure parameter 'x' in the current context}}
2727
}
2828

2929
func g<T>(_ a: T, _ b: Int) -> Void {}

test/decl/typealias/generic.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ typealias E<T1, T2> = Int // expected-note {{generic type 'E' declared here}}
6868
// expected-note@-1 {{'T1' declared as parameter to type 'E'}}
6969
// expected-note@-2 {{'T2' declared as parameter to type 'E'}}
7070

71-
typealias F<T1, T2> = (T1) -> T2 // expected-note {{'T1' declared as parameter to type 'F'}}
71+
typealias F<T1, T2> = (T1) -> T2
7272

7373
// Type alias of type alias.
7474
typealias G<S1, S2> = A<S1, S2>
@@ -94,7 +94,7 @@ let _ : D<Int, Int, Float> = D(a: 1, b: 2)
9494

9595
let _ : F = { (a : Int) -> Int in a } // Infer the types of F
9696

97-
let _ : F = { a in a } // expected-error {{generic parameter 'T1' could not be inferred}}
97+
let _ : F = { a in a } // expected-error {{unable to infer type of a closure parameter 'a' in the current context}}
9898

9999
_ = MyType(a: "foo", b: 42)
100100
_ = A(a: "foo", b: 42)

test/expr/closure/anonymous.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ func takesIntArray(_: [Int]) { }
1313
func takesVariadicInt(_: (Int...) -> ()) { }
1414
func takesVariadicIntInt(_: (Int, Int...) -> ()) { }
1515

16-
func takesVariadicGeneric<T>(_ f: (T...) -> ()) { } // expected-note {{in call to function 'takesVariadicGeneric'}}
16+
func takesVariadicGeneric<T>(_ f: (T...) -> ()) { }
1717

1818
func variadic() {
1919
// These work
@@ -32,7 +32,7 @@ func variadic() {
3232
// FIXME: Problem here is related to multi-statement closure body not being type-checked together with
3333
// enclosing context. We could have inferred `$0` to be `[Int]` if `let` was a part of constraint system.
3434
takesVariadicGeneric({let _: [Int] = $0})
35-
// expected-error@-1 {{generic parameter 'T' could not be inferred}}
35+
// expected-error@-1 {{unable to infer type of a closure parameter $0 in the current context}}
3636

3737
takesVariadicIntInt({_ = $0; takesIntArray($1)})
3838
takesVariadicIntInt({_ = $0; let _: [Int] = $1})

test/expr/closure/basic.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func variadic() {
2626
_ = f(1, 2)
2727
_ = f(1, 3)
2828

29-
let D = { (Ss ...) in 1 } // expected-error{{'...' cannot be applied to a subpattern which is not explicitly typed}}, expected-error{{unable to infer closure type in the current context}}
29+
let D = { (Ss ...) in 1 } // expected-error{{'...' cannot be applied to a subpattern which is not explicitly typed}}, expected-error{{unable to infer type of a closure parameter 'Ss' in the current context}}
3030
}
3131

3232
// Closures with attributes in the parameter list.

test/expr/unary/keypath/salvage-with-other-type-errors.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ extension A: K {
3434

3535
struct B {
3636
let v: String
37-
func f1<T, E>(block: (T) -> E) -> B { // expected-note {{in call to function 'f1(block:)'}}
37+
func f1<T, E>(block: (T) -> E) -> B {
3838
return self
3939
}
4040

4141
func f2<T, E: Equatable>(keyPath: KeyPath<T, E>) {
4242
}
4343
}
4444
func f3() {
45-
B(v: "").f1(block: { _ in }).f2(keyPath: \B.v) // expected-error{{}}
45+
B(v: "").f1(block: { _ in }).f2(keyPath: \B.v) // expected-error{{unable to infer type of a closure parameter '_' in the current context}}
4646
}
4747

4848
// SR-5375

validation-test/compiler_crashers_2_fixed/0186-rdar46497155.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,9 @@ struct E {
2020

2121
func foo(arr: [E], other: P) -> Bool {
2222
return arr.compactMap { i in
23-
// expected-error@-1 {{generic parameter 'ElementOfResult' could not be inferred}}
2423
var flag = false
2524
return try? i.getB(&flag)
26-
}.compactMap { u -> P? in
25+
}.compactMap { u -> P? in // expected-error {{nable to infer type of a closure parameter 'u' in the current context}}
2726
guard let a = try? u.foo() else { return nil }
2827
return a.value!
2928
}.contains {

0 commit comments

Comments
 (0)