Skip to content

add docs for never type #206

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions src/expressions/loop-expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
48 changes: 1 addition & 47 deletions src/items/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,52 +93,6 @@ sufficient context to determine the type parameters. For example,

[path]: paths.html

## Diverging functions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove this? The information about what constructs produce the ! return type remains useful. Also, the new section below doesn't use "diverges", "diverge", or "divergent", though we make use of "diverges" in the section about loop {}s.

I say just keep this section in tact, with adjustments to account for new thinking about the Never Type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's not really a good reason to have information on divergence in the function items page. Perhaps mention in the function call and method call operators that calling a function that returns ! diverges? Divergence sort of needs its own section in the Expressions page itself, I think? I haven't thought too much about whether it's a property of expressions, statements, or both? And that can be done separately from this.

It would be nice to pull the example into the Never type docs though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @Havvy here. Divergence isn't specifically a property of functions, it's its own thing entirely and really needs its own section. I don't fully understand the semantics of it though, so I'm not confident that I'd be able to write that section.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, put the information where ever you think it fits best, but I don't want to lose the information.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe someone like @arielb1 can help here. Is this an accurate-enough description of type-checking w.r.t divergence and !?

  • Expressions of type ! cause everything in the computation graph after the ! to be marked unreachable.
  • If a block ends in a statement, and the end of the block is unreachable, then the block has type !.

I know it's not exactly implemented like this in the compiler, but have I left out any relevant caveats? Do you think the reference needs a section on divergence separate from !?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll make sure that divergence information doesn't get lost before the next beta, even if this PR loses it.


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
Expand Down Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated to this PR, but why does this keep showing up? And why this time in a file that is otherwise untouched?

[external blocks]: items/external-blocks.html
3 changes: 2 additions & 1 deletion src/special-types-and-traits.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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
2 changes: 2 additions & 0 deletions src/type-coercions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 9 additions & 1 deletion src/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Expand Down Expand Up @@ -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*
Expand Down Expand Up @@ -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
[_LIFETIME_OR_LABEL_]: tokens.html#lifetimes-and-loop-labels