Expand description
Builds MIR from expressions. As a caller into this module, you have many options, but the first thing you have to decide is whether you are evaluating this expression for its value, its location, or as a constant.
Typically, you want the value: e.g., if you are doing expr_a + expr_b
, you want the values of those expressions. In that case,
you want one of the following functions. Note that if the expr has
a type that is not Copy
, then using any of these functions will
“move” the value out of its current home (if any).
expr_into_dest
– writes the value into a specific location, which should be uninitializedas_operand
– evaluates the value and yields anOperand
, suitable for use as an argument to anRvalue
as_temp
– evaluates into a temporary; this is similar toas_operand
except it always returns a fresh place, even for constantsas_rvalue
– yields anRvalue
, suitable for use in an assignment; as of this writing, never needed outside of theexpr
module itself
Sometimes though want the expression’s location. An example
would be during a match statement, or the operand of the &
operator. In that case, you want as_place
. This will create a
temporary if necessary.
Finally, if it’s a constant you seek, then call
as_constant
. This creates a Constant<H>
, but naturally it can
only be used on constant expressions and hence is needed only in
very limited contexts.
§Implementation notes
For any given kind of expression, there is generally one way that
can be lowered most naturally. This is specified by the
Category::of
function in the category
module. For example, a
struct expression (or other expression that creates a new value)
is typically easiest to write in terms of as_rvalue
or into
,
whereas a reference to a field is easiest to write in terms of
as_place
. (The exception to this is scope and paren
expressions, which have no category.)
Therefore, the various functions above make use of one another in a descending fashion. For any given expression, you should pick the most suitable spot to implement it, and then just let the other fns cycle around. The handoff works like this:
into(place)
-> fallback is to create an rvalue withas_rvalue
and assign it toplace
as_rvalue
-> fallback is to create an Operand withas_operand
and useRvalue::use
as_operand
-> either invokesas_constant
oras_temp
as_constant
-> (no fallback)as_temp
-> creates a temporary and either callsas_place
orinto
as_place
-> for rvalues, falls back toas_temp
and returns that
As you can see, there is a cycle where into
can (in theory) fallback to as_temp
which can fallback to into
. So if one of the ExprKind
variants is not, in fact,
implemented in the category where it is supposed to be, there will be a problem.
Of those fallbacks, the most interesting one is into
, because
it discriminates based on the category of the expression. This is
basically the point where the “by value” operations are bridged
over to the “by reference” mode (as_place
).