1 use crate::thir
::cx
::Cx
;
2 use crate::thir
::util
::UserAnnotatedTyHelpers
;
4 use rustc_data_structures
::stack
::ensure_sufficient_stack
;
6 use rustc_hir
::def
::{CtorKind, CtorOf, DefKind, Res}
;
7 use rustc_index
::vec
::Idx
;
8 use rustc_middle
::hir
::place
::Place
as HirPlace
;
9 use rustc_middle
::hir
::place
::PlaceBase
as HirPlaceBase
;
10 use rustc_middle
::hir
::place
::ProjectionKind
as HirProjectionKind
;
11 use rustc_middle
::mir
::interpret
::Scalar
;
12 use rustc_middle
::mir
::BorrowKind
;
13 use rustc_middle
::ty
::adjustment
::{
14 Adjust
, Adjustment
, AutoBorrow
, AutoBorrowMutability
, PointerCast
,
16 use rustc_middle
::ty
::subst
::{InternalSubsts, SubstsRef}
;
17 use rustc_middle
::ty
::{self, AdtKind, Ty}
;
22 impl<'thir
, 'tcx
> Cx
<'thir
, 'tcx
> {
23 /// Mirrors and allocates a single [`hir::Expr`]. If you need to mirror a whole slice
24 /// of expressions, prefer using [`mirror_exprs`].
26 /// [`mirror_exprs`]: Self::mirror_exprs
27 crate fn mirror_expr(&mut self, expr
: &'tcx hir
::Expr
<'tcx
>) -> &'thir Expr
<'thir
, 'tcx
> {
28 // `mirror_expr` is recursing very deep. Make sure the stack doesn't overflow.
29 ensure_sufficient_stack(|| self.arena
.alloc(self.mirror_expr_inner(expr
)))
32 /// Mirrors and allocates a slice of [`hir::Expr`]s. They will be allocated as a
33 /// contiguous sequence in memory.
34 crate fn mirror_exprs(&mut self, exprs
: &'tcx
[hir
::Expr
<'tcx
>]) -> &'thir
[Expr
<'thir
, 'tcx
>] {
35 self.arena
.alloc_from_iter(exprs
.iter().map(|expr
| self.mirror_expr_inner(expr
)))
38 /// Mirrors a [`hir::Expr`] without allocating it into the arena.
39 /// This is a separate, private function so that [`mirror_expr`] and [`mirror_exprs`] can
40 /// decide how to allocate this expression (alone or within a slice).
42 /// [`mirror_expr`]: Self::mirror_expr
43 /// [`mirror_exprs`]: Self::mirror_exprs
44 pub(super) fn mirror_expr_inner(
46 hir_expr
: &'tcx hir
::Expr
<'tcx
>,
47 ) -> Expr
<'thir
, 'tcx
> {
48 let temp_lifetime
= self.region_scope_tree
.temporary_scope(hir_expr
.hir_id
.local_id
);
50 region
::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node }
;
52 debug
!("Expr::make_mirror(): id={}, span={:?}", hir_expr
.hir_id
, hir_expr
.span
);
54 let mut expr
= self.make_mirror_unadjusted(hir_expr
);
56 // Now apply adjustments, if any.
57 for adjustment
in self.typeck_results
.expr_adjustments(hir_expr
) {
58 debug
!("make_mirror: expr={:?} applying adjustment={:?}", expr
, adjustment
);
59 expr
= self.apply_adjustment(hir_expr
, expr
, adjustment
);
62 // Next, wrap this up in the expr's scope.
67 kind
: ExprKind
::Scope
{
68 region_scope
: expr_scope
,
69 value
: self.arena
.alloc(expr
),
70 lint_level
: LintLevel
::Explicit(hir_expr
.hir_id
),
74 // Finally, create a destruction scope, if any.
75 if let Some(region_scope
) =
76 self.region_scope_tree
.opt_destruction_scope(hir_expr
.hir_id
.local_id
)
82 kind
: ExprKind
::Scope
{
84 value
: self.arena
.alloc(expr
),
85 lint_level
: LintLevel
::Inherited
,
96 hir_expr
: &'tcx hir
::Expr
<'tcx
>,
97 mut expr
: Expr
<'thir
, 'tcx
>,
98 adjustment
: &Adjustment
<'tcx
>,
99 ) -> Expr
<'thir
, 'tcx
> {
100 let Expr { temp_lifetime, mut span, .. }
= expr
;
102 // Adjust the span from the block, to the last expression of the
103 // block. This is a better span when returning a mutable reference
104 // with too short a lifetime. The error message will use the span
105 // from the assignment to the return place, which should only point
106 // at the returned value, not the entire function body.
108 // fn return_short_lived<'a>(x: &'a mut i32) -> &'static mut i32 {
110 // // ^ error message points at this expression.
112 let mut adjust_span
= |expr
: &mut Expr
<'thir
, 'tcx
>| {
113 if let ExprKind
::Block { body }
= &expr
.kind
{
114 if let Some(ref last_expr
) = body
.expr
{
115 span
= last_expr
.span
;
121 let kind
= match adjustment
.kind
{
122 Adjust
::Pointer(PointerCast
::Unsize
) => {
123 adjust_span(&mut expr
);
124 ExprKind
::Pointer { cast: PointerCast::Unsize, source: self.arena.alloc(expr) }
126 Adjust
::Pointer(cast
) => ExprKind
::Pointer { cast, source: self.arena.alloc(expr) }
,
127 Adjust
::NeverToAny
=> ExprKind
::NeverToAny { source: self.arena.alloc(expr) }
,
128 Adjust
::Deref(None
) => {
129 adjust_span(&mut expr
);
130 ExprKind
::Deref { arg: self.arena.alloc(expr) }
132 Adjust
::Deref(Some(deref
)) => {
133 // We don't need to do call adjust_span here since
134 // deref coercions always start with a built-in deref.
135 let call
= deref
.method_call(self.tcx(), expr
.ty
);
141 .mk_ref(deref
.region
, ty
::TypeAndMut { ty: expr.ty, mutbl: deref.mutbl }
),
143 kind
: ExprKind
::Borrow
{
144 borrow_kind
: deref
.mutbl
.to_borrow_kind(),
145 arg
: self.arena
.alloc(expr
),
149 self.overloaded_place(
153 self.arena
.alloc_from_iter(iter
::once(expr
)),
157 Adjust
::Borrow(AutoBorrow
::Ref(_
, m
)) => {
158 ExprKind
::Borrow { borrow_kind: m.to_borrow_kind(), arg: self.arena.alloc(expr) }
160 Adjust
::Borrow(AutoBorrow
::RawPtr(mutability
)) => {
161 ExprKind
::AddressOf { mutability, arg: self.arena.alloc(expr) }
165 Expr { temp_lifetime, ty: adjustment.target, span, kind }
168 fn make_mirror_unadjusted(&mut self, expr
: &'tcx hir
::Expr
<'tcx
>) -> Expr
<'thir
, 'tcx
> {
169 let expr_ty
= self.typeck_results().expr_ty(expr
);
170 let temp_lifetime
= self.region_scope_tree
.temporary_scope(expr
.hir_id
.local_id
);
172 let kind
= match expr
.kind
{
173 // Here comes the interesting stuff:
174 hir
::ExprKind
::MethodCall(_
, method_span
, ref args
, fn_span
) => {
175 // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
176 let expr
= self.method_callee(expr
, method_span
, None
);
177 let args
= self.mirror_exprs(args
);
180 fun
: self.arena
.alloc(expr
),
187 hir
::ExprKind
::Call(ref fun
, ref args
) => {
188 if self.typeck_results().is_method_call(expr
) {
189 // The callee is something implementing Fn, FnMut, or FnOnce.
190 // Find the actual method implementation being called and
191 // build the appropriate UFCS call expression with the
192 // callee-object as expr parameter.
194 // rewrite f(u, v) into FnOnce::call_once(f, (u, v))
196 let method
= self.method_callee(expr
, fun
.span
, None
);
198 let arg_tys
= args
.iter().map(|e
| self.typeck_results().expr_ty_adjusted(e
));
199 let tupled_args
= Expr
{
200 ty
: self.tcx
.mk_tup(arg_tys
),
203 kind
: ExprKind
::Tuple { fields: self.mirror_exprs(args) }
,
208 fun
: self.arena
.alloc(method
),
211 .alloc_from_iter(vec
![self.mirror_expr_inner(fun
), tupled_args
]),
217 if let hir
::ExprKind
::Path(hir
::QPath
::Resolved(_
, ref path
)) = fun
.kind
{
218 // Tuple-like ADTs are represented as ExprKind::Call. We convert them here.
219 expr_ty
.ty_adt_def().and_then(|adt_def
| match path
.res
{
220 Res
::Def(DefKind
::Ctor(_
, CtorKind
::Fn
), ctor_id
) => {
221 Some((adt_def
, adt_def
.variant_index_with_ctor_id(ctor_id
)))
223 Res
::SelfCtor(..) => Some((adt_def
, VariantIdx
::new(0))),
229 if let Some((adt_def
, index
)) = adt_data
{
230 let substs
= self.typeck_results().node_substs(fun
.hir_id
);
231 let user_provided_types
= self.typeck_results().user_provided_types();
233 user_provided_types
.get(fun
.hir_id
).copied().map(|mut u_ty
| {
234 if let UserType
::TypeOf(ref mut did
, _
) = &mut u_ty
.value
{
239 debug
!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty
);
242 self.arena
.alloc_from_iter(args
.iter().enumerate().map(|(idx
, e
)| {
243 FieldExpr { name: Field::new(idx), expr: self.mirror_expr(e) }
248 variant_index
: index
,
255 ty
: self.typeck_results().node_type(fun
.hir_id
),
256 fun
: self.mirror_expr(fun
),
257 args
: self.mirror_exprs(args
),
265 hir
::ExprKind
::AddrOf(hir
::BorrowKind
::Ref
, mutbl
, ref arg
) => {
266 ExprKind
::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: self.mirror_expr(arg) }
269 hir
::ExprKind
::AddrOf(hir
::BorrowKind
::Raw
, mutability
, ref arg
) => {
270 ExprKind
::AddressOf { mutability, arg: self.mirror_expr(arg) }
273 hir
::ExprKind
::Block(ref blk
, _
) => ExprKind
::Block { body: self.mirror_block(blk) }
,
275 hir
::ExprKind
::Assign(ref lhs
, ref rhs
, _
) => {
276 ExprKind
::Assign { lhs: self.mirror_expr(lhs), rhs: self.mirror_expr(rhs) }
279 hir
::ExprKind
::AssignOp(op
, ref lhs
, ref rhs
) => {
280 if self.typeck_results().is_method_call(expr
) {
281 let lhs
= self.mirror_expr_inner(lhs
);
282 let rhs
= self.mirror_expr_inner(rhs
);
283 self.overloaded_operator(expr
, self.arena
.alloc_from_iter(vec
![lhs
, rhs
]))
287 lhs
: self.mirror_expr(lhs
),
288 rhs
: self.mirror_expr(rhs
),
293 hir
::ExprKind
::Lit(ref lit
) => ExprKind
::Literal
{
294 literal
: self.const_eval_literal(&lit
.node
, expr_ty
, lit
.span
, false),
299 hir
::ExprKind
::Binary(op
, ref lhs
, ref rhs
) => {
300 if self.typeck_results().is_method_call(expr
) {
301 let lhs
= self.mirror_expr_inner(lhs
);
302 let rhs
= self.mirror_expr_inner(rhs
);
303 self.overloaded_operator(expr
, self.arena
.alloc_from_iter(vec
![lhs
, rhs
]))
307 hir
::BinOpKind
::And
=> ExprKind
::LogicalOp
{
309 lhs
: self.mirror_expr(lhs
),
310 rhs
: self.mirror_expr(rhs
),
312 hir
::BinOpKind
::Or
=> ExprKind
::LogicalOp
{
314 lhs
: self.mirror_expr(lhs
),
315 rhs
: self.mirror_expr(rhs
),
319 let op
= bin_op(op
.node
);
322 lhs
: self.mirror_expr(lhs
),
323 rhs
: self.mirror_expr(rhs
),
330 hir
::ExprKind
::Index(ref lhs
, ref index
) => {
331 if self.typeck_results().is_method_call(expr
) {
332 let lhs
= self.mirror_expr_inner(lhs
);
333 let index
= self.mirror_expr_inner(index
);
334 self.overloaded_place(
338 self.arena
.alloc_from_iter(vec
![lhs
, index
]),
342 ExprKind
::Index { lhs: self.mirror_expr(lhs), index: self.mirror_expr(index) }
346 hir
::ExprKind
::Unary(hir
::UnOp
::Deref
, ref arg
) => {
347 if self.typeck_results().is_method_call(expr
) {
348 let arg
= self.mirror_expr_inner(arg
);
349 self.overloaded_place(
353 self.arena
.alloc_from_iter(iter
::once(arg
)),
357 ExprKind
::Deref { arg: self.mirror_expr(arg) }
361 hir
::ExprKind
::Unary(hir
::UnOp
::Not
, ref arg
) => {
362 if self.typeck_results().is_method_call(expr
) {
363 let arg
= self.mirror_expr_inner(arg
);
364 self.overloaded_operator(expr
, self.arena
.alloc_from_iter(iter
::once(arg
)))
366 ExprKind
::Unary { op: UnOp::Not, arg: self.mirror_expr(arg) }
370 hir
::ExprKind
::Unary(hir
::UnOp
::Neg
, ref arg
) => {
371 if self.typeck_results().is_method_call(expr
) {
372 let arg
= self.mirror_expr_inner(arg
);
373 self.overloaded_operator(expr
, self.arena
.alloc_from_iter(iter
::once(arg
)))
374 } else if let hir
::ExprKind
::Lit(ref lit
) = arg
.kind
{
376 literal
: self.const_eval_literal(&lit
.node
, expr_ty
, lit
.span
, true),
381 ExprKind
::Unary { op: UnOp::Neg, arg: self.mirror_expr(arg) }
385 hir
::ExprKind
::Struct(ref qpath
, ref fields
, ref base
) => match expr_ty
.kind() {
386 ty
::Adt(adt
, substs
) => match adt
.adt_kind() {
387 AdtKind
::Struct
| AdtKind
::Union
=> {
388 let user_provided_types
= self.typeck_results().user_provided_types();
389 let user_ty
= user_provided_types
.get(expr
.hir_id
).copied();
390 debug
!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty
);
393 variant_index
: VariantIdx
::new(0),
396 fields
: self.field_refs(fields
),
397 base
: base
.as_ref().map(|base
| FruInfo
{
398 base
: self.mirror_expr(base
),
399 field_types
: self.arena
.alloc_from_iter(
400 self.typeck_results().fru_field_types()[expr
.hir_id
]
408 let res
= self.typeck_results().qpath_res(qpath
, expr
.hir_id
);
410 Res
::Def(DefKind
::Variant
, variant_id
) => {
411 assert
!(base
.is_none());
413 let index
= adt
.variant_index_with_id(variant_id
);
414 let user_provided_types
=
415 self.typeck_results().user_provided_types();
416 let user_ty
= user_provided_types
.get(expr
.hir_id
).copied();
417 debug
!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty
);
420 variant_index
: index
,
423 fields
: self.field_refs(fields
),
428 span_bug
!(expr
.span
, "unexpected res: {:?}", res
);
434 span_bug
!(expr
.span
, "unexpected type for struct literal: {:?}", expr_ty
);
438 hir
::ExprKind
::Closure(..) => {
439 let closure_ty
= self.typeck_results().expr_ty(expr
);
440 let (def_id
, substs
, movability
) = match *closure_ty
.kind() {
441 ty
::Closure(def_id
, substs
) => (def_id
, UpvarSubsts
::Closure(substs
), None
),
442 ty
::Generator(def_id
, substs
, movability
) => {
443 (def_id
, UpvarSubsts
::Generator(substs
), Some(movability
))
446 span_bug
!(expr
.span
, "closure expr w/o closure type: {:?}", closure_ty
);
450 let upvars
= self.arena
.alloc_from_iter(
452 .closure_min_captures_flattened(def_id
)
453 .zip(substs
.upvar_tys())
454 .map(|(captured_place
, ty
)| self.capture_upvar(expr
, captured_place
, ty
)),
457 // Convert the closure fake reads, if any, from hir `Place` to ExprRef
458 let fake_reads
= match self.typeck_results
.closure_fake_reads
.get(&def_id
) {
459 Some(fake_reads
) => fake_reads
461 .map(|(place
, cause
, hir_id
)| {
462 let expr
= self.convert_captured_hir_place(expr
, place
.clone());
463 let expr_ref
: &'thir Expr
<'thir
, 'tcx
> = self.arena
.alloc(expr
);
464 (expr_ref
, *cause
, *hir_id
)
470 ExprKind
::Closure { closure_id: def_id, substs, upvars, movability, fake_reads }
473 hir
::ExprKind
::Path(ref qpath
) => {
474 let res
= self.typeck_results().qpath_res(qpath
, expr
.hir_id
);
475 self.convert_path_expr(expr
, res
)
478 hir
::ExprKind
::InlineAsm(ref asm
) => ExprKind
::InlineAsm
{
479 template
: asm
.template
,
480 operands
: self.arena
.alloc_from_iter(asm
.operands
.iter().map(|(op
, _op_sp
)| {
482 hir
::InlineAsmOperand
::In { reg, ref expr }
=> {
483 InlineAsmOperand
::In { reg, expr: self.mirror_expr(expr) }
485 hir
::InlineAsmOperand
::Out { reg, late, ref expr }
=> {
486 InlineAsmOperand
::Out
{
489 expr
: expr
.as_ref().map(|expr
| self.mirror_expr(expr
)),
492 hir
::InlineAsmOperand
::InOut { reg, late, ref expr }
=> {
493 InlineAsmOperand
::InOut { reg, late, expr: self.mirror_expr(expr) }
495 hir
::InlineAsmOperand
::SplitInOut
{
500 } => InlineAsmOperand
::SplitInOut
{
503 in_expr
: self.mirror_expr(in_expr
),
504 out_expr
: out_expr
.as_ref().map(|expr
| self.mirror_expr(expr
)),
506 hir
::InlineAsmOperand
::Const { ref anon_const }
=> {
507 let anon_const_def_id
= self.tcx
.hir().local_def_id(anon_const
.hir_id
);
508 let value
= ty
::Const
::from_anon_const(self.tcx
, anon_const_def_id
);
509 let span
= self.tcx
.hir().span(anon_const
.hir_id
);
511 InlineAsmOperand
::Const { value, span }
513 hir
::InlineAsmOperand
::Sym { ref expr }
=> {
514 let qpath
= match expr
.kind
{
515 hir
::ExprKind
::Path(ref qpath
) => qpath
,
518 "asm `sym` operand should be a path, found {:?}",
523 self.region_scope_tree
.temporary_scope(expr
.hir_id
.local_id
);
524 let res
= self.typeck_results().qpath_res(qpath
, expr
.hir_id
);
527 Res
::Def(DefKind
::Fn
, _
) | Res
::Def(DefKind
::AssocFn
, _
) => {
528 ty
= self.typeck_results().node_type(expr
.hir_id
);
529 let user_ty
= self.user_substs_applied_to_res(expr
.hir_id
, res
);
530 InlineAsmOperand
::SymFn
{
531 expr
: self.arena
.alloc(Expr
{
535 kind
: ExprKind
::Literal
{
536 literal
: ty
::Const
::zero_sized(self.tcx
, ty
),
544 Res
::Def(DefKind
::Static
, def_id
) => {
545 InlineAsmOperand
::SymStatic { def_id }
549 self.tcx
.sess
.span_err(
551 "asm `sym` operand must point to a fn or static",
554 // Not a real fn, but we're not reaching codegen anyways...
555 ty
= self.tcx
.ty_error();
556 InlineAsmOperand
::SymFn
{
557 expr
: self.arena
.alloc(Expr
{
561 kind
: ExprKind
::Literal
{
562 literal
: ty
::Const
::zero_sized(self.tcx
, ty
),
573 options
: asm
.options
,
574 line_spans
: asm
.line_spans
,
577 hir
::ExprKind
::LlvmInlineAsm(ref asm
) => ExprKind
::LlvmInlineAsm
{
579 outputs
: self.mirror_exprs(asm
.outputs_exprs
),
580 inputs
: self.mirror_exprs(asm
.inputs_exprs
),
583 hir
::ExprKind
::ConstBlock(ref anon_const
) => {
584 let anon_const_def_id
= self.tcx
.hir().local_def_id(anon_const
.hir_id
);
585 let value
= ty
::Const
::from_anon_const(self.tcx
, anon_const_def_id
);
587 ExprKind
::ConstBlock { value }
589 // Now comes the rote stuff:
590 hir
::ExprKind
::Repeat(ref v
, ref count
) => {
591 let count_def_id
= self.tcx
.hir().local_def_id(count
.hir_id
);
592 let count
= ty
::Const
::from_anon_const(self.tcx
, count_def_id
);
594 ExprKind
::Repeat { value: self.mirror_expr(v), count }
596 hir
::ExprKind
::Ret(ref v
) => {
597 ExprKind
::Return { value: v.as_ref().map(|v| self.mirror_expr(v)) }
599 hir
::ExprKind
::Break(dest
, ref value
) => match dest
.target_id
{
600 Ok(target_id
) => ExprKind
::Break
{
601 label
: region
::Scope { id: target_id.local_id, data: region::ScopeData::Node }
,
602 value
: value
.as_ref().map(|value
| self.mirror_expr(value
)),
604 Err(err
) => bug
!("invalid loop id for break: {}", err
),
606 hir
::ExprKind
::Continue(dest
) => match dest
.target_id
{
607 Ok(loop_id
) => ExprKind
::Continue
{
608 label
: region
::Scope { id: loop_id.local_id, data: region::ScopeData::Node }
,
610 Err(err
) => bug
!("invalid loop id for continue: {}", err
),
612 hir
::ExprKind
::If(cond
, then
, else_opt
) => ExprKind
::If
{
613 cond
: self.mirror_expr(cond
),
614 then
: self.mirror_expr(then
),
615 else_opt
: else_opt
.map(|el
| self.mirror_expr(el
)),
617 hir
::ExprKind
::Match(ref discr
, ref arms
, _
) => ExprKind
::Match
{
618 scrutinee
: self.mirror_expr(discr
),
619 arms
: self.arena
.alloc_from_iter(arms
.iter().map(|a
| self.convert_arm(a
))),
621 hir
::ExprKind
::Loop(ref body
, ..) => {
622 let block_ty
= self.typeck_results().node_type(body
.hir_id
);
623 let temp_lifetime
= self.region_scope_tree
.temporary_scope(body
.hir_id
.local_id
);
624 let block
= self.mirror_block(body
);
625 let body
= self.arena
.alloc(Expr
{
629 kind
: ExprKind
::Block { body: block }
,
631 ExprKind
::Loop { body }
633 hir
::ExprKind
::Field(ref source
, ..) => ExprKind
::Field
{
634 lhs
: self.mirror_expr(source
),
635 name
: Field
::new(self.tcx
.field_index(expr
.hir_id
, self.typeck_results
)),
637 hir
::ExprKind
::Cast(ref source
, ref cast_ty
) => {
638 // Check for a user-given type annotation on this `cast`
639 let user_provided_types
= self.typeck_results
.user_provided_types();
640 let user_ty
= user_provided_types
.get(cast_ty
.hir_id
);
643 "cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}",
644 expr
, cast_ty
.hir_id
, user_ty
,
647 // Check to see if this cast is a "coercion cast", where the cast is actually done
648 // using a coercion (or is a no-op).
649 let cast
= if self.typeck_results().is_coercion_cast(source
.hir_id
) {
650 // Convert the lexpr to a vexpr.
651 ExprKind
::Use { source: self.mirror_expr(source) }
652 } else if self.typeck_results().expr_ty(source
).is_region_ptr() {
653 // Special cased so that we can type check that the element
654 // type of the source matches the pointed to type of the
657 source
: self.mirror_expr(source
),
658 cast
: PointerCast
::ArrayToPointer
,
661 // check whether this is casting an enum variant discriminant
662 // to prevent cycles, we refer to the discriminant initializer
663 // which is always an integer and thus doesn't need to know the
664 // enum's layout (or its tag type) to compute it during const eval
668 // B = A as isize + 4,
670 // The correct solution would be to add symbolic computations to miri,
671 // so we wouldn't have to compute and store the actual value
672 let var
= if let hir
::ExprKind
::Path(ref qpath
) = source
.kind
{
673 let res
= self.typeck_results().qpath_res(qpath
, source
.hir_id
);
674 self.typeck_results().node_type(source
.hir_id
).ty_adt_def().and_then(
675 |adt_def
| match res
{
677 DefKind
::Ctor(CtorOf
::Variant
, CtorKind
::Const
),
680 let idx
= adt_def
.variant_index_with_ctor_id(variant_ctor_id
);
681 let (d
, o
) = adt_def
.discriminant_def_for_variant(idx
);
682 use rustc_middle
::ty
::util
::IntTypeExt
;
683 let ty
= adt_def
.repr
.discr_type();
684 let ty
= ty
.to_ty(self.tcx());
694 let source
= if let Some((did
, offset
, var_ty
)) = var
{
695 let mk_const
= |literal
| {
696 self.arena
.alloc(Expr
{
700 kind
: ExprKind
::Literal { literal, user_ty: None, const_id: None }
,
703 let offset
= mk_const(ty
::Const
::from_bits(
706 self.param_env
.and(var_ty
),
710 // in case we are offsetting from a computed discriminant
711 // and not the beginning of discriminants (which is always `0`)
712 let substs
= InternalSubsts
::identity_for_item(self.tcx(), did
);
713 let lhs
= mk_const(self.tcx().mk_const(ty
::Const
{
714 val
: ty
::ConstKind
::Unevaluated(ty
::Unevaluated
{
715 def
: ty
::WithOptConstParam
::unknown(did
),
722 ExprKind
::Binary { op: BinOp::Add, lhs: lhs, rhs: offset }
;
723 self.arena
.alloc(Expr
{
733 self.mirror_expr(source
)
736 ExprKind
::Cast { source: source }
739 if let Some(user_ty
) = user_ty
{
740 // NOTE: Creating a new Expr and wrapping a Cast inside of it may be
741 // inefficient, revisit this when performance becomes an issue.
742 let cast_expr
= self.arena
.alloc(Expr
{
748 debug
!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty
);
750 ExprKind
::ValueTypeAscription { source: cast_expr, user_ty: Some(*user_ty) }
755 hir
::ExprKind
::Type(ref source
, ref ty
) => {
756 let user_provided_types
= self.typeck_results
.user_provided_types();
757 let user_ty
= user_provided_types
.get(ty
.hir_id
).copied();
758 debug
!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty
);
759 let mirrored
= self.mirror_expr(source
);
760 if source
.is_syntactic_place_expr() {
761 ExprKind
::PlaceTypeAscription { source: mirrored, user_ty }
763 ExprKind
::ValueTypeAscription { source: mirrored, user_ty }
766 hir
::ExprKind
::DropTemps(ref source
) => {
767 ExprKind
::Use { source: self.mirror_expr(source) }
769 hir
::ExprKind
::Box(ref value
) => ExprKind
::Box { value: self.mirror_expr(value) }
,
770 hir
::ExprKind
::Array(ref fields
) => {
771 ExprKind
::Array { fields: self.mirror_exprs(fields) }
773 hir
::ExprKind
::Tup(ref fields
) => ExprKind
::Tuple { fields: self.mirror_exprs(fields) }
,
775 hir
::ExprKind
::Yield(ref v
, _
) => ExprKind
::Yield { value: self.mirror_expr(v) }
,
776 hir
::ExprKind
::Err
=> unreachable
!(),
779 Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind }
782 fn user_substs_applied_to_res(
786 ) -> Option
<ty
::CanonicalUserType
<'tcx
>> {
787 debug
!("user_substs_applied_to_res: res={:?}", res
);
788 let user_provided_type
= match res
{
789 // A reference to something callable -- e.g., a fn, method, or
790 // a tuple-struct or tuple-variant. This has the type of a
791 // `Fn` but with the user-given substitutions.
792 Res
::Def(DefKind
::Fn
, _
)
793 | Res
::Def(DefKind
::AssocFn
, _
)
794 | Res
::Def(DefKind
::Ctor(_
, CtorKind
::Fn
), _
)
795 | Res
::Def(DefKind
::Const
, _
)
796 | Res
::Def(DefKind
::AssocConst
, _
) => {
797 self.typeck_results().user_provided_types().get(hir_id
).copied()
800 // A unit struct/variant which is used as a value (e.g.,
801 // `None`). This has the type of the enum/struct that defines
802 // this variant -- but with the substitutions given by the
804 Res
::Def(DefKind
::Ctor(_
, CtorKind
::Const
), _
) => {
805 self.user_substs_applied_to_ty_of_hir_id(hir_id
)
808 // `Self` is used in expression as a tuple struct constructor or an unit struct constructor
809 Res
::SelfCtor(_
) => self.user_substs_applied_to_ty_of_hir_id(hir_id
),
811 _
=> bug
!("user_substs_applied_to_res: unexpected res {:?} at {:?}", res
, hir_id
),
813 debug
!("user_substs_applied_to_res: user_provided_type={:?}", user_provided_type
);
819 expr
: &hir
::Expr
<'_
>,
821 overloaded_callee
: Option
<(DefId
, SubstsRef
<'tcx
>)>,
822 ) -> Expr
<'thir
, 'tcx
> {
823 let temp_lifetime
= self.region_scope_tree
.temporary_scope(expr
.hir_id
.local_id
);
824 let (def_id
, substs
, user_ty
) = match overloaded_callee
{
825 Some((def_id
, substs
)) => (def_id
, substs
, None
),
828 self.typeck_results().type_dependent_def(expr
.hir_id
).unwrap_or_else(|| {
829 span_bug
!(expr
.span
, "no type-dependent def for method callee")
831 let user_ty
= self.user_substs_applied_to_res(expr
.hir_id
, Res
::Def(kind
, def_id
));
832 debug
!("method_callee: user_ty={:?}", user_ty
);
833 (def_id
, self.typeck_results().node_substs(expr
.hir_id
), user_ty
)
836 let ty
= self.tcx().mk_fn_def(def_id
, substs
);
841 kind
: ExprKind
::Literal
{
842 literal
: ty
::Const
::zero_sized(self.tcx(), ty
),
849 fn convert_arm(&mut self, arm
: &'tcx hir
::Arm
<'tcx
>) -> Arm
<'thir
, 'tcx
> {
851 pattern
: self.pattern_from_hir(&arm
.pat
),
852 guard
: arm
.guard
.as_ref().map(|g
| match g
{
853 hir
::Guard
::If(ref e
) => Guard
::If(self.mirror_expr(e
)),
854 hir
::Guard
::IfLet(ref pat
, ref e
) => {
855 Guard
::IfLet(self.pattern_from_hir(pat
), self.mirror_expr(e
))
858 body
: self.mirror_expr(arm
.body
),
859 lint_level
: LintLevel
::Explicit(arm
.hir_id
),
860 scope
: region
::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node }
,
865 fn convert_path_expr(
867 expr
: &'tcx hir
::Expr
<'tcx
>,
869 ) -> ExprKind
<'thir
, 'tcx
> {
870 let substs
= self.typeck_results().node_substs(expr
.hir_id
);
872 // A regular function, constructor function or a constant.
873 Res
::Def(DefKind
::Fn
, _
)
874 | Res
::Def(DefKind
::AssocFn
, _
)
875 | Res
::Def(DefKind
::Ctor(_
, CtorKind
::Fn
), _
)
876 | Res
::SelfCtor(..) => {
877 let user_ty
= self.user_substs_applied_to_res(expr
.hir_id
, res
);
878 debug
!("convert_path_expr: user_ty={:?}", user_ty
);
880 literal
: ty
::Const
::zero_sized(
882 self.typeck_results().node_type(expr
.hir_id
),
889 Res
::Def(DefKind
::ConstParam
, def_id
) => {
890 let hir_id
= self.tcx
.hir().local_def_id_to_hir_id(def_id
.expect_local());
891 let item_id
= self.tcx
.hir().get_parent_node(hir_id
);
892 let item_def_id
= self.tcx
.hir().local_def_id(item_id
);
893 let generics
= self.tcx
.generics_of(item_def_id
);
894 let index
= generics
.param_def_id_to_index
[&def_id
];
895 let name
= self.tcx
.hir().name(hir_id
);
896 let val
= ty
::ConstKind
::Param(ty
::ParamConst
::new(index
, name
));
898 literal
: self.tcx
.mk_const(ty
::Const
{
900 ty
: self.typeck_results().node_type(expr
.hir_id
),
903 const_id
: Some(def_id
),
907 Res
::Def(DefKind
::Const
, def_id
) | Res
::Def(DefKind
::AssocConst
, def_id
) => {
908 let user_ty
= self.user_substs_applied_to_res(expr
.hir_id
, res
);
909 debug
!("convert_path_expr: (const) user_ty={:?}", user_ty
);
911 literal
: self.tcx
.mk_const(ty
::Const
{
912 val
: ty
::ConstKind
::Unevaluated(ty
::Unevaluated
{
913 def
: ty
::WithOptConstParam
::unknown(def_id
),
917 ty
: self.typeck_results().node_type(expr
.hir_id
),
920 const_id
: Some(def_id
),
924 Res
::Def(DefKind
::Ctor(_
, CtorKind
::Const
), def_id
) => {
925 let user_provided_types
= self.typeck_results
.user_provided_types();
926 let user_provided_type
= user_provided_types
.get(expr
.hir_id
).copied();
927 debug
!("convert_path_expr: user_provided_type={:?}", user_provided_type
);
928 let ty
= self.typeck_results().node_type(expr
.hir_id
);
930 // A unit struct/variant which is used as a value.
931 // We return a completely different ExprKind here to account for this special case.
932 ty
::Adt(adt_def
, substs
) => ExprKind
::Adt
{
934 variant_index
: adt_def
.variant_index_with_ctor_id(def_id
),
936 user_ty
: user_provided_type
,
937 fields
: self.arena
.alloc_from_iter(iter
::empty()),
940 _
=> bug
!("unexpected ty: {:?}", ty
),
944 // We encode uses of statics as a `*&STATIC` where the `&STATIC` part is
945 // a constant reference (or constant raw pointer for `static mut`) in MIR
946 Res
::Def(DefKind
::Static
, id
) => {
947 let ty
= self.tcx
.static_ptr_ty(id
);
948 let temp_lifetime
= self.region_scope_tree
.temporary_scope(expr
.hir_id
.local_id
);
949 let kind
= if self.tcx
.is_thread_local_static(id
) {
950 ExprKind
::ThreadLocalRef(id
)
952 let ptr
= self.tcx
.create_static_alloc(id
);
953 ExprKind
::StaticRef
{
954 literal
: ty
::Const
::from_scalar(self.tcx
, Scalar
::Ptr(ptr
.into()), ty
),
959 arg
: self.arena
.alloc(Expr { ty, temp_lifetime, span: expr.span, kind }
),
963 Res
::Local(var_hir_id
) => self.convert_var(var_hir_id
),
965 _
=> span_bug
!(expr
.span
, "res `{:?}` not yet implemented", res
),
969 fn convert_var(&mut self, var_hir_id
: hir
::HirId
) -> ExprKind
<'thir
, 'tcx
> {
970 // We want upvars here not captures.
971 // Captures will be handled in MIR.
974 .upvars_mentioned(self.body_owner
)
975 .map_or(false, |upvars
| upvars
.contains_key(&var_hir_id
));
978 "convert_var({:?}): is_upvar={}, body_owner={:?}",
979 var_hir_id
, is_upvar
, self.body_owner
983 ExprKind
::UpvarRef { closure_def_id: self.body_owner, var_hir_id }
985 ExprKind
::VarRef { id: var_hir_id }
989 fn overloaded_operator(
991 expr
: &'tcx hir
::Expr
<'tcx
>,
992 args
: &'thir
[Expr
<'thir
, 'tcx
>],
993 ) -> ExprKind
<'thir
, 'tcx
> {
994 let fun
= self.arena
.alloc(self.method_callee(expr
, expr
.span
, None
));
995 ExprKind
::Call { ty: fun.ty, fun, args, from_hir_call: false, fn_span: expr.span }
1000 expr
: &'tcx hir
::Expr
<'tcx
>,
1002 overloaded_callee
: Option
<(DefId
, SubstsRef
<'tcx
>)>,
1003 args
: &'thir
[Expr
<'thir
, 'tcx
>],
1005 ) -> ExprKind
<'thir
, 'tcx
> {
1006 // For an overloaded *x or x[y] expression of type T, the method
1007 // call returns an &T and we must add the deref so that the types
1008 // line up (this is because `*x` and `x[y]` represent places):
1010 // Reconstruct the output assuming it's a reference with the
1011 // same region and mutability as the receiver. This holds for
1012 // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
1013 let (region
, mutbl
) = match *args
[0].ty
.kind() {
1014 ty
::Ref(region
, _
, mutbl
) => (region
, mutbl
),
1015 _
=> span_bug
!(span
, "overloaded_place: receiver is not a reference"),
1017 let ref_ty
= self.tcx
.mk_ref(region
, ty
::TypeAndMut { ty: place_ty, mutbl }
);
1019 // construct the complete expression `foo()` for the overloaded call,
1020 // which will yield the &T type
1021 let temp_lifetime
= self.region_scope_tree
.temporary_scope(expr
.hir_id
.local_id
);
1022 let fun
= self.arena
.alloc(self.method_callee(expr
, span
, overloaded_callee
));
1023 let ref_expr
= self.arena
.alloc(Expr
{
1027 kind
: ExprKind
::Call { ty: fun.ty, fun, args, from_hir_call: false, fn_span: span }
,
1030 // construct and return a deref wrapper `*foo()`
1031 ExprKind
::Deref { arg: ref_expr }
1034 fn convert_captured_hir_place(
1036 closure_expr
: &'tcx hir
::Expr
<'tcx
>,
1037 place
: HirPlace
<'tcx
>,
1038 ) -> Expr
<'thir
, 'tcx
> {
1039 let temp_lifetime
= self.region_scope_tree
.temporary_scope(closure_expr
.hir_id
.local_id
);
1040 let var_ty
= place
.base_ty
;
1042 // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
1043 // as it's seen for use within the closure and not at the time of closure creation.
1045 // That is we see expect to see it start from a captured upvar and not something that is local
1046 // to the closure's parent.
1047 let var_hir_id
= match place
.base
{
1048 HirPlaceBase
::Upvar(upvar_id
) => upvar_id
.var_path
.hir_id
,
1049 base
=> bug
!("Expected an upvar, found {:?}", base
),
1052 let mut captured_place_expr
= Expr
{
1055 span
: closure_expr
.span
,
1056 kind
: self.convert_var(var_hir_id
),
1059 for proj
in place
.projections
.iter() {
1060 let kind
= match proj
.kind
{
1061 HirProjectionKind
::Deref
=> {
1062 ExprKind
::Deref { arg: self.arena.alloc(captured_place_expr) }
1064 HirProjectionKind
::Field(field
, ..) => {
1065 // Variant index will always be 0, because for multi-variant
1066 // enums, we capture the enum entirely.
1068 lhs
: self.arena
.alloc(captured_place_expr
),
1069 name
: Field
::new(field
as usize),
1072 HirProjectionKind
::Index
| HirProjectionKind
::Subslice
=> {
1073 // We don't capture these projections, so we can ignore them here
1078 captured_place_expr
=
1079 Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind }
;
1087 closure_expr
: &'tcx hir
::Expr
<'tcx
>,
1088 captured_place
: &'tcx ty
::CapturedPlace
<'tcx
>,
1090 ) -> Expr
<'thir
, 'tcx
> {
1091 let upvar_capture
= captured_place
.info
.capture_kind
;
1092 let captured_place_expr
=
1093 self.convert_captured_hir_place(closure_expr
, captured_place
.place
.clone());
1094 let temp_lifetime
= self.region_scope_tree
.temporary_scope(closure_expr
.hir_id
.local_id
);
1096 match upvar_capture
{
1097 ty
::UpvarCapture
::ByValue(_
) => captured_place_expr
,
1098 ty
::UpvarCapture
::ByRef(upvar_borrow
) => {
1099 let borrow_kind
= match upvar_borrow
.kind
{
1100 ty
::BorrowKind
::ImmBorrow
=> BorrowKind
::Shared
,
1101 ty
::BorrowKind
::UniqueImmBorrow
=> BorrowKind
::Unique
,
1102 ty
::BorrowKind
::MutBorrow
=> BorrowKind
::Mut { allow_two_phase_borrow: false }
,
1107 span
: closure_expr
.span
,
1108 kind
: ExprKind
::Borrow
{
1110 arg
: self.arena
.alloc(captured_place_expr
),
1117 /// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExpr.
1120 fields
: &'tcx
[hir
::ExprField
<'tcx
>],
1121 ) -> &'thir
[FieldExpr
<'thir
, 'tcx
>] {
1122 self.arena
.alloc_from_iter(fields
.iter().map(|field
| FieldExpr
{
1123 name
: Field
::new(self.tcx
.field_index(field
.hir_id
, self.typeck_results
)),
1124 expr
: self.mirror_expr(field
.expr
),
1129 trait ToBorrowKind
{
1130 fn to_borrow_kind(&self) -> BorrowKind
;
1133 impl ToBorrowKind
for AutoBorrowMutability
{
1134 fn to_borrow_kind(&self) -> BorrowKind
{
1135 use rustc_middle
::ty
::adjustment
::AllowTwoPhase
;
1137 AutoBorrowMutability
::Mut { allow_two_phase_borrow }
=> BorrowKind
::Mut
{
1138 allow_two_phase_borrow
: match allow_two_phase_borrow
{
1139 AllowTwoPhase
::Yes
=> true,
1140 AllowTwoPhase
::No
=> false,
1143 AutoBorrowMutability
::Not
=> BorrowKind
::Shared
,
1148 impl ToBorrowKind
for hir
::Mutability
{
1149 fn to_borrow_kind(&self) -> BorrowKind
{
1151 hir
::Mutability
::Mut
=> BorrowKind
::Mut { allow_two_phase_borrow: false }
,
1152 hir
::Mutability
::Not
=> BorrowKind
::Shared
,
1157 fn bin_op(op
: hir
::BinOpKind
) -> BinOp
{
1159 hir
::BinOpKind
::Add
=> BinOp
::Add
,
1160 hir
::BinOpKind
::Sub
=> BinOp
::Sub
,
1161 hir
::BinOpKind
::Mul
=> BinOp
::Mul
,
1162 hir
::BinOpKind
::Div
=> BinOp
::Div
,
1163 hir
::BinOpKind
::Rem
=> BinOp
::Rem
,
1164 hir
::BinOpKind
::BitXor
=> BinOp
::BitXor
,
1165 hir
::BinOpKind
::BitAnd
=> BinOp
::BitAnd
,
1166 hir
::BinOpKind
::BitOr
=> BinOp
::BitOr
,
1167 hir
::BinOpKind
::Shl
=> BinOp
::Shl
,
1168 hir
::BinOpKind
::Shr
=> BinOp
::Shr
,
1169 hir
::BinOpKind
::Eq
=> BinOp
::Eq
,
1170 hir
::BinOpKind
::Lt
=> BinOp
::Lt
,
1171 hir
::BinOpKind
::Le
=> BinOp
::Le
,
1172 hir
::BinOpKind
::Ne
=> BinOp
::Ne
,
1173 hir
::BinOpKind
::Ge
=> BinOp
::Ge
,
1174 hir
::BinOpKind
::Gt
=> BinOp
::Gt
,
1175 _
=> bug
!("no equivalent for ast binop {:?}", op
),