Skip to content

Commit 7f3f0f8

Browse files
authored
Merge pull request #4393 from CodaFi/never-say-never
[SIL] Fix Diagnosing Never-returning functions that don't call other Never-returning functions
2 parents fcad0ba + 5a2479c commit 7f3f0f8

File tree

8 files changed

+39
-13
lines changed

8 files changed

+39
-13
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,11 @@ ERROR(assignment_to_immutable_value,none,
179179
ERROR(missing_return,none,
180180
"missing return in a %select{function|closure}1 expected to return %0",
181181
(Type, unsigned))
182-
ERROR(non_exhaustive_switch,none,
182+
ERROR(missing_never_call,none,
183+
"%select{function|closure}1 with uninhabited return type %0 is missing "
184+
"call to another never-returning function on all paths",
185+
(Type, unsigned))
186+
ERROR(non_exhaustive_switch,none,
183187
"switch must be exhaustive, consider adding a default clause", ())
184188
ERROR(guard_body_must_not_fallthrough,none,
185189
"'guard' body may not fall through, consider using 'return' or 'break'"

include/swift/AST/Types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ class alignas(1 << TypeAlignInBits) TypeBase {
394394
bool hasReferenceSemantics();
395395

396396
/// Is this an uninhabited type, such as 'Never'?
397-
bool isNever();
397+
bool isUninhabited();
398398

399399
/// Is this the 'Any' type?
400400
bool isAny();

lib/AST/Type.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,11 @@ bool TypeBase::hasReferenceSemantics() {
8989
return getCanonicalType().hasReferenceSemantics();
9090
}
9191

92-
bool TypeBase::isNever() {
92+
bool TypeBase::isUninhabited() {
9393
if (auto nominalDecl = getAnyNominal())
9494
if (auto enumDecl = dyn_cast<EnumDecl>(nominalDecl))
9595
if (enumDecl->getAllElements().empty())
9696
return true;
97-
9897
return false;
9998
}
10099

lib/IRGen/GenClangType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ GenClangType::visitBoundGenericType(CanBoundGenericType type) {
493493
clang::CanQualType GenClangType::visitEnumType(CanEnumType type) {
494494
// Special case: Uninhabited enums are not @objc, so we don't
495495
// know what to do below, but we can just convert to 'void'.
496-
if (type->isNever())
496+
if (type->isUninhabited())
497497
return Converter.convert(IGM, IGM.Context.TheEmptyTupleType);
498498

499499
assert(type->getDecl()->isObjC() && "not an @objc enum?!");

lib/SIL/SILType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ bool SILType::isReferenceCounted(SILModule &M) const {
7272

7373
bool SILType::isNoReturnFunction() const {
7474
if (auto funcTy = dyn_cast<SILFunctionType>(getSwiftRValueType()))
75-
return funcTy->getSILResult().getSwiftRValueType()->isNever();
75+
return funcTy->getSILResult().getSwiftRValueType()->isUninhabited();
7676

7777
return false;
7878
}

lib/SILOptimizer/Mandatory/DataflowDiagnostics.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,13 @@ static void diagnoseMissingReturn(const UnreachableInst *UI,
4646
llvm_unreachable("unhandled case in MissingReturn");
4747
}
4848

49-
// No action required if the function returns 'Void' or that the
50-
// function is marked 'noreturn'.
51-
if (ResTy->isVoid() || F->isNoReturnFunction())
52-
return;
53-
5449
SILLocation L = UI->getLoc();
5550
assert(L && ResTy);
51+
auto diagID = F->isNoReturnFunction() ? diag::missing_never_call
52+
: diag::missing_return;
5653
diagnose(Context,
5754
L.getEndSourceLoc(),
58-
diag::missing_return, ResTy,
55+
diagID, ResTy,
5956
FLoc.isASTNode<ClosureExpr>() ? 1 : 0);
6057
}
6158

lib/Sema/TypeCheckStmt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1005,7 +1005,7 @@ bool TypeChecker::typeCheckCatchPattern(CatchStmt *S, DeclContext *DC) {
10051005

10061006
static bool isDiscardableType(Type type) {
10071007
return (type->is<ErrorType>() ||
1008-
type->isNever() ||
1008+
type->isUninhabited() ||
10091009
type->lookThroughAllAnyOptionalTypes()->isVoid());
10101010
}
10111011

test/SILOptimizer/return.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,32 @@ func singleBlock2() -> Int {
99
y += 1
1010
} // expected-error {{missing return in a function expected to return 'Int'}}
1111

12+
enum NoCasesButNotNever {}
13+
14+
func diagnoseNoCaseEnumMissingReturn() -> NoCasesButNotNever {
15+
} // expected-error {{function with uninhabited return type 'NoCasesButNotNever' is missing call to another never-returning function on all paths}}
16+
17+
func diagnoseNeverMissingBody() -> Never {
18+
} // expected-error {{function with uninhabited return type 'Never' is missing call to another never-returning function on all paths}}
19+
20+
_ = { () -> Never in
21+
}() // expected-error {{closure with uninhabited return type 'Never' is missing call to another never-returning function on all paths}}-
22+
23+
func diagnoseNeverWithBody(i : Int) -> Never {
24+
if (i == -1) {
25+
print("Oh no!")
26+
} else {
27+
switch i {
28+
case 0:
29+
exit()
30+
case 1:
31+
fatalError()
32+
default:
33+
repeat { } while true
34+
}
35+
}
36+
} // expected-error {{function with uninhabited return type 'Never' is missing call to another never-returning function on all paths}}
37+
1238
class MyClassWithClosure {
1339
var f : (_ s: String) -> String = { (_ s: String) -> String in } // expected-error {{missing return in a closure expected to return 'String'}}
1440
}

0 commit comments

Comments
 (0)