Skip to content

Extend rust reference with section about subtyping and type coercions #25900

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 2 commits into from
Jun 4, 2015
Merged
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
140 changes: 140 additions & 0 deletions src/doc/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -3608,6 +3608,146 @@ The notation `&self` is a shorthand for `self: &Self`. In this case,
in the impl, `Self` refers to the value of type `String` that is the
receiver for a call to the method `make_string`.

## Subtyping

Subtyping is implicit and can occur at any stage in type checking or
inference. Subtyping in Rust is very restricted and occurs only due to
variance with respect to lifetimes and between types with higher ranked
lifetimes. If we were to erase lifetimes from types, then the only subtyping
would be due to type equality.

Consider the following example: string literals always have `'static`
lifetime. Nevertheless, we can assign `s` to `t`:

```
fn bar<'a>() {
let s: &'static str = "hi";
let t: &'a str = s;
}
```
Since `'static` "lives longer" than `'a`, `&'static str` is a subtype of
`&'a str`.

## Type coercions

Coercions are defined in [RFC401]. A coercion is implicit and has no syntax.

[RFC401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md

### Coercion sites

A coercion can only occur at certain coercion sites in a program; these are
typically places where the desired type is explicit or can be dervied by
propagation from explicit types (without type inference). Possible coercion
sites are:

* `let` statements where an explicit type is given.

In `let _: U = e;`, `e` is coerced to have type `U`.

* `static` and `const` statements (similar to `let` statements).

* arguments for function calls.

The value being coerced is the
actual parameter and it is coerced to the type of the formal parameter. For
example, let `foo` be defined as `fn foo(x: U) { ... }` and call it as
`foo(e);`. Then `e` is coerced to have type `U`;

* instantiations of struct or variant fields.

Assume we have a `struct
Foo { x: U }` and instantiate it as `Foo { x: e }`. Then `e` is coerced to
have type `U`.

* function results (either the final line of a block if it is not semicolon
terminated or any expression in a `return` statement).

In `fn foo() -> U { e }`, `e` is coerced to to have type `U`.

If the expression in one of these coercion sites is a coercion-propagating
expression, then the relevant sub-expressions in that expression are also
coercion sites. Propagation recurses from these new coercion sites.
Propagating expressions and their relevant sub-expressions are:

* array literals, where the array has type `[U; n]`. Each sub-expression in
the array literal is a coercion site for coercion to type `U`.

* array literals with repeating syntax, where the array has type `[U; n]`. The
repeated sub-expression is a coercion site for coercion to type `U`.

* tuples, where a tuple is a coercion site to type `(U_0, U_1, ..., U_n)`.
Each sub-expression is a coercion site to the respective type, e.g. the
zeroth sub-expression is a coercion site to type `U_0`.

* parenthesised sub-expressions (`(e)`). If the expression has type `U`, then
the sub-expression is a coercion site to `U`.

* blocks. If a block has type `U`, then the last expression in the block (if
it is not semicolon-terminated) is a coercion site to `U`. This includes
blocks which are part of control flow statements, such as `if`/`else`, if
the block has a known type.

### Coercion types

Coercion is allowed between the following types:

* `T` to `U` if `T` is a subtype of `U` (*reflexive case*).

* `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to `T_3`
(*transitive case*).

Note that this is not fully supported yet

* `&mut T` to `&T`.

* `*mut T` to `*const T`.

* `&T` to `*const T`.

* `&mut T` to `*mut T`.

* `&T` to `&U` if `T` implements `Deref<Target = U>`. For example:
```
use std::ops::Deref;

struct CharContainer {
value: char
}

impl Deref for CharContainer {
type Target = char;

fn deref<'a>(&'a self) -> &'a char {
&self.value
}
}

fn foo(arg: &char) {}

fn main() {
let x = &mut CharContainer { value: 'y' };
foo(x); //&mut CharContainer is coerced to &char.
}
```
* `&mut T` to `&mut U` if `T` implements `DerefMut<Target = U>`.

* TyCtor(`T`) to TyCtor(coerce_inner(`T`)), where TyCtor(`T`) is one of
- `&T`
- `&mut T`
- `*const T`
- `*mut T`
- `Box<T>`

and where
- coerce_inner(`[T, ..n]`) = `[T]`
- coerce_inner(`T`) = `U` where `T` is a concrete type which implements the
trait `U`.

In the future, coerce_inner will be recursively extended to tuples and
structs. In addition, coercions from sub-traits to super-traits will be
added. See [RFC401] for more details.

# Special traits

Several traits define special evaluation behavior.
Expand Down