Skip to content

Commit 1fb69a7

Browse files
committed
[Diagnostics] Diagnose cases when it's impossible to infer type for nil
Detect and diagnose situations when it's invalid to use `nil` literal without more context e.g. `_ = nil`, `nil as? Int`, or `_ = nil!`.
1 parent 8c6098a commit 1fb69a7

File tree

3 files changed

+66
-1
lines changed

3 files changed

+66
-1
lines changed

lib/Sema/CSDiagnostics.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6945,3 +6945,50 @@ bool InvalidEmptyKeyPathFailure::diagnoseAsError() {
69456945
emitDiagnostic(diag::expr_swift_keypath_empty);
69466946
return true;
69476947
}
6948+
6949+
bool MissingContextualTypeForNil::diagnoseAsError() {
6950+
auto *expr = castToExpr<NilLiteralExpr>(getAnchor());
6951+
6952+
// If this is a standalone `nil` literal expression e.g.
6953+
// `_ = nil`, let's diagnose it here because solver can't
6954+
// attempt any types for it.
6955+
auto *parentExpr = findParentExpr(expr);
6956+
6957+
while (parentExpr && isa<IdentityExpr>(parentExpr))
6958+
parentExpr = findParentExpr(parentExpr);
6959+
6960+
// In cases like `_ = nil?` AST would have `nil`
6961+
// wrapped in `BindOptionalExpr`.
6962+
if (parentExpr && isa<BindOptionalExpr>(parentExpr))
6963+
parentExpr = findParentExpr(parentExpr);
6964+
6965+
if (parentExpr) {
6966+
// `_ = nil as? ...`
6967+
if (isa<ConditionalCheckedCastExpr>(parentExpr)) {
6968+
emitDiagnostic(diag::conditional_cast_from_nil);
6969+
return true;
6970+
}
6971+
6972+
// `_ = nil!`
6973+
if (isa<ForceValueExpr>(parentExpr)) {
6974+
emitDiagnostic(diag::cannot_force_unwrap_nil_literal);
6975+
return true;
6976+
}
6977+
6978+
// `_ = nil?`
6979+
if (isa<OptionalEvaluationExpr>(parentExpr)) {
6980+
emitDiagnostic(diag::unresolved_nil_literal);
6981+
return true;
6982+
}
6983+
// `_ = nil`
6984+
if (auto *assignment = dyn_cast<AssignExpr>(parentExpr)) {
6985+
if (isa<DiscardAssignmentExpr>(assignment->getDest())) {
6986+
emitDiagnostic(diag::unresolved_nil_literal);
6987+
return true;
6988+
}
6989+
}
6990+
}
6991+
6992+
emitDiagnostic(diag::unresolved_nil_literal);
6993+
return true;
6994+
}

lib/Sema/CSDiagnostics.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2268,6 +2268,23 @@ class InvalidEmptyKeyPathFailure final : public FailureDiagnostic {
22682268
bool diagnoseAsError() override;
22692269
};
22702270

2271+
/// Diagnose situations where there is no context to determine a
2272+
/// type of `nil` literal e.g.
2273+
///
2274+
/// \code
2275+
/// let _ = nil
2276+
/// let _ = try nil
2277+
/// let _ = nil!
2278+
/// \endcode
2279+
class MissingContextualTypeForNil final : public FailureDiagnostic {
2280+
public:
2281+
MissingContextualTypeForNil(const Solution &solution,
2282+
ConstraintLocator *locator)
2283+
: FailureDiagnostic(solution, locator) {}
2284+
2285+
bool diagnoseAsError() override;
2286+
};
2287+
22712288
} // end namespace constraints
22722289
} // end namespace swift
22732290

lib/Sema/CSFix.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1606,7 +1606,8 @@ IgnoreInvalidFunctionBuilderBody *IgnoreInvalidFunctionBuilderBody::create(
16061606

16071607
bool SpecifyContextualTypeForNil::diagnose(const Solution &solution,
16081608
bool asNote) const {
1609-
return false;
1609+
MissingContextualTypeForNil failure(solution, getLocator());
1610+
return failure.diagnose(asNote);
16101611
}
16111612

16121613
SpecifyContextualTypeForNil *

0 commit comments

Comments
 (0)