Add type ascription to expressions.式
(An earlier version of this RFC covered type ascription in patterns too, that has been postponed).
Type ascription on expression式
has already been implemented.実装する
See also discussion on #354 and rust issue 10502 .
Type inference is imperfect. It is often useful to help type inference by annotating a sub-expression with a type. Currently, this is only possible by extracting抽出する
the sub-expression into a variable変数、ストレージ
using a let
statement文
and/or giving a type for a whole expression式
or pattern. This is un- ergonomic, and sometimes impossible due to lifetime issues. Specifically,特に
where a variable変数、ストレージ
has lifetime of its enclosing囲う
scope, but a sub-expression's lifetime is typically一般的に、典型的に
limited to the nearest semi-colon.
Typical use cases are where a function's return type is generic (e.g., collect) and where we want to force a coercion.
Type ascription can also be used for documentation文書
and debugging - where it is unclear from the code which type will be inferred, type ascription can be used to precisely正確に
communicate通信する
expectations to the compiler or other programmers.
By allowing許可する、可能にする
type ascription in more places, we remove the inconsistency that type ascription is currently only allowed許可する、可能にする
on top-level patterns.
(Somewhat simplified examples, in these cases there are sometimes better solutions with the current syntax).
Generic return type:
// Current.
let z = if ... {
let x: Vec<_> = foo.enumerate().collect();
x
} else {
...
};
// With type ascription.
let z = if ... {
foo.enumerate().collect(): Vec<_>
} else {
...
};
Coercion:
fn foo<T>(a: T, b: T) { ... }
// Current.
let x = [1u32, 2, 4];
let y = [3u32];
...
let x: &[_] = &x;
let y: &[_] = &y;
foo(x, y);
// With type ascription.
let x = [1u32, 2, 4];
let y = [3u32];
...
foo(x: &[_], y: &[_]);
Generic return type and coercion:
// Current.
let x: T = {
let temp: U<_> = foo();
temp
};
// With type ascription.
let x: T = foo(): U<_>;
The syntax文法
of expressions式
is extended拡張する
with type ascription:
e ::= ... | e: T
where e
is an expression式
and T
is a type. Type ascription has the same precedence優先順位
as explicit明示的な
coercions using as
.
When type checking e: T
, e
must have type T
. The must have type
test includes implicit暗黙の
coercions and subtyping, but not explicit明示的な
coercions. T
may be any well-formed type.
At runtime, type ascription is a no-op, unless an implicit暗黙の
coercion was used in type checking, in which case the dynamic動的
semantics of a type ascription expression式
are exactly正確に
those of the implicit暗黙の
coercion.
@eddyb has implemented実装する
the expressions式
part of this RFC, PR .
This feature should land behind the ascription
feature gate.
A downside of type ascription is the overlap重なる/重なり
with explicit明示的な
coercions (aka casts, the as
operator). To the programmer, type ascription makes implicit暗黙の
coercions explicit明示的な
(however, the compiler makes no distinction between coercions due to type ascription and other coercions). In RFC 401, it is proposed that all valid有効な、正しい
implicit暗黙の
coercions are valid有効な、正しい
explicit明示的な
coercions. However, that may be too confusing for users, since there is no reason to use type ascription rather than as
(if there is some coercion). Furthermore, if programmers do opt to use as
as the default whether or not it is required, then it loses its function as a warning sign符号
for programmers to beware of.
To address this I propose two lints which check for: trivial casts and trivial numeric数の、数値の
casts. Other than these lints we stick with the proposal from #401 that unnecessary casts will no longer be an error.
A trivial cast is a cast x as T
where x
has type U
and x
can be implicitly暗黙的に
coerced to T
or is already a subtype of T
.
A trivial numeric数の、数値の
cast is a cast x as T
where x
has type U
and x
is implicitly暗黙的に
coercible to T
or U
is a subtype of T
, and both U
and T
are numeric数の、数値の
types.
Like any lints, these can be customised per-crate by the programmer. Both lints are 'warn' by default.
Although this is a somewhat complex複素数、複文の
scheme, it allows許可する、可能にする
code that works today to work with only minor adjustment, it allows許可する、可能にする
for a backwards compatible path to 'promoting' type conversions変換
from explicit明示的な
casts to implicit暗黙の
coercions, and it allows許可する、可能にする
customisation of a contentious kind of error (especially so in the context文脈、背景
of cross-platform programming).
There is an implementation実装
choice between treating取り扱う
x: T
as an lvalue or rvalue. Note that when an rvalue is used in 'reference参照
context'文脈、背景
(e.g., the subject of a reference参照
operation), then the compiler introduces a temporary一時的な
variable.変数、ストレージ
Neither option is satisfactory, if we treat取り扱う
an ascription expression式
as an lvalue (i.e., no new temporary), then there is potential for unsoundness:
let mut foo: S = ...;
{
let bar = &mut (foo: T); // S <: T, no coercion required
*bar = ... : T;
}
// Whoops, foo has type T, but the compiler thinks it has type S, where potentially T </: S
If we treat取り扱う
ascription expressions式
as rvalues (i.e., create a temporary一時的な
in lvalue position), then we don't have the soundness problem, but we do get the unexpected result結果、戻り値
that &(x: T)
is not in fact a reference参照
to x
, but a reference参照
to a temporary一時的な
copy of x
.
The proposed solution is that type ascription expressions式
inherit継承する
their 'lvalue-ness' from their underlying裏に潜んだ、背後の
expressions.式
I.e., e: T
is an lvalue if e
is an lvalue, and an rvalue otherwise.さもなければ
If the type ascription expression式
is in reference参照
context,文脈、背景
then we require the ascribed type to exactly正確に
match一致する、マッチさせる
the type of the expression,式
i.e., neither subtyping nor coercion is allowed.許可する、可能にする
These reference参照
contexts are as follows下記の、次に続く、追従する
(where <expr>
is a type ascription expression):
&[mut] <expr>
let ref [mut] x = <expr>
match <expr> { .. ref [mut] x .. => { .. } .. }
<expr>.foo() // due to autoref
<expr> = ...;
More syntax,文法
another feature in the language.言語
Interacts poorly with struct構造、構造体
initialisers (changing the syntax文法
for struct構造、構造体
literals has been discussed and rejected and again in discuss ).
If we introduce named arguments引数
in the future, then it would make it more difficult to support the same syntax文法
as field initialisers.
We could do nothing and force programmers to use temporary一時的な
variables変数、ストレージ
to specify特定する、指定する、規定する
a type. However, this is less ergonomic and has problems with scopes/lifetimes.
Rely on explicit明示的な
coercions - the current plan RFC 401 is to allow許可する、可能にする
explicit明示的な
coercion to any valid有効な、正しい
type and to use a customisable lint for trivial casts (that is, those given与えられた
by subtyping, including the identity同一性
case). If we allow許可する、可能にする
trivial casts, then we could always use explicit明示的な
coercions instead of type ascription. However, we would then lose the distinction between implicit暗黙の
coercions which are safe and explicit明示的な
coercions, such as narrowing, which require more programmer attention. This also does not help with patterns.
We could use a different symbol or keyword instead of :
, e.g., is
.
Is the suggested precedence優先順位
correct?
Should we remove integer整数
suffixes in favour of type ascription?
Style guidelines - should we recommend spacing or parenthesis to make type ascription syntax文法
more easily recognisable?