Skip to content

Commit 6ff02a9

Browse files
committed
AST/SIL: Add a new Never type, and a TypeBase::isNever() check
Mostly NFC, this is just plumbing for the next patch. Note that isNever() returns true for any uninhabited enum. It should be generalized so that stuff like (Never, Int) is also known to be uninhabited, or even to support generic substitutions that yield uninhabited types, but for now I really see no reason to go that far, and the current check for an enum with no cases seems perfectly adequate.
1 parent 9738079 commit 6ff02a9

File tree

12 files changed

+102
-12
lines changed

12 files changed

+102
-12
lines changed

include/swift/AST/ASTContext.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,11 +440,15 @@ class ASTContext {
440440
/// Retrieve the declaration of the "pointee" property of a pointer type.
441441
VarDecl *getPointerPointeePropertyDecl(PointerTypeKind ptrKind) const;
442442

443+
/// Retrieve the declaration of Swift.Never.
444+
NominalTypeDecl *getNeverDecl() const;
445+
CanType getNeverType() const;
446+
443447
/// Retrieve the declaration of Swift.Void.
444448
TypeAliasDecl *getVoidDecl() const;
445449

446450
/// Retrieve the declaration of ObjectiveC.ObjCBool.
447-
StructDecl *getObjCBoolDecl();
451+
StructDecl *getObjCBoolDecl() const;
448452

449453
/// Retrieve the declaration of Foundation.NSError.
450454
ClassDecl *getNSErrorDecl() const;
@@ -491,7 +495,7 @@ class ASTContext {
491495
FuncDecl *getIsOSVersionAtLeastDecl(LazyResolver *resolver) const;
492496

493497
/// Look for the declaration with the given name within the
494-
/// swift module.
498+
/// Swift module.
495499
void lookupInSwiftModule(StringRef name,
496500
SmallVectorImpl<ValueDecl *> &results) const;
497501

include/swift/AST/Types.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,10 @@ class alignas(1 << TypeAlignInBits) TypeBase {
392392
/// hasReferenceSemantics() - Do objects of this type have reference
393393
/// semantics?
394394
bool hasReferenceSemantics();
395-
395+
396+
/// Is this an uninhabited type, such as 'Never'?
397+
bool isNever();
398+
396399
/// Is this the 'Any' type?
397400
bool isAny();
398401

include/swift/SIL/SILFunction.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ class SILFunction
215215
return LoweredType;
216216
}
217217

218+
bool isNoReturnFunction() const;
219+
218220
/// Unsafely rewrite the lowered type of this function.
219221
///
220222
/// This routine does not touch the entry block arguments

include/swift/SIL/SILInstruction.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,10 @@ class ApplyInstBase<Impl, Base, false> : public Base {
10021002
return SubstCalleeType;
10031003
}
10041004

1005+
bool isCalleeNoReturn() const {
1006+
return getSubstCalleeSILType().isNoReturnFunction();
1007+
}
1008+
10051009
bool isCalleeThin() const {
10061010
auto Rep = getSubstCalleeType()->getRepresentation();
10071011
return Rep == FunctionType::Representation::Thin;
@@ -5077,6 +5081,11 @@ class ApplySite {
50775081
FOREACH_IMPL_RETURN(getSubstCalleeSILType());
50785082
}
50795083

5084+
/// Check if this is a call of a never-returning function.
5085+
bool isCalleeNoReturn() const {
5086+
FOREACH_IMPL_RETURN(isCalleeNoReturn());
5087+
}
5088+
50805089
bool isCalleeThin() const {
50815090
switch (getSubstCalleeType()->getRepresentation()) {
50825091
case SILFunctionTypeRepresentation::CFunctionPointer:

include/swift/SIL/SILType.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,11 @@ class SILType {
285285
/// True if the type, or the referenced type of an address type, is a
286286
/// scalar reference-counted type.
287287
bool isReferenceCounted(SILModule &M) const;
288-
288+
289+
/// Returns true if the referenced type is a function type that never
290+
/// returns.
291+
bool isNoReturnFunction() const;
292+
289293
/// Returns true if the referenced type has reference semantics.
290294
bool hasReferenceSemantics() const {
291295
return getSwiftRValueType().hasReferenceSemantics();

lib/AST/ASTContext.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@ struct ASTContext::Implementation {
155155
/// The declaration of Swift.Unmanaged<T>
156156
NominalTypeDecl *UnmanagedDecl = nullptr;
157157

158+
/// The declaration of Swift.Never.
159+
NominalTypeDecl *NeverDecl = nullptr;
160+
158161
/// The declaration of Swift.Void.
159162
TypeAliasDecl *VoidDecl = nullptr;
160163

@@ -710,7 +713,7 @@ NominalTypeDecl *ASTContext::getUnsafeMutablePointerDecl() const {
710713
NominalTypeDecl *ASTContext::getOpaquePointerDecl() const {
711714
if (!Impl.OpaquePointerDecl)
712715
Impl.OpaquePointerDecl
713-
= findStdlibType(*this, "OpaquePointer", 0);
716+
= findStdlibType(*this, "OpaquePointer", 0);
714717

715718
return Impl.OpaquePointerDecl;
716719
}
@@ -784,6 +787,17 @@ ASTContext::getPointerPointeePropertyDecl(PointerTypeKind ptrKind) const {
784787
llvm_unreachable("bad pointer kind");
785788
}
786789

790+
NominalTypeDecl *ASTContext::getNeverDecl() const {
791+
if (!Impl.NeverDecl)
792+
Impl.NeverDecl = findStdlibType(*this, "Never", 0);
793+
794+
return Impl.NeverDecl;
795+
}
796+
797+
CanType ASTContext::getNeverType() const {
798+
return getNeverDecl()->getDeclaredType()->getCanonicalType();
799+
}
800+
787801
TypeAliasDecl *ASTContext::getVoidDecl() const {
788802
if (Impl.VoidDecl) {
789803
return Impl.VoidDecl;
@@ -802,10 +816,11 @@ TypeAliasDecl *ASTContext::getVoidDecl() const {
802816
return Impl.VoidDecl;
803817
}
804818

805-
StructDecl *ASTContext::getObjCBoolDecl() {
819+
StructDecl *ASTContext::getObjCBoolDecl() const {
806820
if (!Impl.ObjCBoolDecl) {
807821
SmallVector<ValueDecl *, 1> results;
808-
if (Module *M = getModuleByName(Id_ObjectiveC.str())) {
822+
auto *Context = const_cast<ASTContext *>(this);
823+
if (Module *M = Context->getModuleByName(Id_ObjectiveC.str())) {
809824
M->lookupValue({ }, getIdentifier("ObjCBool"), NLKind::UnqualifiedLookup,
810825
results);
811826
for (auto result : results) {

lib/AST/Type.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@ bool TypeBase::hasReferenceSemantics() {
8989
return getCanonicalType().hasReferenceSemantics();
9090
}
9191

92+
bool TypeBase::isNever() {
93+
if (auto nominalDecl = getAnyNominal())
94+
if (auto enumDecl = dyn_cast<EnumDecl>(nominalDecl))
95+
if (enumDecl->getAllElements().empty())
96+
return true;
97+
98+
return false;
99+
}
100+
92101
bool TypeBase::isAny() {
93102
return isEqual(getASTContext().TheAnyType);
94103
}

lib/IRGen/GenClangType.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,11 @@ GenClangType::visitBoundGenericType(CanBoundGenericType type) {
489489
}
490490

491491
clang::CanQualType GenClangType::visitEnumType(CanEnumType type) {
492+
// Special case: Uninhabited enums are not @objc, so we don't
493+
// know what to do below, but we can just convert to 'void'.
494+
if (type->isNever())
495+
return Converter.convert(IGM, IGM.Context.TheEmptyTupleType);
496+
492497
assert(type->getDecl()->isObjC() && "not an @objc enum?!");
493498

494499
// @objc enums lower to their raw types.

lib/SIL/SILFunction.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,11 @@ Type SILFunction::mapTypeOutOfContext(Type type) const {
294294
type);
295295
}
296296

297+
bool SILFunction::isNoReturnFunction() const {
298+
return SILType::getPrimitiveObjectType(getLoweredFunctionType())
299+
.isNoReturnFunction();
300+
}
301+
297302
SILBasicBlock *SILFunction::createBasicBlock() {
298303
return new (getModule()) SILBasicBlock(this);
299304
}

lib/SIL/SILType.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,17 @@ bool SILType::isReferenceCounted(SILModule &M) const {
7070
return M.getTypeLowering(*this).isReferenceCounted();
7171
}
7272

73+
bool SILType::isNoReturnFunction() const {
74+
if (auto funcTy = dyn_cast<SILFunctionType>(getSwiftRValueType())) {
75+
if (funcTy->isNoReturn())
76+
return true;
77+
78+
return funcTy->getSILResult().getSwiftRValueType()->isNever();
79+
}
80+
81+
return false;
82+
}
83+
7384
std::string SILType::getAsString() const {
7485
std::string Result;
7586
llvm::raw_string_ostream OS(Result);

lib/Sema/TypeCheckStmt.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -998,7 +998,13 @@ bool TypeChecker::typeCheckCatchPattern(CatchStmt *S, DeclContext *DC) {
998998
}
999999
return false;
10001000
}
1001-
1001+
1002+
static bool isDiscardableType(Type type) {
1003+
return (type->is<ErrorType>() ||
1004+
type->isNever() ||
1005+
type->lookThroughAllAnyOptionalTypes()->isVoid());
1006+
}
1007+
10021008
void TypeChecker::checkIgnoredExpr(Expr *E) {
10031009
// For parity with C, several places in the grammar accept multiple
10041010
// comma-separated expressions and then bind them together as an implicit
@@ -1041,10 +1047,10 @@ void TypeChecker::checkIgnoredExpr(Expr *E) {
10411047
return;
10421048
}
10431049

1044-
// If the result of this expression is of type "()" potentially wrapped in
1045-
// optionals, then it is safe to ignore.
1046-
if (valueE->getType()->lookThroughAllAnyOptionalTypes()->isVoid() ||
1047-
valueE->getType()->is<ErrorType>())
1050+
// If the result of this expression is of type "Never" or "()"
1051+
// (the latter potentially wrapped in optionals) then it is
1052+
// safe to ignore.
1053+
if (isDiscardableType(valueE->getType()))
10481054
return;
10491055

10501056
// Complain about '#selector'.

stdlib/public/core/Policy.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,23 @@
1212
// Swift Standard Prolog Library.
1313
//===----------------------------------------------------------------------===//
1414

15+
//===----------------------------------------------------------------------===//
16+
// Standardized uninhabited type
17+
//===----------------------------------------------------------------------===//
18+
/// The return type of functions that do not return normally; a type with no
19+
/// values.
20+
///
21+
/// Use `Never` as the return type when declarting a closure, function, or
22+
/// method that unconditionally throws an error, traps, or otherwise does
23+
/// not terminate.
24+
///
25+
/// func crashAndBurn() -> Never {
26+
/// fatalError("Something very, very bad happened")
27+
/// }
28+
29+
@_fixed_layout
30+
public enum Never {}
31+
1532
//===----------------------------------------------------------------------===//
1633
// Standardized aliases
1734
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)