about summary refs log tree commit diff
path: root/src/doc/rustc-dev-guide
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2023-09-16 10:06:32 +0200
committerTshepang Mbambo <tshepang@gmail.com>2023-09-18 03:57:13 +0200
commit2eb4e139992d0ba8332947535cc8c3452174f964 (patch)
tree3c6d8306dd04778f3409c0be19f7a098869bf50c /src/doc/rustc-dev-guide
parent1f3a6d62ef15f7247b3a7d6ff1ab337498a9246e (diff)
downloadrust-2eb4e139992d0ba8332947535cc8c3452174f964.tar.gz
rust-2eb4e139992d0ba8332947535cc8c3452174f964.zip
explain the MIR const vs TY const situation
Diffstat (limited to 'src/doc/rustc-dev-guide')
-rw-r--r--src/doc/rustc-dev-guide/src/const-eval.md49
-rw-r--r--src/doc/rustc-dev-guide/src/mir/index.md72
2 files changed, 75 insertions, 46 deletions
diff --git a/src/doc/rustc-dev-guide/src/const-eval.md b/src/doc/rustc-dev-guide/src/const-eval.md
index 6d301823be5..736405326e1 100644
--- a/src/doc/rustc-dev-guide/src/const-eval.md
+++ b/src/doc/rustc-dev-guide/src/const-eval.md
@@ -40,52 +40,11 @@ in which the constant is evaluated (e.g. the function within which the constant
 and a [`GlobalId`]. The `GlobalId` is made up of an `Instance` referring to a constant
 or static or of an `Instance` of a function and an index into the function's `Promoted` table.
 
-Constant evaluation returns an [`EvalToValTreeResult`] for type system constants or
-[`EvalToConstValueResult`] with either the error, or a representation of the constant.
-
-Constants for the type system are encoded in "valtree representation". The `ValTree` datastructure
-allows us to represent
-
-* arrays,
-* many structs,
-* tuples,
-* enums and,
-* most primitives.
-
-The basic rule for
-being permitted in the type system is that every value must be uniquely represented. In other
-words: a specific value must only be representable in one specific way. For example: there is only
-one way to represent an array of two integers as a `ValTree`:
-`ValTree::Branch(&[ValTree::Leaf(first_int), ValTree::Leaf(second_int)])`.
-Even though theoretically a `[u32; 2]` could be encoded in a `u64` and thus just be a
-`ValTree::Leaf(bits_of_two_u32)`, that is not a legal construction of `ValTree`
-(and is very complex to do, so it is unlikely anyone is tempted to do so).
-
-These rules also mean that some values are not representable. There can be no `union`s in type
-level constants, as it is not clear how they should be represented, because their active variant
-is unknown. Similarly there is no way to represent raw pointers, as addresses are unknown at
-compile-time and thus we cannot make any assumptions about them. References on the other hand
-*can* be represented, as equality for references is defined as equality on their value, so we
-ignore their address and just look at the backing value. We must make sure that the pointer values
-of the references are not observable at compile time. We thus encode `&42` exactly like `42`.
-Any conversion from
-valtree back to codegen constants must reintroduce an actual indirection. At codegen time the
-addresses may be deduplicated between multiple uses or not, entirely depending on arbitrary
-optimization choices.
-
-As a consequence, all decoding of `ValTree` must happen by matching on the type first and making
-decisions depending on that. The value itself gives no useful information without the type that
-belongs to it.
-
-Other constants get represented as [`ConstValue::Scalar`] or
-[`ConstValue::Slice`] if possible. These values are only useful outside the
-compile-time interpreter. If you need the value of a constant during
-interpretation, you need to directly work with [`const_to_op`].
+Constant evaluation returns an [`EvalToValTreeResult`] for type system constants
+or [`EvalToConstValueResult`] with either the error, or a representation of the
+evaluated constant: a [valtree](mir/index.md#valtrees) or a [MIR constant
+value](mir/index.md#mir-constant-values), respectively.
 
 [`GlobalId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/struct.GlobalId.html
-[`ConstValue::Scalar`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/value/enum.ConstValue.html#variant.Scalar
-[`ConstValue::Slice`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/value/enum.ConstValue.html#variant.Slice
-[`ConstValue::ByRef`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/value/enum.ConstValue.html#variant.ByRef
 [`EvalToConstValueResult`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/error/type.EvalToConstValueResult.html
 [`EvalToValTreeResult`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/interpret/error/type.EvalToValTreeResult.html
-[`const_to_op`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_const_eval/interpret/struct.InterpCx.html#method.const_to_op
diff --git a/src/doc/rustc-dev-guide/src/mir/index.md b/src/doc/rustc-dev-guide/src/mir/index.md
index 7027cd80321..36733c598c3 100644
--- a/src/doc/rustc-dev-guide/src/mir/index.md
+++ b/src/doc/rustc-dev-guide/src/mir/index.md
@@ -255,7 +255,75 @@ but [you can read about those below](#promoted)).
 
 ## Representing constants
 
-*to be written*
+When code has reached the MIR stage, constants can generally come in two forms:
+*MIR constants* ([`mir::Constant`]) and *type system constants* ([`ty::Const`]).
+MIR constants are used as operands: in `x + CONST`, `CONST` is a MIR constant;
+similarly, in `x + 2`, `2` is a MIR constant. Type system constants are used in
+the type system, in particular for array lengths but also for const generics.
+
+Generally, both kinds of constants can be "unevaluated" or "already evaluated".
+And unevaluated constant simply stores the `DefId` of what needs to be evaluated
+to compute this result. An evaluated constant (a "value") has already been
+computed; their representation differs between type system constants and MIR
+constants: MIR constants evaluate to a `mir::ConstValue`; type system constants
+evaluate to a `ty::ValTree`.
+
+Type system constants have some more variants to support const generics: they
+can refer to local const generic parameters, and they are subject to inference.
+Furthermore, the `mir::Constant::Ty` variant lets us use an arbitrary type
+system constant as a MIR constant; this happens whenever a const generic
+parameter is used as an operand.
+
+### MIR constant values
+
+In general, a MIR constant value (`mir::ConstValue`) was computed by evaluating
+some constant the user wrote. This [const evaluation](../const-eval.md) produces
+a very low-level representation of the result in terms of individual bytes. We
+call this an "indirect" constant (`mir::ConstValue::Indirect`) since the value
+is stored in-memory.
+
+However, storing everything in-memory would be awfully inefficient. Hence there
+are some other variants in `mir::ConstValue` that can represent certain simple
+and common values more efficiently. In particular, everything that can be
+directly written as a literal in Rust (integers, floats, chars, bools, but also
+`"string literals"` and `b"byte string literals"`) has an optimized variant that
+avoids the full overhead of the in-memory representation.
+
+### ValTrees
+
+An evaluated type system constant is a "valtree". The `ty::ValTree` datastructure
+allows us to represent
+
+* arrays,
+* many structs,
+* tuples,
+* enums and,
+* most primitives.
+
+The most important rule for
+this representation is that every value must be uniquely represented. In other
+words: a specific value must only be representable in one specific way. For example: there is only
+one way to represent an array of two integers as a `ValTree`:
+`ValTree::Branch(&[ValTree::Leaf(first_int), ValTree::Leaf(second_int)])`.
+Even though theoretically a `[u32; 2]` could be encoded in a `u64` and thus just be a
+`ValTree::Leaf(bits_of_two_u32)`, that is not a legal construction of `ValTree`
+(and is very complex to do, so it is unlikely anyone is tempted to do so).
+
+These rules also mean that some values are not representable. There can be no `union`s in type
+level constants, as it is not clear how they should be represented, because their active variant
+is unknown. Similarly there is no way to represent raw pointers, as addresses are unknown at
+compile-time and thus we cannot make any assumptions about them. References on the other hand
+*can* be represented, as equality for references is defined as equality on their value, so we
+ignore their address and just look at the backing value. We must make sure that the pointer values
+of the references are not observable at compile time. We thus encode `&42` exactly like `42`.
+Any conversion from
+valtree back a to MIR constant value must reintroduce an actual indirection. At codegen time the
+addresses may be deduplicated between multiple uses or not, entirely depending on arbitrary
+optimization choices.
+
+As a consequence, all decoding of `ValTree` must happen by matching on the type first and making
+decisions depending on that. The value itself gives no useful information without the type that
+belongs to it.
 
 <a name="promoted"></a>
 
@@ -283,3 +351,5 @@ See the const-eval WG's [docs on promotion](https://github.com/rust-lang/const-e
 [`ProjectionElem::Deref`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.ProjectionElem.html#variant.Deref
 [`Rvalue`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.Rvalue.html
 [`Operand`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.Operand.html
+[`mir::Constant`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/struct.Constant.html
+[`ty::Const`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Const.html