Skip to content

Commit d35d19b

Browse files
committed
Explain the new valtree system for type level constants.
1 parent 0687daa commit d35d19b

File tree

1 file changed

+31
-3
lines changed

1 file changed

+31
-3
lines changed

src/const-eval.md

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,44 @@ Additionally constant evaluation can be used to reduce the workload or binary
2020
size at runtime by precomputing complex operations at compiletime and only
2121
storing the result.
2222

23+
All uses of constant evaluation can either be categorized as "influencing the type system"
24+
(array lengths, enum variant discriminants, const generic parameters), or as solely being
25+
done to precompute expressions to be used at runtime.
26+
2327
Constant evaluation can be done by calling the `const_eval_*` functions of `TyCtxt`.
2428
They're the wrappers of the `const_eval` query.
2529

30+
`static` initializers must use the `eval_static_initializer` function. All other functions
31+
do not represent statics correctly and have thus assertions preventing their use on statics.
32+
2633
The `const_eval_*` functions use a [`ParamEnv`](./param_env.html) of environment
2734
in which the constant is evaluated (e.g. the function within which the constant is used)
2835
and a [`GlobalId`]. The `GlobalId` is made up of an `Instance` referring to a constant
2936
or static or of an `Instance` of a function and an index into the function's `Promoted` table.
3037

31-
Constant evaluation returns a [`EvalToConstValueResult`] with either the error, or a
32-
representation of the constant. `static` initializers are always represented as
33-
[`miri`](./miri.html) virtual memory allocations (via [`ConstValue::ByRef`]).
38+
Constant evaluation returns a [`EvalToValTreeResult`] (for type system constants) or [`EvalToConstValueResult`] with either the error, or a
39+
representation of the constant.
40+
41+
Constants for the type system are encoded in "valtree representation". The `ValTree` datastructure
42+
allows us to represent arrays, many structs, tuples, enums and most primitives. The basic rule for
43+
being permitted in the type system is that every value must be uniquely represented. In other words:
44+
a specific value must only be representable in one specific way. For example: there is only one way
45+
to represent an array of two integers as a `ValTree`: `ValTree::Branch(&[ValTree::Leaf(first_int), ValTree;:Leaf(second_int)])`.
46+
Even though theoretically a `[u32; 2]` could be encoded in a `u64` and thus just be a `ValTree::Leaf(bits_of_two_u32)`, that
47+
is not a legal construction of `ValTree` (and is so complex to do, that it is unlikely to tempt anyone to do so).
48+
These rules also mean that some values are not representable. There can be no `union`s in type level
49+
constants, as it is not clear how they should be represented, because their active variant is unknown.
50+
Similarly there is no way to represent pointers, as addresses are unknown at compile-time and thus we
51+
cannot make any assumptions about them. References on the other hand can be represented, as equality
52+
for references is defined as equality on their value, so we ignore their address and just look at the
53+
backing value. This means that there is no difference in encoding for `&42` and `42`.
54+
As a consequence, all decoding of `ValTree` must happen by matching on the type first and making decisions
55+
depending on that. The value itself gives no useful information without the type that belongs to it.
56+
One notable oddity is `&str` representation. There is no sized equivalent of it, so unlike slices we cannot
57+
choose to represent them as their sized variant (slices are represented as arrays). `&str` thus has
58+
its own `ValTree` variant `Str`. The advantage of using a custom variant is that we are able to translate
59+
parser/AST/HIR string literals without any conversion as we use the same (`Symbol`) representation.
60+
3461
Other constants get represented as [`ConstValue::Scalar`]
3562
or [`ConstValue::Slice`] if possible. This means that the `const_eval_*`
3663
functions cannot be used to create miri-pointers to the evaluated constant.
@@ -42,4 +69,5 @@ If you need the value of a constant inside Miri, you need to directly work with
4269
[`ConstValue::Slice`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/value/enum.ConstValue.html#variant.Slice
4370
[`ConstValue::ByRef`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/value/enum.ConstValue.html#variant.ByRef
4471
[`EvalToConstValueResult`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/error/type.EvalToConstValueResult.html
72+
[`EvalToValTreeResult`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/error/type.EvalToValTreeResult.html
4573
[`eval_const_to_op`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_mir/interpret/struct.InterpCx.html#method.eval_const_to_op

0 commit comments

Comments
 (0)