diff --git a/src/type-coercions.md b/src/type-coercions.md index 7d254f4e7..a96e749de 100644 --- a/src/type-coercions.md +++ b/src/type-coercions.md @@ -1,9 +1,13 @@ # 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`. @@ -11,11 +15,15 @@ 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: @@ -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 @@ -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: @@ -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 @@ -68,24 +80,30 @@ 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 @@ -93,23 +111,33 @@ 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`. For example: ```rust @@ -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`. +r[coerce.types.unsize] * TyCtor(`T`) to TyCtor(`U`), where TyCtor(`T`) is one of - `&T` - `&mut T` @@ -150,28 +180,38 @@ 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` 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`. @@ -179,6 +219,7 @@ an implementation of `Unsize` for `T` will be provided: * If that field has type `Bar`, then `Bar` implements `Unsized>`. * T is not part of the type of any other fields. +r[coerce.unsized.pointer] Additionally, a type `Foo` can implement `CoerceUnsized>` when `T` implements `Unsize` or `CoerceUnsized>`. This allows it to provide an unsized coercion to `Foo`. @@ -189,6 +230,9 @@ unsized coercion to `Foo`. ## 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: @@ -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: