Skip to content

Commit 18521bb

Browse files
committed
Explain the new valtree system for type level constants.
1 parent 290ecb9 commit 18521bb

File tree

1 file changed

+49
-3
lines changed

1 file changed

+49
-3
lines changed

src/const-eval.md

+49-3
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,62 @@ 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+
* `const_eval_global_id_for_typeck` evaluates a constant to a valtree,
31+
so the result value can be further inspected by the compiler.
32+
* `const_eval_global_id` evaluate a constant to an "opaque blob" containing its final value;
33+
this is only useful for codegen backends and the CTFE evaluator engine itself.
34+
* `eval_static_initializer` specifically computes the initial values of a static.
35+
Statics are special; all other functions do not represent statics correctly
36+
and have thus assertions preventing their use on statics.
37+
2638
The `const_eval_*` functions use a [`ParamEnv`](./param_env.html) of environment
2739
in which the constant is evaluated (e.g. the function within which the constant is used)
2840
and a [`GlobalId`]. The `GlobalId` is made up of an `Instance` referring to a constant
2941
or static or of an `Instance` of a function and an index into the function's `Promoted` table.
3042

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`]).
43+
Constant evaluation returns an [`EvalToValTreeResult`] for type system constants or
44+
[`EvalToConstValueResult`] with either the error, or a representation of the constant.
45+
46+
Constants for the type system are encoded in "valtree representation". The `ValTree` datastructure
47+
allows us to represent
48+
49+
* arrays,
50+
* many structs,
51+
* tuples,
52+
* enums and,
53+
* most primitives.
54+
55+
The basic rule for
56+
being permitted in the type system is that every value must be uniquely represented. In other
57+
words: a specific value must only be representable in one specific way. For example: there is only
58+
one way to represent an array of two integers as a `ValTree`:
59+
`ValTree::Branch(&[ValTree::Leaf(first_int), ValTree;:Leaf(second_int)])`.
60+
Even though theoretically a `[u32; 2]` could be encoded in a `u64` and thus just be a
61+
`ValTree::Leaf(bits_of_two_u32)`, that is not a legal construction of `ValTree`
62+
(and is very complex to do, so it is unlikely anyone is tempted to do so).
63+
64+
These rules also mean that some values are not representable. There can be no `union`s in type
65+
level constants, as it is not clear how they should be represented, because their active variant
66+
is unknown. Similarly there is no way to represent pointers, as addresses are unknown at
67+
compile-time and thus we cannot make any assumptions about them. References on the other hand
68+
*can* be represented, as equality for references is defined as equality on their value, so we
69+
ignore their address and just look at the backing value. We must make sure that the pointer value
70+
of the references are not observable. We thus encode `&42` exactly like `42`. Any conversion from
71+
valtree back to codegen constants must reintroduce an actual indirection. At codegen time the
72+
addresses may be deduplicated between multiple uses or not, entirely depending on arbitrary
73+
optimization choices.
74+
75+
As a consequence, all decoding of `ValTree` must happen by matching on the type first and making
76+
decisions depending on that. The value itself gives no useful information without the type that
77+
belongs to it.
78+
3479
Other constants get represented as [`ConstValue::Scalar`]
3580
or [`ConstValue::Slice`] if possible. This means that the `const_eval_*`
3681
functions cannot be used to create miri-pointers to the evaluated constant.
@@ -42,4 +87,5 @@ If you need the value of a constant inside Miri, you need to directly work with
4287
[`ConstValue::Slice`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/value/enum.ConstValue.html#variant.Slice
4388
[`ConstValue::ByRef`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/value/enum.ConstValue.html#variant.ByRef
4489
[`EvalToConstValueResult`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/error/type.EvalToConstValueResult.html
90+
[`EvalToValTreeResult`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/error/type.EvalToValTreeResult.html
4591
[`const_to_op`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_const_eval/interpret/struct.InterpCx.html#method.const_to_op

0 commit comments

Comments
 (0)