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 expr }
=> {
507 InlineAsmOperand
::Const { expr: self.mirror_expr(expr) }
509 hir
::InlineAsmOperand
::Sym { ref expr }
=> {
510 let qpath
= match expr
.kind
{
511 hir
::ExprKind
::Path(ref qpath
) => qpath
,
514 "asm `sym` operand should be a path, found {:?}",
519 self.region_scope_tree
.temporary_scope(expr
.hir_id
.local_id
);
520 let res
= self.typeck_results().qpath_res(qpath
, expr
.hir_id
);
523 Res
::Def(DefKind
::Fn
, _
) | Res
::Def(DefKind
::AssocFn
, _
) => {
524 ty
= self.typeck_results().node_type(expr
.hir_id
);
525 let user_ty
= self.user_substs_applied_to_res(expr
.hir_id
, res
);
526 InlineAsmOperand
::SymFn
{
527 expr
: self.arena
.alloc(Expr
{
531 kind
: ExprKind
::Literal
{
532 literal
: ty
::Const
::zero_sized(self.tcx
, ty
),
540 Res
::Def(DefKind
::Static
, def_id
) => {
541 InlineAsmOperand
::SymStatic { def_id }
545 self.tcx
.sess
.span_err(
547 "asm `sym` operand must point to a fn or static",
550 // Not a real fn, but we're not reaching codegen anyways...
551 ty
= self.tcx
.ty_error();
552 InlineAsmOperand
::SymFn
{
553 expr
: self.arena
.alloc(Expr
{
557 kind
: ExprKind
::Literal
{
558 literal
: ty
::Const
::zero_sized(self.tcx
, ty
),
569 options
: asm
.options
,
570 line_spans
: asm
.line_spans
,
573 hir
::ExprKind
::LlvmInlineAsm(ref asm
) => ExprKind
::LlvmInlineAsm
{
575 outputs
: self.mirror_exprs(asm
.outputs_exprs
),
576 inputs
: self.mirror_exprs(asm
.inputs_exprs
),
579 hir
::ExprKind
::ConstBlock(ref anon_const
) => {
580 let anon_const_def_id
= self.tcx
.hir().local_def_id(anon_const
.hir_id
);
581 let value
= ty
::Const
::from_anon_const(self.tcx
, anon_const_def_id
);
583 ExprKind
::ConstBlock { value }
585 // Now comes the rote stuff:
586 hir
::ExprKind
::Repeat(ref v
, ref count
) => {
587 let count_def_id
= self.tcx
.hir().local_def_id(count
.hir_id
);
588 let count
= ty
::Const
::from_anon_const(self.tcx
, count_def_id
);
590 ExprKind
::Repeat { value: self.mirror_expr(v), count }
592 hir
::ExprKind
::Ret(ref v
) => {
593 ExprKind
::Return { value: v.as_ref().map(|v| self.mirror_expr(v)) }
595 hir
::ExprKind
::Break(dest
, ref value
) => match dest
.target_id
{
596 Ok(target_id
) => ExprKind
::Break
{
597 label
: region
::Scope { id: target_id.local_id, data: region::ScopeData::Node }
,
598 value
: value
.as_ref().map(|value
| self.mirror_expr(value
)),
600 Err(err
) => bug
!("invalid loop id for break: {}", err
),
602 hir
::ExprKind
::Continue(dest
) => match dest
.target_id
{
603 Ok(loop_id
) => ExprKind
::Continue
{
604 label
: region
::Scope { id: loop_id.local_id, data: region::ScopeData::Node }
,
606 Err(err
) => bug
!("invalid loop id for continue: {}", err
),
608 hir
::ExprKind
::If(cond
, then
, else_opt
) => ExprKind
::If
{
609 cond
: self.mirror_expr(cond
),
610 then
: self.mirror_expr(then
),
611 else_opt
: else_opt
.map(|el
| self.mirror_expr(el
)),
613 hir
::ExprKind
::Match(ref discr
, ref arms
, _
) => ExprKind
::Match
{
614 scrutinee
: self.mirror_expr(discr
),
615 arms
: self.arena
.alloc_from_iter(arms
.iter().map(|a
| self.convert_arm(a
))),
617 hir
::ExprKind
::Loop(ref body
, ..) => {
618 let block_ty
= self.typeck_results().node_type(body
.hir_id
);
619 let temp_lifetime
= self.region_scope_tree
.temporary_scope(body
.hir_id
.local_id
);
620 let block
= self.mirror_block(body
);
621 let body
= self.arena
.alloc(Expr
{
625 kind
: ExprKind
::Block { body: block }
,
627 ExprKind
::Loop { body }
629 hir
::ExprKind
::Field(ref source
, ..) => ExprKind
::Field
{
630 lhs
: self.mirror_expr(source
),
631 name
: Field
::new(self.tcx
.field_index(expr
.hir_id
, self.typeck_results
)),
633 hir
::ExprKind
::Cast(ref source
, ref cast_ty
) => {
634 // Check for a user-given type annotation on this `cast`
635 let user_provided_types
= self.typeck_results
.user_provided_types();
636 let user_ty
= user_provided_types
.get(cast_ty
.hir_id
);
639 "cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}",
640 expr
, cast_ty
.hir_id
, user_ty
,
643 // Check to see if this cast is a "coercion cast", where the cast is actually done
644 // using a coercion (or is a no-op).
645 let cast
= if self.typeck_results().is_coercion_cast(source
.hir_id
) {
646 // Convert the lexpr to a vexpr.
647 ExprKind
::Use { source: self.mirror_expr(source) }
648 } else if self.typeck_results().expr_ty(source
).is_region_ptr() {
649 // Special cased so that we can type check that the element
650 // type of the source matches the pointed to type of the
653 source
: self.mirror_expr(source
),
654 cast
: PointerCast
::ArrayToPointer
,
657 // check whether this is casting an enum variant discriminant
658 // to prevent cycles, we refer to the discriminant initializer
659 // which is always an integer and thus doesn't need to know the
660 // enum's layout (or its tag type) to compute it during const eval
664 // B = A as isize + 4,
666 // The correct solution would be to add symbolic computations to miri,
667 // so we wouldn't have to compute and store the actual value
668 let var
= if let hir
::ExprKind
::Path(ref qpath
) = source
.kind
{
669 let res
= self.typeck_results().qpath_res(qpath
, source
.hir_id
);
670 self.typeck_results().node_type(source
.hir_id
).ty_adt_def().and_then(
671 |adt_def
| match res
{
673 DefKind
::Ctor(CtorOf
::Variant
, CtorKind
::Const
),
676 let idx
= adt_def
.variant_index_with_ctor_id(variant_ctor_id
);
677 let (d
, o
) = adt_def
.discriminant_def_for_variant(idx
);
678 use rustc_middle
::ty
::util
::IntTypeExt
;
679 let ty
= adt_def
.repr
.discr_type();
680 let ty
= ty
.to_ty(self.tcx());
690 let source
= if let Some((did
, offset
, var_ty
)) = var
{
691 let mk_const
= |literal
| {
692 self.arena
.alloc(Expr
{
696 kind
: ExprKind
::Literal { literal, user_ty: None, const_id: None }
,
699 let offset
= mk_const(ty
::Const
::from_bits(
702 self.param_env
.and(var_ty
),
706 // in case we are offsetting from a computed discriminant
707 // and not the beginning of discriminants (which is always `0`)
708 let substs
= InternalSubsts
::identity_for_item(self.tcx(), did
);
709 let lhs
= mk_const(self.tcx().mk_const(ty
::Const
{
710 val
: ty
::ConstKind
::Unevaluated(
711 ty
::WithOptConstParam
::unknown(did
),
718 ExprKind
::Binary { op: BinOp::Add, lhs: lhs, rhs: offset }
;
719 self.arena
.alloc(Expr
{
729 self.mirror_expr(source
)
732 ExprKind
::Cast { source: source }
735 if let Some(user_ty
) = user_ty
{
736 // NOTE: Creating a new Expr and wrapping a Cast inside of it may be
737 // inefficient, revisit this when performance becomes an issue.
738 let cast_expr
= self.arena
.alloc(Expr
{
744 debug
!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty
);
746 ExprKind
::ValueTypeAscription { source: cast_expr, user_ty: Some(*user_ty) }
751 hir
::ExprKind
::Type(ref source
, ref ty
) => {
752 let user_provided_types
= self.typeck_results
.user_provided_types();
753 let user_ty
= user_provided_types
.get(ty
.hir_id
).copied();
754 debug
!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty
);
755 let mirrored
= self.mirror_expr(source
);
756 if source
.is_syntactic_place_expr() {
757 ExprKind
::PlaceTypeAscription { source: mirrored, user_ty }
759 ExprKind
::ValueTypeAscription { source: mirrored, user_ty }
762 hir
::ExprKind
::DropTemps(ref source
) => {
763 ExprKind
::Use { source: self.mirror_expr(source) }
765 hir
::ExprKind
::Box(ref value
) => ExprKind
::Box { value: self.mirror_expr(value) }
,
766 hir
::ExprKind
::Array(ref fields
) => {
767 ExprKind
::Array { fields: self.mirror_exprs(fields) }
769 hir
::ExprKind
::Tup(ref fields
) => ExprKind
::Tuple { fields: self.mirror_exprs(fields) }
,
771 hir
::ExprKind
::Yield(ref v
, _
) => ExprKind
::Yield { value: self.mirror_expr(v) }
,
772 hir
::ExprKind
::Err
=> unreachable
!(),
775 Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind }
778 fn user_substs_applied_to_res(
782 ) -> Option
<ty
::CanonicalUserType
<'tcx
>> {
783 debug
!("user_substs_applied_to_res: res={:?}", res
);
784 let user_provided_type
= match res
{
785 // A reference to something callable -- e.g., a fn, method, or
786 // a tuple-struct or tuple-variant. This has the type of a
787 // `Fn` but with the user-given substitutions.
788 Res
::Def(DefKind
::Fn
, _
)
789 | Res
::Def(DefKind
::AssocFn
, _
)
790 | Res
::Def(DefKind
::Ctor(_
, CtorKind
::Fn
), _
)
791 | Res
::Def(DefKind
::Const
, _
)
792 | Res
::Def(DefKind
::AssocConst
, _
) => {
793 self.typeck_results().user_provided_types().get(hir_id
).copied()
796 // A unit struct/variant which is used as a value (e.g.,
797 // `None`). This has the type of the enum/struct that defines
798 // this variant -- but with the substitutions given by the
800 Res
::Def(DefKind
::Ctor(_
, CtorKind
::Const
), _
) => {
801 self.user_substs_applied_to_ty_of_hir_id(hir_id
)
804 // `Self` is used in expression as a tuple struct constructor or an unit struct constructor
805 Res
::SelfCtor(_
) => self.user_substs_applied_to_ty_of_hir_id(hir_id
),
807 _
=> bug
!("user_substs_applied_to_res: unexpected res {:?} at {:?}", res
, hir_id
),
809 debug
!("user_substs_applied_to_res: user_provided_type={:?}", user_provided_type
);
815 expr
: &hir
::Expr
<'_
>,
817 overloaded_callee
: Option
<(DefId
, SubstsRef
<'tcx
>)>,
818 ) -> Expr
<'thir
, 'tcx
> {
819 let temp_lifetime
= self.region_scope_tree
.temporary_scope(expr
.hir_id
.local_id
);
820 let (def_id
, substs
, user_ty
) = match overloaded_callee
{
821 Some((def_id
, substs
)) => (def_id
, substs
, None
),
824 self.typeck_results().type_dependent_def(expr
.hir_id
).unwrap_or_else(|| {
825 span_bug
!(expr
.span
, "no type-dependent def for method callee")
827 let user_ty
= self.user_substs_applied_to_res(expr
.hir_id
, Res
::Def(kind
, def_id
));
828 debug
!("method_callee: user_ty={:?}", user_ty
);
829 (def_id
, self.typeck_results().node_substs(expr
.hir_id
), user_ty
)
832 let ty
= self.tcx().mk_fn_def(def_id
, substs
);
837 kind
: ExprKind
::Literal
{
838 literal
: ty
::Const
::zero_sized(self.tcx(), ty
),
845 fn convert_arm(&mut self, arm
: &'tcx hir
::Arm
<'tcx
>) -> Arm
<'thir
, 'tcx
> {
847 pattern
: self.pattern_from_hir(&arm
.pat
),
848 guard
: arm
.guard
.as_ref().map(|g
| match g
{
849 hir
::Guard
::If(ref e
) => Guard
::If(self.mirror_expr(e
)),
850 hir
::Guard
::IfLet(ref pat
, ref e
) => {
851 Guard
::IfLet(self.pattern_from_hir(pat
), self.mirror_expr(e
))
854 body
: self.mirror_expr(arm
.body
),
855 lint_level
: LintLevel
::Explicit(arm
.hir_id
),
856 scope
: region
::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node }
,
861 fn convert_path_expr(
863 expr
: &'tcx hir
::Expr
<'tcx
>,
865 ) -> ExprKind
<'thir
, 'tcx
> {
866 let substs
= self.typeck_results().node_substs(expr
.hir_id
);
868 // A regular function, constructor function or a constant.
869 Res
::Def(DefKind
::Fn
, _
)
870 | Res
::Def(DefKind
::AssocFn
, _
)
871 | Res
::Def(DefKind
::Ctor(_
, CtorKind
::Fn
), _
)
872 | Res
::SelfCtor(..) => {
873 let user_ty
= self.user_substs_applied_to_res(expr
.hir_id
, res
);
874 debug
!("convert_path_expr: user_ty={:?}", user_ty
);
876 literal
: ty
::Const
::zero_sized(
878 self.typeck_results().node_type(expr
.hir_id
),
885 Res
::Def(DefKind
::ConstParam
, def_id
) => {
886 let hir_id
= self.tcx
.hir().local_def_id_to_hir_id(def_id
.expect_local());
887 let item_id
= self.tcx
.hir().get_parent_node(hir_id
);
888 let item_def_id
= self.tcx
.hir().local_def_id(item_id
);
889 let generics
= self.tcx
.generics_of(item_def_id
);
890 let index
= generics
.param_def_id_to_index
[&def_id
];
891 let name
= self.tcx
.hir().name(hir_id
);
892 let val
= ty
::ConstKind
::Param(ty
::ParamConst
::new(index
, name
));
894 literal
: self.tcx
.mk_const(ty
::Const
{
896 ty
: self.typeck_results().node_type(expr
.hir_id
),
899 const_id
: Some(def_id
),
903 Res
::Def(DefKind
::Const
, def_id
) | Res
::Def(DefKind
::AssocConst
, def_id
) => {
904 let user_ty
= self.user_substs_applied_to_res(expr
.hir_id
, res
);
905 debug
!("convert_path_expr: (const) user_ty={:?}", user_ty
);
907 literal
: self.tcx
.mk_const(ty
::Const
{
908 val
: ty
::ConstKind
::Unevaluated(
909 ty
::WithOptConstParam
::unknown(def_id
),
913 ty
: self.typeck_results().node_type(expr
.hir_id
),
916 const_id
: Some(def_id
),
920 Res
::Def(DefKind
::Ctor(_
, CtorKind
::Const
), def_id
) => {
921 let user_provided_types
= self.typeck_results
.user_provided_types();
922 let user_provided_type
= user_provided_types
.get(expr
.hir_id
).copied();
923 debug
!("convert_path_expr: user_provided_type={:?}", user_provided_type
);
924 let ty
= self.typeck_results().node_type(expr
.hir_id
);
926 // A unit struct/variant which is used as a value.
927 // We return a completely different ExprKind here to account for this special case.
928 ty
::Adt(adt_def
, substs
) => ExprKind
::Adt
{
930 variant_index
: adt_def
.variant_index_with_ctor_id(def_id
),
932 user_ty
: user_provided_type
,
933 fields
: self.arena
.alloc_from_iter(iter
::empty()),
936 _
=> bug
!("unexpected ty: {:?}", ty
),
940 // We encode uses of statics as a `*&STATIC` where the `&STATIC` part is
941 // a constant reference (or constant raw pointer for `static mut`) in MIR
942 Res
::Def(DefKind
::Static
, id
) => {
943 let ty
= self.tcx
.static_ptr_ty(id
);
944 let temp_lifetime
= self.region_scope_tree
.temporary_scope(expr
.hir_id
.local_id
);
945 let kind
= if self.tcx
.is_thread_local_static(id
) {
946 ExprKind
::ThreadLocalRef(id
)
948 let ptr
= self.tcx
.create_static_alloc(id
);
949 ExprKind
::StaticRef
{
950 literal
: ty
::Const
::from_scalar(self.tcx
, Scalar
::Ptr(ptr
.into()), ty
),
955 arg
: self.arena
.alloc(Expr { ty, temp_lifetime, span: expr.span, kind }
),
959 Res
::Local(var_hir_id
) => self.convert_var(var_hir_id
),
961 _
=> span_bug
!(expr
.span
, "res `{:?}` not yet implemented", res
),
965 fn convert_var(&mut self, var_hir_id
: hir
::HirId
) -> ExprKind
<'thir
, 'tcx
> {
966 // We want upvars here not captures.
967 // Captures will be handled in MIR.
970 .upvars_mentioned(self.body_owner
)
971 .map_or(false, |upvars
| upvars
.contains_key(&var_hir_id
));
974 "convert_var({:?}): is_upvar={}, body_owner={:?}",
975 var_hir_id
, is_upvar
, self.body_owner
979 ExprKind
::UpvarRef { closure_def_id: self.body_owner, var_hir_id }
981 ExprKind
::VarRef { id: var_hir_id }
985 fn overloaded_operator(
987 expr
: &'tcx hir
::Expr
<'tcx
>,
988 args
: &'thir
[Expr
<'thir
, 'tcx
>],
989 ) -> ExprKind
<'thir
, 'tcx
> {
990 let fun
= self.arena
.alloc(self.method_callee(expr
, expr
.span
, None
));
991 ExprKind
::Call { ty: fun.ty, fun, args, from_hir_call: false, fn_span: expr.span }
996 expr
: &'tcx hir
::Expr
<'tcx
>,
998 overloaded_callee
: Option
<(DefId
, SubstsRef
<'tcx
>)>,
999 args
: &'thir
[Expr
<'thir
, 'tcx
>],
1001 ) -> ExprKind
<'thir
, 'tcx
> {
1002 // For an overloaded *x or x[y] expression of type T, the method
1003 // call returns an &T and we must add the deref so that the types
1004 // line up (this is because `*x` and `x[y]` represent places):
1006 // Reconstruct the output assuming it's a reference with the
1007 // same region and mutability as the receiver. This holds for
1008 // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
1009 let (region
, mutbl
) = match *args
[0].ty
.kind() {
1010 ty
::Ref(region
, _
, mutbl
) => (region
, mutbl
),
1011 _
=> span_bug
!(span
, "overloaded_place: receiver is not a reference"),
1013 let ref_ty
= self.tcx
.mk_ref(region
, ty
::TypeAndMut { ty: place_ty, mutbl }
);
1015 // construct the complete expression `foo()` for the overloaded call,
1016 // which will yield the &T type
1017 let temp_lifetime
= self.region_scope_tree
.temporary_scope(expr
.hir_id
.local_id
);
1018 let fun
= self.arena
.alloc(self.method_callee(expr
, span
, overloaded_callee
));
1019 let ref_expr
= self.arena
.alloc(Expr
{
1023 kind
: ExprKind
::Call { ty: fun.ty, fun, args, from_hir_call: false, fn_span: span }
,
1026 // construct and return a deref wrapper `*foo()`
1027 ExprKind
::Deref { arg: ref_expr }
1030 fn convert_captured_hir_place(
1032 closure_expr
: &'tcx hir
::Expr
<'tcx
>,
1033 place
: HirPlace
<'tcx
>,
1034 ) -> Expr
<'thir
, 'tcx
> {
1035 let temp_lifetime
= self.region_scope_tree
.temporary_scope(closure_expr
.hir_id
.local_id
);
1036 let var_ty
= place
.base_ty
;
1038 // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path
1039 // as it's seen for use within the closure and not at the time of closure creation.
1041 // That is we see expect to see it start from a captured upvar and not something that is local
1042 // to the closure's parent.
1043 let var_hir_id
= match place
.base
{
1044 HirPlaceBase
::Upvar(upvar_id
) => upvar_id
.var_path
.hir_id
,
1045 base
=> bug
!("Expected an upvar, found {:?}", base
),
1048 let mut captured_place_expr
= Expr
{
1051 span
: closure_expr
.span
,
1052 kind
: self.convert_var(var_hir_id
),
1055 for proj
in place
.projections
.iter() {
1056 let kind
= match proj
.kind
{
1057 HirProjectionKind
::Deref
=> {
1058 ExprKind
::Deref { arg: self.arena.alloc(captured_place_expr) }
1060 HirProjectionKind
::Field(field
, ..) => {
1061 // Variant index will always be 0, because for multi-variant
1062 // enums, we capture the enum entirely.
1064 lhs
: self.arena
.alloc(captured_place_expr
),
1065 name
: Field
::new(field
as usize),
1068 HirProjectionKind
::Index
| HirProjectionKind
::Subslice
=> {
1069 // We don't capture these projections, so we can ignore them here
1074 captured_place_expr
=
1075 Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind }
;
1083 closure_expr
: &'tcx hir
::Expr
<'tcx
>,
1084 captured_place
: &'tcx ty
::CapturedPlace
<'tcx
>,
1086 ) -> Expr
<'thir
, 'tcx
> {
1087 let upvar_capture
= captured_place
.info
.capture_kind
;
1088 let captured_place_expr
=
1089 self.convert_captured_hir_place(closure_expr
, captured_place
.place
.clone());
1090 let temp_lifetime
= self.region_scope_tree
.temporary_scope(closure_expr
.hir_id
.local_id
);
1092 match upvar_capture
{
1093 ty
::UpvarCapture
::ByValue(_
) => captured_place_expr
,
1094 ty
::UpvarCapture
::ByRef(upvar_borrow
) => {
1095 let borrow_kind
= match upvar_borrow
.kind
{
1096 ty
::BorrowKind
::ImmBorrow
=> BorrowKind
::Shared
,
1097 ty
::BorrowKind
::UniqueImmBorrow
=> BorrowKind
::Unique
,
1098 ty
::BorrowKind
::MutBorrow
=> BorrowKind
::Mut { allow_two_phase_borrow: false }
,
1103 span
: closure_expr
.span
,
1104 kind
: ExprKind
::Borrow
{
1106 arg
: self.arena
.alloc(captured_place_expr
),
1113 /// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExpr.
1116 fields
: &'tcx
[hir
::ExprField
<'tcx
>],
1117 ) -> &'thir
[FieldExpr
<'thir
, 'tcx
>] {
1118 self.arena
.alloc_from_iter(fields
.iter().map(|field
| FieldExpr
{
1119 name
: Field
::new(self.tcx
.field_index(field
.hir_id
, self.typeck_results
)),
1120 expr
: self.mirror_expr(field
.expr
),
1125 trait ToBorrowKind
{
1126 fn to_borrow_kind(&self) -> BorrowKind
;
1129 impl ToBorrowKind
for AutoBorrowMutability
{
1130 fn to_borrow_kind(&self) -> BorrowKind
{
1131 use rustc_middle
::ty
::adjustment
::AllowTwoPhase
;
1133 AutoBorrowMutability
::Mut { allow_two_phase_borrow }
=> BorrowKind
::Mut
{
1134 allow_two_phase_borrow
: match allow_two_phase_borrow
{
1135 AllowTwoPhase
::Yes
=> true,
1136 AllowTwoPhase
::No
=> false,
1139 AutoBorrowMutability
::Not
=> BorrowKind
::Shared
,
1144 impl ToBorrowKind
for hir
::Mutability
{
1145 fn to_borrow_kind(&self) -> BorrowKind
{
1147 hir
::Mutability
::Mut
=> BorrowKind
::Mut { allow_two_phase_borrow: false }
,
1148 hir
::Mutability
::Not
=> BorrowKind
::Shared
,
1153 fn bin_op(op
: hir
::BinOpKind
) -> BinOp
{
1155 hir
::BinOpKind
::Add
=> BinOp
::Add
,
1156 hir
::BinOpKind
::Sub
=> BinOp
::Sub
,
1157 hir
::BinOpKind
::Mul
=> BinOp
::Mul
,
1158 hir
::BinOpKind
::Div
=> BinOp
::Div
,
1159 hir
::BinOpKind
::Rem
=> BinOp
::Rem
,
1160 hir
::BinOpKind
::BitXor
=> BinOp
::BitXor
,
1161 hir
::BinOpKind
::BitAnd
=> BinOp
::BitAnd
,
1162 hir
::BinOpKind
::BitOr
=> BinOp
::BitOr
,
1163 hir
::BinOpKind
::Shl
=> BinOp
::Shl
,
1164 hir
::BinOpKind
::Shr
=> BinOp
::Shr
,
1165 hir
::BinOpKind
::Eq
=> BinOp
::Eq
,
1166 hir
::BinOpKind
::Lt
=> BinOp
::Lt
,
1167 hir
::BinOpKind
::Le
=> BinOp
::Le
,
1168 hir
::BinOpKind
::Ne
=> BinOp
::Ne
,
1169 hir
::BinOpKind
::Ge
=> BinOp
::Ge
,
1170 hir
::BinOpKind
::Gt
=> BinOp
::Gt
,
1171 _
=> bug
!("no equivalent for ast binop {:?}", op
),