Skip to content
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

Add identifier syntax to type-coercions.md #1632

Merged
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
55 changes: 54 additions & 1 deletion src/type-coercions.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
# Type coercions

r[coerce]

r[coerce.intro]
**Type coercions** are implicit operations that change the type of a value.
They happen automatically at specific locations and are highly restricted in
what types actually coerce.

r[cerce.as]
Any conversions allowed by coercion can also be explicitly performed by the
[type cast operator], `as`.

Coercions are originally defined in [RFC 401] and expanded upon in [RFC 1558].

## Coercion sites

r[coerce.site]

r[coerce.site.intro]
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 derived by
propagation from explicit types (without type inference). Possible coercion
sites are:

r[coerce.site.let]
* `let` statements where an explicit type is given.

For example, `&mut 42` is coerced to have type `&i8` in the following:
Expand All @@ -24,8 +32,10 @@ sites are:
let _: &i8 = &mut 42;
```

r[coerce.site.value]
* `static` and `const` item declarations (similar to `let` statements).

r[coerce.site.argument]
* Arguments for function calls

The value being coerced is the actual parameter, and it is coerced to
Expand All @@ -44,6 +54,7 @@ sites are:
For method calls, the receiver (`self` parameter) type is coerced
differently, see the documentation on [method-call expressions] for details.

r[coerce.site.constructor]
* Instantiations of struct, union, or enum variant fields

For example, `&mut 42` is coerced to have type `&i8` in the following:
Expand All @@ -56,6 +67,7 @@ sites are:
}
```

r[coerce.site.return]
* Function results—either the final line of a block if it is not
semicolon-terminated or any expression in a `return` statement

Expand All @@ -68,48 +80,64 @@ sites are:
}
```

r[coerce.site.subexpr]
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:

r[coerce.site.array]
* 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`.

r[coerce.site.repeat]
* 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`.

r[coerce.site.tuple]
* 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`.

r[coerce.site.parenthesis]
* Parenthesized sub-expressions (`(e)`): if the expression has type `U`, then
the sub-expression is a coercion site to `U`.

r[coerce.site.block]
* 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

r[coerce.types]

r[coerce.types.intro]
Coercion is allowed between the following types:

r[coerce.types.reflexive]
* `T` to `U` if `T` is a [subtype] of `U` (*reflexive case*)

r[coerce.types.transitive]
* `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.

r[coerce.types.mut-reborrow]
* `&mut T` to `&T`

r[coerce.types.mut-pointer]
* `*mut T` to `*const T`

r[coerce.types.ref-to-pointer]
* `&T` to `*const T`

r[coerce.types.mut-to-pointer]
* `&mut T` to `*mut T`

r[coerce.types.deref]
* `&T` or `&mut T` to `&U` if `T` implements `Deref<Target = U>`. For example:

```rust
Expand All @@ -135,8 +163,10 @@ Coercion is allowed between the following types:
}
```

r[coerce.types.deref-mut]
* `&mut T` to `&mut U` if `T` implements `DerefMut<Target = U>`.

r[coerce.types.unsize]
* TyCtor(`T`) to TyCtor(`U`), where TyCtor(`T`) is one of
- `&T`
- `&mut T`
Expand All @@ -150,35 +180,46 @@ Coercion is allowed between the following types:
structs. In addition, coercions from subtraits to supertraits will be
added. See [RFC 401] for more details.-->

r[coerce.types.fn]
* Function item types to `fn` pointers

r[coerce.types.closure]
* Non capturing closures to `fn` pointers

r[coerce.types.never]
* `!` to any `T`

### Unsized Coercions

r[coerce.unsize]

r[coerce.unsize.intro]
The following coercions are called `unsized coercions`, since they
relate to converting sized types to unsized types, and are permitted in a few
cases where other coercions are not, as described above. They can still happen
anywhere else a coercion can occur.

r[coerce.unsize.trait]
Two traits, [`Unsize`] and [`CoerceUnsized`], are used
to assist in this process and expose it for library use. The following
coercions are built-ins and, if `T` can be coerced to `U` with one of them, then
an implementation of `Unsize<U>` for `T` will be provided:

r[coerce.unsize.slice]
* `[T; n]` to `[T]`.

r[coerce.unsize.trait-object]
* `T` to `dyn U`, when `T` implements `U + Sized`, and `U` is [object safe].

r[coerce.unsized.composite]
* `Foo<..., T, ...>` to `Foo<..., U, ...>`, when:
* `Foo` is a struct.
* `T` implements `Unsize<U>`.
* The last field of `Foo` has a type involving `T`.
* If that field has type `Bar<T>`, then `Bar<T>` implements `Unsized<Bar<U>>`.
* T is not part of the type of any other fields.

r[coerce.unsized.pointer]
Additionally, a type `Foo<T>` can implement `CoerceUnsized<Foo<U>>` when `T`
implements `Unsize<U>` or `CoerceUnsized<Foo<U>>`. This allows it to provide an
unsized coercion to `Foo<U>`.
Expand All @@ -189,6 +230,9 @@ unsized coercion to `Foo<U>`.

## Least upper bound coercions

r[coerce.least-upper-bound]

r[coerce.least-upper-bound.intro]
In some contexts, the compiler must coerce together multiple types to try and
find the most general type. This is called a "Least Upper Bound" coercion.
LUB coercion is used and only used in the following situations:
Expand All @@ -199,15 +243,24 @@ LUB coercion is used and only used in the following situations:
+ To find the type for the return type of a closure with multiple return statements.
+ To check the type for the return type of a function with multiple return statements.

r[coerce.least-upper-bound.target]
In each such case, there are a set of types `T0..Tn` to be mutually coerced
to some target type `T_t`, which is unknown to start. Computing the LUB
to some target type `T_t`, which is unknown to start.

r[coerce.least-upper-bound.computation]
Computing the LUB
coercion is done iteratively. The target type `T_t` begins as the type `T0`.
For each new type `Ti`, we consider whether

r[coerce.least-upper-bound.computation-identity]
+ If `Ti` can be coerced to the current target type `T_t`, then no change is made.

r[coerce.least-upper-bound.computation-replace]
+ Otherwise, check whether `T_t` can be coerced to `Ti`; if so, the `T_t` is
changed to `Ti`. (This check is also conditioned on whether all of the source
expressions considered thus far have implicit coercions.)

r[coerce.least-upper-bound.computation-unify]
+ If not, try to compute a mutual supertype of `T_t` and `Ti`, which will become the new target type.

### Examples:
Expand Down