1 //! See docs in build/expr/mod.rs
3 use crate::build
::expr
::category
::Category
;
4 use crate::build
::ForGuard
::{OutsideGuard, RefWithinGuard}
;
5 use crate::build
::{BlockAnd, BlockAndExtension, Builder}
;
7 use rustc
::mir
::interpret
::EvalErrorKind
::BoundsCheck
;
9 use rustc
::ty
::{CanonicalUserTypeAnnotation, Variance}
;
11 use rustc_data_structures
::indexed_vec
::Idx
;
13 impl<'a
, 'gcx
, 'tcx
> Builder
<'a
, 'gcx
, 'tcx
> {
14 /// Compile `expr`, yielding a place that we can move from etc.
15 pub fn as_place
<M
>(&mut self, block
: BasicBlock
, expr
: M
) -> BlockAnd
<Place
<'tcx
>>
17 M
: Mirror
<'tcx
, Output
= Expr
<'tcx
>>,
19 let expr
= self.hir
.mirror(expr
);
20 self.expr_as_place(block
, expr
, Mutability
::Mut
)
23 /// Compile `expr`, yielding a place that we can move from etc.
24 /// Mutability note: The caller of this method promises only to read from the resulting
25 /// place. The place itself may or may not be mutable:
26 /// * If this expr is a place expr like a.b, then we will return that place.
27 /// * Otherwise, a temporary is created: in that event, it will be an immutable temporary.
28 pub fn as_read_only_place
<M
>(&mut self, block
: BasicBlock
, expr
: M
) -> BlockAnd
<Place
<'tcx
>>
30 M
: Mirror
<'tcx
, Output
= Expr
<'tcx
>>,
32 let expr
= self.hir
.mirror(expr
);
33 self.expr_as_place(block
, expr
, Mutability
::Not
)
38 mut block
: BasicBlock
,
40 mutability
: Mutability
,
41 ) -> BlockAnd
<Place
<'tcx
>> {
43 "expr_as_place(block={:?}, expr={:?}, mutability={:?})",
44 block
, expr
, mutability
48 let expr_span
= expr
.span
;
49 let source_info
= this
.source_info(expr_span
);
55 } => this
.in_scope((region_scope
, source_info
), lint_level
, block
, |this
| {
56 if mutability
== Mutability
::Not
{
57 this
.as_read_only_place(block
, value
)
59 this
.as_place(block
, value
)
62 ExprKind
::Field { lhs, name }
=> {
63 let place
= unpack
!(block
= this
.as_place(block
, lhs
));
64 let place
= place
.field(name
, expr
.ty
);
67 ExprKind
::Deref { arg }
=> {
68 let place
= unpack
!(block
= this
.as_place(block
, arg
));
69 let place
= place
.deref();
72 ExprKind
::Index { lhs, index }
=> {
73 let (usize_ty
, bool_ty
) = (this
.hir
.usize_ty(), this
.hir
.bool_ty());
75 let slice
= unpack
!(block
= this
.as_place(block
, lhs
));
76 // region_scope=None so place indexes live forever. They are scalars so they
77 // do not need storage annotations, and they are often copied between
79 // Making this a *fresh* temporary also means we do not have to worry about
80 // the index changing later: Nothing will ever change this temporary.
81 // The "retagging" transformation (for Stacked Borrows) relies on this.
82 let idx
= unpack
!(block
= this
.as_temp(block
, None
, index
, Mutability
::Mut
));
86 this
.temp(usize_ty
.clone(), expr_span
),
87 this
.temp(bool_ty
, expr_span
),
91 source_info
, // len = len(slice)
93 Rvalue
::Len(slice
.clone()),
97 source_info
, // lt = idx < len
101 Operand
::Copy(Place
::Local(idx
)),
102 Operand
::Copy(len
.clone()),
106 let msg
= BoundsCheck
{
107 len
: Operand
::Move(len
),
108 index
: Operand
::Copy(Place
::Local(idx
)),
110 let success
= this
.assert(block
, Operand
::Move(lt
), true, msg
, expr_span
);
111 success
.and(slice
.index(idx
))
113 ExprKind
::SelfRef
=> block
.and(Place
::Local(Local
::new(1))),
114 ExprKind
::VarRef { id }
=> {
115 let place
= if this
.is_bound_var_in_guard(id
) && this
118 .all_pat_vars_are_implicit_refs_within_guards()
120 let index
= this
.var_local_id(id
, RefWithinGuard
);
121 Place
::Local(index
).deref()
123 let index
= this
.var_local_id(id
, OutsideGuard
);
128 ExprKind
::StaticRef { id }
=> block
.and(Place
::Static(Box
::new(Static
{
133 ExprKind
::PlaceTypeAscription { source, user_ty }
=> {
134 let place
= unpack
!(block
= this
.as_place(block
, source
));
135 if let Some(user_ty
) = user_ty
{
136 let annotation_index
= this
.canonical_user_type_annotations
.push(
137 CanonicalUserTypeAnnotation
{
138 span
: source_info
.span
,
140 inferred_ty
: expr
.ty
,
147 kind
: StatementKind
::AscribeUserType(
150 box UserTypeProjection { base: annotation_index, projs: vec![], }
,
157 ExprKind
::ValueTypeAscription { source, user_ty }
=> {
158 let source
= this
.hir
.mirror(source
);
160 block
= this
.as_temp(block
, source
.temp_lifetime
, source
, mutability
)
162 if let Some(user_ty
) = user_ty
{
163 let annotation_index
= this
.canonical_user_type_annotations
.push(
164 CanonicalUserTypeAnnotation
{
165 span
: source_info
.span
,
167 inferred_ty
: expr
.ty
,
174 kind
: StatementKind
::AscribeUserType(
175 Place
::Local(temp
.clone()),
177 box UserTypeProjection { base: annotation_index, projs: vec![], }
,
182 block
.and(Place
::Local(temp
))
185 ExprKind
::Array { .. }
186 | ExprKind
::Tuple { .. }
187 | ExprKind
::Adt { .. }
188 | ExprKind
::Closure { .. }
189 | ExprKind
::Unary { .. }
190 | ExprKind
::Binary { .. }
191 | ExprKind
::LogicalOp { .. }
192 | ExprKind
::Box { .. }
193 | ExprKind
::Cast { .. }
194 | ExprKind
::Use { .. }
195 | ExprKind
::NeverToAny { .. }
196 | ExprKind
::ReifyFnPointer { .. }
197 | ExprKind
::ClosureFnPointer { .. }
198 | ExprKind
::UnsafeFnPointer { .. }
199 | ExprKind
::Unsize { .. }
200 | ExprKind
::Repeat { .. }
201 | ExprKind
::Borrow { .. }
202 | ExprKind
::If { .. }
203 | ExprKind
::Match { .. }
204 | ExprKind
::Loop { .. }
205 | ExprKind
::Block { .. }
206 | ExprKind
::Assign { .. }
207 | ExprKind
::AssignOp { .. }
208 | ExprKind
::Break { .. }
209 | ExprKind
::Continue { .. }
210 | ExprKind
::Return { .. }
211 | ExprKind
::Literal { .. }
212 | ExprKind
::InlineAsm { .. }
213 | ExprKind
::Yield { .. }
214 | ExprKind
::Call { .. }
=> {
215 // these are not places, so we need to make a temporary.
216 debug_assert
!(match Category
::of(&expr
.kind
) {
217 Some(Category
::Place
) => false,
221 unpack
!(block
= this
.as_temp(block
, expr
.temp_lifetime
, expr
, mutability
));
222 block
.and(Place
::Local(temp
))