diff --git a/src/expressions/loop-expr.md b/src/expressions/loop-expr.md index 2577689bd..9cd1120ba 100644 --- a/src/expressions/loop-expr.md +++ b/src/expressions/loop-expr.md @@ -36,12 +36,10 @@ Only `loop` supports [evaluation to non-trivial values](#break-and-loop-values). A `loop` expression repeats execution of its body continuously: `loop { println!("I live."); }`. -A `loop` expression without an associated `break` expression is -[diverging](items/functions.html#diverging-functions), and doesn't -return anything. A `loop` expression containing associated -[`break` expression(s)](#break-expressions) -may terminate, and must have type compatible with the value of the `break` -expression(s). +A `loop` expression without an associated `break` expression is diverging and +has type [`!`](types.html#never-type). A `loop` expression containing +associated [`break` expression(s)](#break-expressions) may terminate, and must +have type compatible with the value of the `break` expression(s). ## Predicate loops diff --git a/src/items/functions.md b/src/items/functions.md index 16b4a3e8c..0ccdeaa61 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -93,52 +93,6 @@ sufficient context to determine the type parameters. For example, [path]: paths.html -## Diverging functions - -A special kind of function can be declared with a `!` character where the -output type would normally be. For example: - -```rust -fn my_err(s: &str) -> ! { - println!("{}", s); - panic!(); -} -``` - -We call such functions "diverging" because they never return a value to the -caller. Every control path in a diverging function must end with a `panic!()`, -a loop expression without an associated break expression, or a call to another -diverging function on every control path. The `!` annotation does *not* denote -a type. - -It might be necessary to declare a diverging function because as mentioned -previously, the typechecker checks that every control path in a function ends -with a [`return`] or diverging expression. So, if `my_err` were declared -without the `!` annotation, the following code would not typecheck: - -[`return`]: expressions/return-expr.html - -```rust -# fn my_err(s: &str) -> ! { panic!() } - -fn f(i: i32) -> i32 { - if i == 42 { - return 42; - } - else { - my_err("Bad number!"); - } -} -``` - -This will not compile without the `!` annotation on `my_err`, since the `else` -branch of the conditional in `f` does not return an `i32`, as required by the -signature of `f`. Adding the `!` annotation to `my_err` informs the typechecker -that, should control ever enter `my_err`, no further type judgments about `f` -need to hold, since control will never resume in any context that relies on -those judgments. Thus the return type on `f` only needs to reflect the `if` -branch of the conditional. - ## Extern functions Extern functions are part of Rust's foreign function interface, providing the @@ -169,4 +123,4 @@ As non-Rust calling conventions do not support unwinding, unwinding past the end of an extern function will cause the process to abort. In LLVM, this is implemented by executing an illegal instruction. -[external blocks]: items/external-blocks.html \ No newline at end of file +[external blocks]: items/external-blocks.html diff --git a/src/special-types-and-traits.md b/src/special-types-and-traits.md index 497eceb3d..119a1c36b 100644 --- a/src/special-types-and-traits.md +++ b/src/special-types-and-traits.md @@ -52,7 +52,7 @@ whose type implements `Copy` are copied rather than moved upon assignment. fields that are not `Copy`. `Copy` is implemented by the compiler for * [Numeric types] -* `char` and `bool` +* `char`, `bool` and [`!`] * [Tuples] of `Copy` types * [Arrays] of `Copy` types * [Shared references] @@ -151,3 +151,4 @@ compiler, not by [implementation items]. [Tuples]: types.html#tuple-types [Type parameters]: types.html#type-parameters [variance]: ../nomicon/subtyping.html +[`!`]: types.html#never-type diff --git a/src/type-coercions.md b/src/type-coercions.md index 22b6ceefc..c8719aee4 100644 --- a/src/type-coercions.md +++ b/src/type-coercions.md @@ -148,6 +148,8 @@ Coercion is allowed between the following types: * Non capturing closures to `fn` pointers +* `!` to any `T` + ### Unsized Coercions The following coercions are called `unsized coercions`, since they diff --git a/src/types.md b/src/types.md index 77a05cc37..1cf257d19 100644 --- a/src/types.md +++ b/src/types.md @@ -17,6 +17,7 @@ types: * The [machine types] (integer and floating-point). * The [machine-dependent integer types]. * The [textual types] `char` and `str`. +* The [never type] `!` There are also some primitive constructs for generic types built in to the language: @@ -31,6 +32,7 @@ language: [machine types]: #machine-types [machine-dependent integer types]: #machine-dependent-integer-types [textual types]: #textual-types +[never-type]: #never-type [Tuples]: #tuple-types [Arrays]: #array-and-slice-types [Slices]: #array-and-slice-types @@ -84,6 +86,12 @@ unsigned bytes holding a sequence of UTF-8 code points. Since `str` is a [dynamically sized type], it is not a _first-class_ type, but can only be instantiated through a pointer type, such as `&str`. +## Never type + +The never type `!` is a type with no values, representing the result of +computations that never complete. Expressions of type `!` can be coerced into +any other type. + ## Tuple types A tuple *type* is a heterogeneous product of other types, called the *elements* @@ -653,4 +661,4 @@ impl Printable for String { [issue 47010]: https://github.com/rust-lang/rust/issues/47010 [issue 33140]: https://github.com/rust-lang/rust/issues/33140 [_PATH_]: paths.html -[_LIFETIME_OR_LABEL_]: tokens.html#lifetimes-and-loop-labels \ No newline at end of file +[_LIFETIME_OR_LABEL_]: tokens.html#lifetimes-and-loop-labels