Rollup merge of #25900 - lorenzb:more_about_types, r=nikomatsakis

My main sources of information are [RFC401](https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md), the rust IRC channel, and a bunch of experiments to figure out what `rustc` currently supports.
Note that the RFC calls for some coercion behaviour that is not implemented yet (see #18469).
The documentation in this PR mostly covers current behaviour of rust and doesn't document the future behaviour. I haven't written about receiver expression coercion.

I would be happy to rewrite/adapt the PR according to feedback.

r? @steveklabnik
This commit is contained in:
Manish Goregaokar 2015-06-04 10:07:02 +05:30
commit 8c2806caae
1 changed files with 140 additions and 0 deletions

View File

@ -3599,6 +3599,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.