Skip to content

Commit 6ce886f

Browse files
authored
Merge pull request swiftlang#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

0 commit comments

Comments
 (0)