Skip to content

Commit 6ce886f

Browse files
authored
Merge pull request #31810 from xedin/rdar-63230293-5.3
[5.3][ConstraintSystem] Detect and diagnose inability to infer type of clo…
2 parents 6916fcf + 810069e commit 6ce886f

File tree

19 files changed

+201
-30
lines changed

19 files changed

+201
-30
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,9 @@ ERROR(no_candidates_match_result_type,none,
245245
"no '%0' candidates produce the expected contextual result type %1",
246246
(StringRef, Type))
247247

248+
ERROR(cannot_infer_closure_parameter_type,none,
249+
"unable to infer type of a closure parameter %0 in the current context",
250+
(StringRef))
248251
ERROR(cannot_infer_closure_type,none,
249252
"unable to infer closure type in the current context", ())
250253
ERROR(cannot_infer_closure_result_type,none,

lib/Sema/CSBindings.cpp

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,27 +1090,25 @@ bool TypeVariableBinding::attempt(ConstraintSystem &cs) const {
10901090
// resolved and had to be bound to a placeholder "hole" type.
10911091
cs.increaseScore(SK_Hole);
10921092

1093+
ConstraintFix *fix = nullptr;
10931094
if (auto *GP = TypeVar->getImpl().getGenericParameter()) {
10941095
auto path = dstLocator->getPath();
10951096
// Drop `generic parameter` locator element so that all missing
10961097
// generic parameters related to the same path can be coalesced later.
1097-
auto *fix = DefaultGenericArgument::create(
1098+
fix = DefaultGenericArgument::create(
10981099
cs, GP,
10991100
cs.getConstraintLocator(dstLocator->getAnchor(), path.drop_back()));
1100-
if (cs.recordFix(fix))
1101-
return true;
1101+
} else if (TypeVar->getImpl().isClosureParameterType()) {
1102+
fix = SpecifyClosureParameterType::create(cs, dstLocator);
11021103
} else if (TypeVar->getImpl().isClosureResultType()) {
1103-
auto *fix = SpecifyClosureReturnType::create(
1104-
cs, TypeVar->getImpl().getLocator());
1105-
if (cs.recordFix(fix))
1106-
return true;
1104+
fix = SpecifyClosureReturnType::create(cs, dstLocator);
11071105
} else if (srcLocator->getAnchor() &&
11081106
isa<ObjectLiteralExpr>(srcLocator->getAnchor())) {
1109-
auto *fix = SpecifyObjectLiteralTypeImport::create(
1110-
cs, TypeVar->getImpl().getLocator());
1111-
if (cs.recordFix(fix))
1112-
return true;
1107+
fix = SpecifyObjectLiteralTypeImport::create(cs, dstLocator);
11131108
}
1109+
1110+
if (fix && cs.recordFix(fix))
1111+
return true;
11141112
}
11151113
}
11161114

lib/Sema/CSDiagnostics.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@
4141
using namespace swift;
4242
using namespace constraints;
4343

44+
static bool hasFixFor(const Solution &solution, ConstraintLocator *locator) {
45+
return llvm::any_of(solution.Fixes, [&locator](const ConstraintFix *fix) {
46+
return fix->getLocator() == locator;
47+
});
48+
}
49+
4450
FailureDiagnostic::~FailureDiagnostic() {}
4551

4652
bool FailureDiagnostic::diagnose(bool asNote) {
@@ -6127,6 +6133,74 @@ bool MissingContextualBaseInMemberRefFailure::diagnoseAsError() {
61276133
return true;
61286134
}
61296135

6136+
bool UnableToInferClosureParameterType::diagnoseAsError() {
6137+
auto *closure = castToExpr<ClosureExpr>(getRawAnchor());
6138+
6139+
// Let's check whether this closure is an argument to
6140+
// a call which couldn't be properly resolved e.g.
6141+
// missing member or invalid contextual reference and
6142+
// if so let's not diagnose this problem because main
6143+
// issue here is inability to establish context for
6144+
// closure inference.
6145+
//
6146+
// TODO(diagnostics): Once we gain an ability to determine
6147+
// originating source of type holes this check could be
6148+
// significantly simplified.
6149+
{
6150+
auto &solution = getSolution();
6151+
6152+
// If there is a contextual mismatch associated with this
6153+
// closure, let's not diagnose any parameter type issues.
6154+
if (hasFixFor(solution, getConstraintLocator(
6155+
closure, LocatorPathElt::ContextualType())))
6156+
return false;
6157+
6158+
if (auto *parentExpr = findParentExpr(closure)) {
6159+
while (parentExpr &&
6160+
(isa<TupleExpr>(parentExpr) || isa<ParenExpr>(parentExpr))) {
6161+
parentExpr = findParentExpr(parentExpr);
6162+
}
6163+
6164+
if (parentExpr) {
6165+
// Missing or invalid member reference in call.
6166+
if (auto *AE = dyn_cast<ApplyExpr>(parentExpr)) {
6167+
if (getType(AE->getFn())->isHole())
6168+
return false;
6169+
}
6170+
6171+
// Any fix anchored on parent expression makes it unnecessary
6172+
// to diagnose unability to infer parameter type because it's
6173+
// an indication that proper context couldn't be established to
6174+
// resolve the closure.
6175+
if (llvm::any_of(solution.Fixes,
6176+
[&parentExpr](const ConstraintFix *fix) -> bool {
6177+
return fix->getAnchor() == parentExpr;
6178+
}))
6179+
return false;
6180+
}
6181+
}
6182+
}
6183+
6184+
auto paramIdx = getLocator()
6185+
->castLastElementTo<LocatorPathElt::TupleElement>()
6186+
.getIndex();
6187+
6188+
auto *PD = closure->getParameters()->get(paramIdx);
6189+
6190+
llvm::SmallString<16> id;
6191+
llvm::raw_svector_ostream OS(id);
6192+
6193+
if (PD->isAnonClosureParam()) {
6194+
OS << "$" << paramIdx;
6195+
} else {
6196+
OS << "'" << PD->getParameterName() << "'";
6197+
}
6198+
6199+
auto loc = PD->isAnonClosureParam() ? getLoc() : PD->getLoc();
6200+
emitDiagnosticAt(loc, diag::cannot_infer_closure_parameter_type, OS.str());
6201+
return true;
6202+
}
6203+
61306204
bool UnableToInferClosureReturnType::diagnoseAsError() {
61316205
auto *closure = castToExpr<ClosureExpr>(getRawAnchor());
61326206

lib/Sema/CSDiagnostics.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1973,6 +1973,15 @@ class MissingContextualBaseInMemberRefFailure final : public FailureDiagnostic {
19731973
bool diagnoseAsError();
19741974
};
19751975

1976+
class UnableToInferClosureParameterType final : public FailureDiagnostic {
1977+
public:
1978+
UnableToInferClosureParameterType(const Solution &solution,
1979+
ConstraintLocator *locator)
1980+
: FailureDiagnostic(solution, locator) {}
1981+
1982+
bool diagnoseAsError();
1983+
};
1984+
19761985
class UnableToInferClosureReturnType final : public FailureDiagnostic {
19771986
public:
19781987
UnableToInferClosureReturnType(const Solution &solution,

lib/Sema/CSFix.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "ConstraintSystem.h"
2323
#include "OverloadChoice.h"
2424
#include "swift/AST/Expr.h"
25+
#include "swift/AST/ParameterList.h"
2526
#include "swift/AST/Type.h"
2627
#include "swift/AST/Types.h"
2728
#include "swift/Basic/SourceManager.h"
@@ -1226,6 +1227,38 @@ SpecifyBaseTypeForContextualMember *SpecifyBaseTypeForContextualMember::create(
12261227
SpecifyBaseTypeForContextualMember(cs, member, locator);
12271228
}
12281229

1230+
std::string SpecifyClosureParameterType::getName() const {
1231+
std::string name;
1232+
llvm::raw_string_ostream OS(name);
1233+
1234+
auto *closure = cast<ClosureExpr>(getAnchor());
1235+
auto paramLoc =
1236+
getLocator()->castLastElementTo<LocatorPathElt::TupleElement>();
1237+
1238+
auto *PD = closure->getParameters()->get(paramLoc.getIndex());
1239+
1240+
OS << "specify type for parameter ";
1241+
if (PD->isAnonClosureParam()) {
1242+
OS << "$" << paramLoc.getIndex();
1243+
} else {
1244+
OS << "'" << PD->getParameterName() << "'";
1245+
}
1246+
1247+
return OS.str();
1248+
}
1249+
1250+
bool SpecifyClosureParameterType::diagnose(const Solution &solution,
1251+
bool asNote) const {
1252+
UnableToInferClosureParameterType failure(solution, getLocator());
1253+
return failure.diagnose(asNote);
1254+
}
1255+
1256+
SpecifyClosureParameterType *
1257+
SpecifyClosureParameterType::create(ConstraintSystem &cs,
1258+
ConstraintLocator *locator) {
1259+
return new (cs.getAllocator()) SpecifyClosureParameterType(cs, locator);
1260+
}
1261+
12291262
bool SpecifyClosureReturnType::diagnose(const Solution &solution,
12301263
bool asNote) const {
12311264
UnableToInferClosureReturnType failure(solution, getLocator());

lib/Sema/CSFix.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,10 @@ enum class FixKind : uint8_t {
232232
/// inferred and has to be specified explicitly.
233233
SpecifyBaseTypeForContextualMember,
234234

235+
/// Type of the closure parameter used in the body couldn't be inferred
236+
/// and has to be specified explicitly.
237+
SpecifyClosureParameterType,
238+
235239
/// Closure return type has to be explicitly specified because it can't be
236240
/// inferred in current context e.g. because it's a multi-statement closure.
237241
SpecifyClosureReturnType,
@@ -251,7 +255,7 @@ enum class FixKind : uint8_t {
251255

252256
/// A warning fix that allows a coercion to perform a force-cast.
253257
AllowCoercionToForceCast,
254-
258+
255259
/// Allow key path root type mismatch when applying a key path that has a
256260
/// root type not convertible to the type of the base instance.
257261
AllowKeyPathRootTypeMismatch,
@@ -1706,6 +1710,19 @@ class SpecifyBaseTypeForContextualMember final : public ConstraintFix {
17061710
create(ConstraintSystem &cs, DeclNameRef member, ConstraintLocator *locator);
17071711
};
17081712

1713+
class SpecifyClosureParameterType final : public ConstraintFix {
1714+
SpecifyClosureParameterType(ConstraintSystem &cs, ConstraintLocator *locator)
1715+
: ConstraintFix(cs, FixKind::SpecifyClosureParameterType, locator) {}
1716+
1717+
public:
1718+
std::string getName() const;
1719+
1720+
bool diagnose(const Solution &solution, bool asNote = false) const;
1721+
1722+
static SpecifyClosureParameterType *create(ConstraintSystem &cs,
1723+
ConstraintLocator *locator);
1724+
};
1725+
17091726
class SpecifyClosureReturnType final : public ConstraintFix {
17101727
SpecifyClosureReturnType(ConstraintSystem &cs, ConstraintLocator *locator)
17111728
: ConstraintFix(cs, FixKind::SpecifyClosureReturnType, locator) {}

lib/Sema/CSGen.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2196,8 +2196,12 @@ namespace {
21962196
auto declaredTy = param->getType();
21972197
externalType = CS.openUnboundGenericType(declaredTy, paramLoc);
21982198
} else {
2199+
// Let's allow parameters which haven't been explicitly typed
2200+
// to become holes by default, this helps in situations like
2201+
// `foo { a in }` where `foo` doesn't exist.
21992202
externalType = CS.createTypeVariable(
2200-
paramLoc, TVO_CanBindToInOut | TVO_CanBindToNoEscape);
2203+
paramLoc,
2204+
TVO_CanBindToInOut | TVO_CanBindToNoEscape | TVO_CanBindToHole);
22012205
}
22022206

22032207
closureParams.push_back(param->toFunctionParam(externalType));

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9603,6 +9603,7 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyFixConstraint(
96039603
case FixKind::AllowTupleSplatForSingleParameter:
96049604
case FixKind::AllowInvalidUseOfTrailingClosure:
96059605
case FixKind::AllowNonClassTypeToConvertToAnyObject:
9606+
case FixKind::SpecifyClosureParameterType:
96069607
case FixKind::SpecifyClosureReturnType:
96079608
case FixKind::AddQualifierToAccessTopLevelName:
96089609
llvm_unreachable("handled elsewhere");

lib/Sema/ConstraintGraph.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,10 @@ bool ConstraintGraph::contractEdges() {
11261126
if (isParamBindingConstraint && tyvar1->getImpl().canBindToInOut()) {
11271127
bool isNotContractable = true;
11281128
if (auto bindings = CS.getPotentialBindings(tyvar1)) {
1129+
// Holes can't be contracted.
1130+
if (bindings.IsHole)
1131+
continue;
1132+
11291133
for (auto &binding : bindings.Bindings) {
11301134
auto type = binding.BindingType;
11311135
isNotContractable = type.findIf([&](Type nestedType) -> bool {

lib/Sema/ConstraintSystem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,10 @@ class TypeVariableType::Implementation {
300300
/// Determine whether this type variable represents a closure type.
301301
bool isClosureType() const;
302302

303+
/// Determine whether this type variable represents one of the
304+
/// parameter types associated with a closure.
305+
bool isClosureParameterType() const;
306+
303307
/// Determine whether this type variable represents a closure result type.
304308
bool isClosureResultType() const;
305309

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,14 @@ bool TypeVariableType::Implementation::isClosureType() const {
9090
return isa<ClosureExpr>(locator->getAnchor()) && locator->getPath().empty();
9191
}
9292

93+
bool TypeVariableType::Implementation::isClosureParameterType() const {
94+
if (!(locator && locator->getAnchor()))
95+
return false;
96+
97+
return isa<ClosureExpr>(locator->getAnchor()) &&
98+
locator->isLastElement<LocatorPathElt::TupleElement>();
99+
}
100+
93101
bool TypeVariableType::Implementation::isClosureResultType() const {
94102
if (!(locator && locator->getAnchor()))
95103
return false;

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)

0 commit comments

Comments
 (0)