1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use rustc_data_structures
::indexed_vec
::Idx
;
13 use rustc_const_math
::ConstInt
;
16 use hair
::cx
::to_ref
::ToRef
;
18 use rustc
::hir
::def
::{Def, CtorKind}
;
19 use rustc
::middle
::const_val
::ConstVal
;
20 use rustc_const_eval
::{ConstContext, fatal_const_eval_err}
;
21 use rustc
::ty
::{self, AdtKind, VariantDef, Ty}
;
22 use rustc
::ty
::cast
::CastKind
as TyCastKind
;
26 impl<'tcx
> Mirror
<'tcx
> for &'tcx hir
::Expr
{
27 type Output
= Expr
<'tcx
>;
29 fn make_mirror
<'a
, 'gcx
>(self, cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>) -> Expr
<'tcx
> {
30 let (temp_lifetime
, was_shrunk
) = cx
.tcx
.region_maps
.temporary_scope2(self.id
);
31 let expr_extent
= cx
.tcx
.region_maps
.node_extent(self.id
);
33 debug
!("Expr::make_mirror(): id={}, span={:?}", self.id
, self.span
);
35 let mut expr
= make_mirror_unadjusted(cx
, self);
36 let adj
= cx
.tables().adjustments
.get(&self.id
).cloned();
38 debug
!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}",
42 // Now apply adjustments, if any.
43 match adj
.map(|adj
| (adj
.kind
, adj
.target
)) {
45 Some((ty
::adjustment
::Adjust
::ReifyFnPointer
, adjusted_ty
)) => {
47 temp_lifetime
: temp_lifetime
,
48 temp_lifetime_was_shrunk
: was_shrunk
,
51 kind
: ExprKind
::ReifyFnPointer { source: expr.to_ref() }
,
54 Some((ty
::adjustment
::Adjust
::UnsafeFnPointer
, adjusted_ty
)) => {
56 temp_lifetime
: temp_lifetime
,
57 temp_lifetime_was_shrunk
: was_shrunk
,
60 kind
: ExprKind
::UnsafeFnPointer { source: expr.to_ref() }
,
63 Some((ty
::adjustment
::Adjust
::ClosureFnPointer
, adjusted_ty
)) => {
65 temp_lifetime
: temp_lifetime
,
66 temp_lifetime_was_shrunk
: was_shrunk
,
69 kind
: ExprKind
::ClosureFnPointer { source: expr.to_ref() }
,
72 Some((ty
::adjustment
::Adjust
::NeverToAny
, adjusted_ty
)) => {
74 temp_lifetime
: temp_lifetime
,
75 temp_lifetime_was_shrunk
: was_shrunk
,
78 kind
: ExprKind
::NeverToAny { source: expr.to_ref() }
,
81 Some((ty
::adjustment
::Adjust
::MutToConstPointer
, adjusted_ty
)) => {
83 temp_lifetime
: temp_lifetime
,
84 temp_lifetime_was_shrunk
: was_shrunk
,
87 kind
: ExprKind
::Cast { source: expr.to_ref() }
,
90 Some((ty
::adjustment
::Adjust
::DerefRef { autoderefs, autoref, unsize }
,
92 for i
in 0..autoderefs
{
95 expr
.ty
.adjust_for_autoderef(cx
.tcx
, self.id
, self.span
, i
, |mc
| {
96 cx
.tables().method_map
.get(&mc
).map(|m
| m
.ty
)
98 debug
!("make_mirror: autoderef #{}, adjusted_ty={:?}",
101 let method_key
= ty
::MethodCall
::autoderef(self.id
, i
);
102 let meth_ty
= cx
.tables().method_map
.get(&method_key
).map(|m
| m
.ty
);
103 let kind
= if let Some(meth_ty
) = meth_ty
{
104 debug
!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty
);
106 let ref_ty
= cx
.tcx
.no_late_bound_regions(&meth_ty
.fn_ret());
107 let (region
, mutbl
) = match ref_ty
{
108 Some(&ty
::TyS { sty: ty::TyRef(region, mt), .. }
) => (region
, mt
.mutbl
),
109 _
=> span_bug
!(expr
.span
, "autoderef returned bad type"),
113 temp_lifetime
: temp_lifetime
,
114 temp_lifetime_was_shrunk
: was_shrunk
,
115 ty
: cx
.tcx
.mk_ref(region
,
121 kind
: ExprKind
::Borrow
{
123 borrow_kind
: to_borrow_kind(mutbl
),
128 overloaded_lvalue(cx
,
135 debug
!("make_mirror: built-in autoderef");
136 ExprKind
::Deref { arg: expr.to_ref() }
139 temp_lifetime
: temp_lifetime
,
140 temp_lifetime_was_shrunk
: was_shrunk
,
147 if let Some(autoref
) = autoref
{
148 let adjusted_ty
= expr
.ty
.adjust_for_autoref(cx
.tcx
, Some(autoref
));
150 ty
::adjustment
::AutoBorrow
::Ref(r
, m
) => {
152 temp_lifetime
: temp_lifetime
,
153 temp_lifetime_was_shrunk
: was_shrunk
,
156 kind
: ExprKind
::Borrow
{
158 borrow_kind
: to_borrow_kind(m
),
163 ty
::adjustment
::AutoBorrow
::RawPtr(m
) => {
164 // Convert this to a suitable `&foo` and
165 // then an unsafe coercion. Limit the region to be just this
167 let region
= ty
::ReScope(expr_extent
);
168 let region
= cx
.tcx
.mk_region(region
);
170 temp_lifetime
: temp_lifetime
,
171 temp_lifetime_was_shrunk
: was_shrunk
,
172 ty
: cx
.tcx
.mk_ref(region
,
178 kind
: ExprKind
::Borrow
{
180 borrow_kind
: to_borrow_kind(m
),
185 temp_lifetime
: temp_lifetime
,
186 temp_lifetime_was_shrunk
: was_shrunk
,
189 kind
: ExprKind
::Cast { source: expr.to_ref() }
,
197 temp_lifetime
: temp_lifetime
,
198 temp_lifetime_was_shrunk
: was_shrunk
,
201 kind
: ExprKind
::Unsize { source: expr.to_ref() }
,
207 // Next, wrap this up in the expr's scope.
209 temp_lifetime
: temp_lifetime
,
210 temp_lifetime_was_shrunk
: was_shrunk
,
213 kind
: ExprKind
::Scope
{
215 value
: expr
.to_ref(),
219 // Finally, create a destruction scope, if any.
220 if let Some(extent
) = cx
.tcx
.region_maps
.opt_destruction_extent(self.id
) {
222 temp_lifetime
: temp_lifetime
,
223 temp_lifetime_was_shrunk
: was_shrunk
,
226 kind
: ExprKind
::Scope
{
228 value
: expr
.to_ref(),
238 fn make_mirror_unadjusted
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>,
239 expr
: &'tcx hir
::Expr
)
241 let expr_ty
= cx
.tables().expr_ty(expr
);
242 let (temp_lifetime
, was_shrunk
) = cx
.tcx
.region_maps
.temporary_scope2(expr
.id
);
244 let kind
= match expr
.node
{
245 // Here comes the interesting stuff:
246 hir
::ExprMethodCall(.., ref args
) => {
247 // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
248 let expr
= method_callee(cx
, expr
, ty
::MethodCall
::expr(expr
.id
));
249 let args
= args
.iter()
259 hir
::ExprCall(ref fun
, ref args
) => {
260 if cx
.tables().is_method_call(expr
.id
) {
261 // The callee is something implementing Fn, FnMut, or FnOnce.
262 // Find the actual method implementation being called and
263 // build the appropriate UFCS call expression with the
264 // callee-object as expr parameter.
266 // rewrite f(u, v) into FnOnce::call_once(f, (u, v))
268 let method
= method_callee(cx
, expr
, ty
::MethodCall
::expr(expr
.id
));
270 let sig
= method
.ty
.fn_sig();
273 .no_late_bound_regions(&sig
)
274 .unwrap_or_else(|| span_bug
!(expr
.span
, "method call has late-bound regions"));
276 assert_eq
!(sig
.inputs().len(), 2);
278 let tupled_args
= Expr
{
280 temp_lifetime
: temp_lifetime
,
281 temp_lifetime_was_shrunk
: was_shrunk
,
283 kind
: ExprKind
::Tuple { fields: args.iter().map(ToRef::to_ref).collect() }
,
288 fun
: method
.to_ref(),
289 args
: vec
![fun
.to_ref(), tupled_args
.to_ref()],
292 let adt_data
= if let hir
::ExprPath(hir
::QPath
::Resolved(_
, ref path
)) = fun
.node
{
293 // Tuple-like ADTs are represented as ExprCall. We convert them here.
294 expr_ty
.ty_adt_def().and_then(|adt_def
| {
296 Def
::VariantCtor(variant_id
, CtorKind
::Fn
) => {
297 Some((adt_def
, adt_def
.variant_index_with_id(variant_id
)))
299 Def
::StructCtor(_
, CtorKind
::Fn
) => Some((adt_def
, 0)),
306 if let Some((adt_def
, index
)) = adt_data
{
307 let substs
= cx
.tables().node_id_item_substs(fun
.id
)
308 .unwrap_or_else(|| cx
.tcx
.intern_substs(&[]));
309 let field_refs
= args
.iter()
313 name
: Field
::new(idx
),
321 variant_index
: index
,
327 ty
: cx
.tables().node_id_to_type(fun
.id
),
335 hir
::ExprAddrOf(mutbl
, ref expr
) => {
336 let region
= match expr_ty
.sty
{
337 ty
::TyRef(r
, _
) => r
,
338 _
=> span_bug
!(expr
.span
, "type of & not region"),
342 borrow_kind
: to_borrow_kind(mutbl
),
347 hir
::ExprBlock(ref blk
) => ExprKind
::Block { body: &blk }
,
349 hir
::ExprAssign(ref lhs
, ref rhs
) => {
356 hir
::ExprAssignOp(op
, ref lhs
, ref rhs
) => {
357 if cx
.tables().is_method_call(expr
.id
) {
358 let pass_args
= if op
.node
.is_by_value() {
363 overloaded_operator(cx
,
365 ty
::MethodCall
::expr(expr
.id
),
378 hir
::ExprLit(..) => ExprKind
::Literal { literal: cx.const_eval_literal(expr) }
,
380 hir
::ExprBinary(op
, ref lhs
, ref rhs
) => {
381 if cx
.tables().is_method_call(expr
.id
) {
382 let pass_args
= if op
.node
.is_by_value() {
387 overloaded_operator(cx
,
389 ty
::MethodCall
::expr(expr
.id
),
395 match (op
.node
, cx
.constness
) {
396 // FIXME(eddyb) use logical ops in constants when
397 // they can handle that kind of control-flow.
398 (hir
::BinOp_
::BiAnd
, hir
::Constness
::Const
) => {
405 (hir
::BinOp_
::BiOr
, hir
::Constness
::Const
) => {
413 (hir
::BinOp_
::BiAnd
, hir
::Constness
::NotConst
) => {
414 ExprKind
::LogicalOp
{
420 (hir
::BinOp_
::BiOr
, hir
::Constness
::NotConst
) => {
421 ExprKind
::LogicalOp
{
429 let op
= bin_op(op
.node
);
440 hir
::ExprIndex(ref lhs
, ref index
) => {
441 if cx
.tables().is_method_call(expr
.id
) {
442 overloaded_lvalue(cx
,
444 ty
::MethodCall
::expr(expr
.id
),
451 index
: index
.to_ref(),
456 hir
::ExprUnary(hir
::UnOp
::UnDeref
, ref arg
) => {
457 if cx
.tables().is_method_call(expr
.id
) {
458 overloaded_lvalue(cx
,
460 ty
::MethodCall
::expr(expr
.id
),
465 ExprKind
::Deref { arg: arg.to_ref() }
469 hir
::ExprUnary(hir
::UnOp
::UnNot
, ref arg
) => {
470 if cx
.tables().is_method_call(expr
.id
) {
471 overloaded_operator(cx
,
473 ty
::MethodCall
::expr(expr
.id
),
485 hir
::ExprUnary(hir
::UnOp
::UnNeg
, ref arg
) => {
486 if cx
.tables().is_method_call(expr
.id
) {
487 overloaded_operator(cx
,
489 ty
::MethodCall
::expr(expr
.id
),
494 // FIXME runtime-overflow
495 if let hir
::ExprLit(_
) = arg
.node
{
496 ExprKind
::Literal { literal: cx.const_eval_literal(expr) }
506 hir
::ExprStruct(ref qpath
, ref fields
, ref base
) => {
508 ty
::TyAdt(adt
, substs
) => {
509 match adt
.adt_kind() {
510 AdtKind
::Struct
| AdtKind
::Union
=> {
511 let field_refs
= field_refs(&adt
.variants
[0], fields
);
517 base
: base
.as_ref().map(|base
| {
520 field_types
: cx
.tables().fru_field_types
[&expr
.id
].clone(),
526 let def
= match *qpath
{
527 hir
::QPath
::Resolved(_
, ref path
) => path
.def
,
528 hir
::QPath
::TypeRelative(..) => Def
::Err
,
531 Def
::Variant(variant_id
) => {
532 assert
!(base
.is_none());
534 let index
= adt
.variant_index_with_id(variant_id
);
535 let field_refs
= field_refs(&adt
.variants
[index
], fields
);
538 variant_index
: index
,
545 span_bug
!(expr
.span
, "unexpected def: {:?}", def
);
553 "unexpected type for struct literal: {:?}",
559 hir
::ExprClosure(..) => {
560 let closure_ty
= cx
.tables().expr_ty(expr
);
561 let (def_id
, substs
) = match closure_ty
.sty
{
562 ty
::TyClosure(def_id
, substs
) => (def_id
, substs
),
564 span_bug
!(expr
.span
, "closure expr w/o closure type: {:?}", closure_ty
);
567 let upvars
= cx
.tcx
.with_freevars(expr
.id
, |freevars
| {
569 .zip(substs
.upvar_tys(def_id
, cx
.tcx
))
570 .map(|(fv
, ty
)| capture_freevar(cx
, expr
, fv
, ty
))
580 hir
::ExprPath(ref qpath
) => {
581 let def
= cx
.tables().qpath_def(qpath
, expr
.id
);
582 convert_path_expr(cx
, expr
, def
)
585 hir
::ExprInlineAsm(ref asm
, ref outputs
, ref inputs
) => {
586 ExprKind
::InlineAsm
{
588 outputs
: outputs
.to_ref(),
589 inputs
: inputs
.to_ref(),
593 // Now comes the rote stuff:
594 hir
::ExprRepeat(ref v
, count
) => {
595 let tcx
= cx
.tcx
.global_tcx();
596 let c
= &cx
.tcx
.hir
.body(count
).value
;
597 let count
= match ConstContext
::new(tcx
, count
).eval(c
) {
598 Ok(ConstVal
::Integral(ConstInt
::Usize(u
))) => u
,
599 Ok(other
) => bug
!("constant evaluation of repeat count yielded {:?}", other
),
600 Err(s
) => fatal_const_eval_err(tcx
, &s
, c
.span
, "expression")
608 hir
::ExprRet(ref v
) => ExprKind
::Return { value: v.to_ref() }
,
609 hir
::ExprBreak(label
, ref value
) => {
610 match label
.loop_id
.into() {
611 Ok(loop_id
) => ExprKind
::Break
{
612 label
: cx
.tcx
.region_maps
.node_extent(loop_id
),
613 value
: value
.to_ref(),
615 Err(err
) => bug
!("invalid loop id for break: {}", err
)
619 hir
::ExprAgain(label
) => {
620 match label
.loop_id
.into() {
621 Ok(loop_id
) => ExprKind
::Continue
{
622 label
: cx
.tcx
.region_maps
.node_extent(loop_id
),
624 Err(err
) => bug
!("invalid loop id for continue: {}", err
)
627 hir
::ExprMatch(ref discr
, ref arms
, _
) => {
629 discriminant
: discr
.to_ref(),
630 arms
: arms
.iter().map(|a
| convert_arm(cx
, a
)).collect(),
633 hir
::ExprIf(ref cond
, ref then
, ref otherwise
) => {
635 condition
: cond
.to_ref(),
636 then
: block
::to_expr_ref(cx
, then
),
637 otherwise
: otherwise
.to_ref(),
640 hir
::ExprWhile(ref cond
, ref body
, _
) => {
642 condition
: Some(cond
.to_ref()),
643 body
: block
::to_expr_ref(cx
, body
),
646 hir
::ExprLoop(ref body
, _
, _
) => {
649 body
: block
::to_expr_ref(cx
, body
),
652 hir
::ExprField(ref source
, name
) => {
653 let index
= match cx
.tables().expr_ty_adjusted(source
).sty
{
654 ty
::TyAdt(adt_def
, _
) => adt_def
.variants
[0].index_of_field_named(name
.node
),
655 ref ty
=> span_bug
!(expr
.span
, "field of non-ADT: {:?}", ty
),
658 index
.unwrap_or_else(|| {
659 span_bug
!(expr
.span
, "no index found for field `{}`", name
.node
)
662 lhs
: source
.to_ref(),
663 name
: Field
::new(index
),
666 hir
::ExprTupField(ref source
, index
) => {
668 lhs
: source
.to_ref(),
669 name
: Field
::new(index
.node
as usize),
672 hir
::ExprCast(ref source
, _
) => {
673 // Check to see if this cast is a "coercion cast", where the cast is actually done
674 // using a coercion (or is a no-op).
675 if let Some(&TyCastKind
::CoercionCast
) = cx
.tables().cast_kinds
.get(&source
.id
) {
676 // Convert the lexpr to a vexpr.
677 ExprKind
::Use { source: source.to_ref() }
679 ExprKind
::Cast { source: source.to_ref() }
682 hir
::ExprType(ref source
, _
) => return source
.make_mirror(cx
),
683 hir
::ExprBox(ref value
) => {
685 value
: value
.to_ref(),
686 value_extents
: cx
.tcx
.region_maps
.node_extent(value
.id
),
689 hir
::ExprArray(ref fields
) => ExprKind
::Array { fields: fields.to_ref() }
,
690 hir
::ExprTup(ref fields
) => ExprKind
::Tuple { fields: fields.to_ref() }
,
694 temp_lifetime
: temp_lifetime
,
695 temp_lifetime_was_shrunk
: was_shrunk
,
702 fn method_callee
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>,
704 method_call
: ty
::MethodCall
)
706 let callee
= cx
.tables().method_map
[&method_call
];
707 let (temp_lifetime
, was_shrunk
) = cx
.tcx
.region_maps
.temporary_scope2(expr
.id
);
709 temp_lifetime
: temp_lifetime
,
710 temp_lifetime_was_shrunk
: was_shrunk
,
713 kind
: ExprKind
::Literal
{
714 literal
: Literal
::Item
{
715 def_id
: callee
.def_id
,
716 substs
: callee
.substs
,
722 fn to_borrow_kind(m
: hir
::Mutability
) -> BorrowKind
{
724 hir
::MutMutable
=> BorrowKind
::Mut
,
725 hir
::MutImmutable
=> BorrowKind
::Shared
,
729 fn convert_arm
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>, arm
: &'tcx hir
::Arm
) -> Arm
<'tcx
> {
731 patterns
: arm
.pats
.iter().map(|p
| Pattern
::from_hir(cx
.tcx
, cx
.tables(), p
)).collect(),
732 guard
: arm
.guard
.to_ref(),
733 body
: arm
.body
.to_ref(),
737 fn convert_path_expr
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>,
738 expr
: &'tcx hir
::Expr
,
741 let substs
= cx
.tables().node_id_item_substs(expr
.id
)
742 .unwrap_or_else(|| cx
.tcx
.intern_substs(&[]));
743 let def_id
= match def
{
744 // A regular function, constructor function or a constant.
746 Def
::Method(def_id
) |
747 Def
::StructCtor(def_id
, CtorKind
::Fn
) |
748 Def
::VariantCtor(def_id
, CtorKind
::Fn
) |
750 Def
::AssociatedConst(def_id
) => def_id
,
752 Def
::StructCtor(def_id
, CtorKind
::Const
) |
753 Def
::VariantCtor(def_id
, CtorKind
::Const
) => {
754 match cx
.tables().node_id_to_type(expr
.id
).sty
{
755 // A unit struct/variant which is used as a value.
756 // We return a completely different ExprKind here to account for this special case.
757 ty
::TyAdt(adt_def
, substs
) => {
758 return ExprKind
::Adt
{
760 variant_index
: adt_def
.variant_index_with_id(def_id
),
766 ref sty
=> bug
!("unexpected sty: {:?}", sty
),
770 Def
::Static(node_id
, _
) => return ExprKind
::StaticRef { id: node_id }
,
772 Def
::Local(..) | Def
::Upvar(..) => return convert_var(cx
, expr
, def
),
774 _
=> span_bug
!(expr
.span
, "def `{:?}` not yet implemented", def
),
777 literal
: Literal
::Item
{
784 fn convert_var
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>,
785 expr
: &'tcx hir
::Expr
,
788 let (temp_lifetime
, was_shrunk
) = cx
.tcx
.region_maps
.temporary_scope2(expr
.id
);
791 Def
::Local(def_id
) => {
792 let node_id
= cx
.tcx
.hir
.as_local_node_id(def_id
).unwrap();
793 ExprKind
::VarRef { id: node_id }
796 Def
::Upvar(def_id
, index
, closure_expr_id
) => {
797 let id_var
= cx
.tcx
.hir
.as_local_node_id(def_id
).unwrap();
798 debug
!("convert_var(upvar({:?}, {:?}, {:?}))",
802 let var_ty
= cx
.tables().node_id_to_type(id_var
);
804 let body_id
= match cx
.tcx
.hir
.find(closure_expr_id
) {
805 Some(map
::NodeExpr(expr
)) => {
807 hir
::ExprClosure(.., body
, _
) => body
.node_id
,
809 span_bug
!(expr
.span
, "closure expr is not a closure expr");
814 span_bug
!(expr
.span
, "ast-map has garbage for closure expr");
818 // FIXME free regions in closures are not right
819 let closure_ty
= cx
.tables().node_id_to_type(closure_expr_id
);
821 // FIXME we're just hard-coding the idea that the
822 // signature will be &self or &mut self and hence will
823 // have a bound region with number 0
824 let region
= ty
::Region
::ReFree(ty
::FreeRegion
{
825 scope
: cx
.tcx
.region_maps
.node_extent(body_id
),
826 bound_region
: ty
::BoundRegion
::BrAnon(0),
828 let region
= cx
.tcx
.mk_region(region
);
830 let self_expr
= match cx
.tcx
.closure_kind(cx
.tcx
.hir
.local_def_id(closure_expr_id
)) {
831 ty
::ClosureKind
::Fn
=> {
832 let ref_closure_ty
= cx
.tcx
.mk_ref(region
,
835 mutbl
: hir
::MutImmutable
,
839 temp_lifetime
: temp_lifetime
,
840 temp_lifetime_was_shrunk
: was_shrunk
,
842 kind
: ExprKind
::Deref
{
845 temp_lifetime
: temp_lifetime
,
846 temp_lifetime_was_shrunk
: was_shrunk
,
848 kind
: ExprKind
::SelfRef
,
854 ty
::ClosureKind
::FnMut
=> {
855 let ref_closure_ty
= cx
.tcx
.mk_ref(region
,
858 mutbl
: hir
::MutMutable
,
862 temp_lifetime
: temp_lifetime
,
863 temp_lifetime_was_shrunk
: was_shrunk
,
865 kind
: ExprKind
::Deref
{
868 temp_lifetime
: temp_lifetime
,
869 temp_lifetime_was_shrunk
: was_shrunk
,
871 kind
: ExprKind
::SelfRef
,
876 ty
::ClosureKind
::FnOnce
=> {
879 temp_lifetime
: temp_lifetime
,
880 temp_lifetime_was_shrunk
: was_shrunk
,
882 kind
: ExprKind
::SelfRef
,
887 // at this point we have `self.n`, which loads up the upvar
888 let field_kind
= ExprKind
::Field
{
889 lhs
: self_expr
.to_ref(),
890 name
: Field
::new(index
),
893 // ...but the upvar might be an `&T` or `&mut T` capture, at which
894 // point we need an implicit deref
895 let upvar_id
= ty
::UpvarId
{
897 closure_expr_id
: closure_expr_id
,
899 let upvar_capture
= match cx
.tables().upvar_capture(upvar_id
) {
902 span_bug
!(expr
.span
, "no upvar_capture for {:?}", upvar_id
);
905 match upvar_capture
{
906 ty
::UpvarCapture
::ByValue
=> field_kind
,
907 ty
::UpvarCapture
::ByRef(borrow
) => {
910 temp_lifetime
: temp_lifetime
,
911 temp_lifetime_was_shrunk
: was_shrunk
,
912 ty
: cx
.tcx
.mk_ref(borrow
.region
,
915 mutbl
: borrow
.kind
.to_mutbl_lossy(),
925 _
=> span_bug
!(expr
.span
, "type of & not region"),
930 fn bin_op(op
: hir
::BinOp_
) -> BinOp
{
932 hir
::BinOp_
::BiAdd
=> BinOp
::Add
,
933 hir
::BinOp_
::BiSub
=> BinOp
::Sub
,
934 hir
::BinOp_
::BiMul
=> BinOp
::Mul
,
935 hir
::BinOp_
::BiDiv
=> BinOp
::Div
,
936 hir
::BinOp_
::BiRem
=> BinOp
::Rem
,
937 hir
::BinOp_
::BiBitXor
=> BinOp
::BitXor
,
938 hir
::BinOp_
::BiBitAnd
=> BinOp
::BitAnd
,
939 hir
::BinOp_
::BiBitOr
=> BinOp
::BitOr
,
940 hir
::BinOp_
::BiShl
=> BinOp
::Shl
,
941 hir
::BinOp_
::BiShr
=> BinOp
::Shr
,
942 hir
::BinOp_
::BiEq
=> BinOp
::Eq
,
943 hir
::BinOp_
::BiLt
=> BinOp
::Lt
,
944 hir
::BinOp_
::BiLe
=> BinOp
::Le
,
945 hir
::BinOp_
::BiNe
=> BinOp
::Ne
,
946 hir
::BinOp_
::BiGe
=> BinOp
::Ge
,
947 hir
::BinOp_
::BiGt
=> BinOp
::Gt
,
948 _
=> bug
!("no equivalent for ast binop {:?}", op
),
957 fn overloaded_operator
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>,
958 expr
: &'tcx hir
::Expr
,
959 method_call
: ty
::MethodCall
,
961 receiver
: ExprRef
<'tcx
>,
962 args
: Vec
<&'tcx P
<hir
::Expr
>>)
964 // the receiver has all the adjustments that are needed, so we can
965 // just push a reference to it
966 let mut argrefs
= vec
![receiver
];
968 // the arguments, unfortunately, do not, so if this is a ByRef
969 // operator, we have to gin up the autorefs (but by value is easy)
971 PassArgs
::ByValue
=> argrefs
.extend(args
.iter().map(|arg
| arg
.to_ref())),
974 let region
= cx
.tcx
.node_scope_region(expr
.id
);
975 let (temp_lifetime
, was_shrunk
) =
976 cx
.tcx
.region_maps
.temporary_scope2(expr
.id
);
977 argrefs
.extend(args
.iter()
979 let arg_ty
= cx
.tables().expr_ty_adjusted(arg
);
980 let adjusted_ty
= cx
.tcx
.mk_ref(region
,
983 mutbl
: hir
::MutImmutable
,
986 temp_lifetime
: temp_lifetime
,
987 temp_lifetime_was_shrunk
: was_shrunk
,
990 kind
: ExprKind
::Borrow
{
992 borrow_kind
: BorrowKind
::Shared
,
1001 // now create the call itself
1002 let fun
= method_callee(cx
, expr
, method_call
);
1010 fn overloaded_lvalue
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>,
1011 expr
: &'tcx hir
::Expr
,
1012 method_call
: ty
::MethodCall
,
1013 pass_args
: PassArgs
,
1014 receiver
: ExprRef
<'tcx
>,
1015 args
: Vec
<&'tcx P
<hir
::Expr
>>)
1017 // For an overloaded *x or x[y] expression of type T, the method
1018 // call returns an &T and we must add the deref so that the types
1019 // line up (this is because `*x` and `x[y]` represent lvalues):
1021 // to find the type &T of the content returned by the method;
1022 let ref_ty
= cx
.tables().method_map
[&method_call
].ty
.fn_ret();
1023 let ref_ty
= cx
.tcx
.no_late_bound_regions(&ref_ty
).unwrap();
1024 // callees always have all late-bound regions fully instantiated,
1026 // construct the complete expression `foo()` for the overloaded call,
1027 // which will yield the &T type
1028 let (temp_lifetime
, was_shrunk
) = cx
.tcx
.region_maps
.temporary_scope2(expr
.id
);
1029 let ref_kind
= overloaded_operator(cx
, expr
, method_call
, pass_args
, receiver
, args
);
1030 let ref_expr
= Expr
{
1031 temp_lifetime
: temp_lifetime
,
1032 temp_lifetime_was_shrunk
: was_shrunk
,
1038 // construct and return a deref wrapper `*foo()`
1039 ExprKind
::Deref { arg: ref_expr.to_ref() }
1042 fn capture_freevar
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>,
1043 closure_expr
: &'tcx hir
::Expr
,
1044 freevar
: &hir
::Freevar
,
1045 freevar_ty
: Ty
<'tcx
>)
1047 let id_var
= cx
.tcx
.hir
.as_local_node_id(freevar
.def
.def_id()).unwrap();
1048 let upvar_id
= ty
::UpvarId
{
1050 closure_expr_id
: closure_expr
.id
,
1052 let upvar_capture
= cx
.tables().upvar_capture(upvar_id
).unwrap();
1053 let (temp_lifetime
, was_shrunk
) = cx
.tcx
.region_maps
.temporary_scope2(closure_expr
.id
);
1054 let var_ty
= cx
.tables().node_id_to_type(id_var
);
1055 let captured_var
= Expr
{
1056 temp_lifetime
: temp_lifetime
,
1057 temp_lifetime_was_shrunk
: was_shrunk
,
1059 span
: closure_expr
.span
,
1060 kind
: convert_var(cx
, closure_expr
, freevar
.def
),
1062 match upvar_capture
{
1063 ty
::UpvarCapture
::ByValue
=> captured_var
.to_ref(),
1064 ty
::UpvarCapture
::ByRef(upvar_borrow
) => {
1065 let borrow_kind
= match upvar_borrow
.kind
{
1066 ty
::BorrowKind
::ImmBorrow
=> BorrowKind
::Shared
,
1067 ty
::BorrowKind
::UniqueImmBorrow
=> BorrowKind
::Unique
,
1068 ty
::BorrowKind
::MutBorrow
=> BorrowKind
::Mut
,
1071 temp_lifetime
: temp_lifetime
,
1072 temp_lifetime_was_shrunk
: was_shrunk
,
1074 span
: closure_expr
.span
,
1075 kind
: ExprKind
::Borrow
{
1076 region
: upvar_borrow
.region
,
1077 borrow_kind
: borrow_kind
,
1078 arg
: captured_var
.to_ref(),
1085 /// Converts a list of named fields (i.e. for struct-like struct/enum ADTs) into FieldExprRef.
1086 fn field_refs
<'tcx
>(variant
: &'tcx VariantDef
,
1087 fields
: &'tcx
[hir
::Field
])
1088 -> Vec
<FieldExprRef
<'tcx
>> {
1092 name
: Field
::new(variant
.index_of_field_named(field
.name
.node
).unwrap()),
1093 expr
: field
.expr
.to_ref(),