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, EvalHint, 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
::NeverToAny
, adjusted_ty
)) => {
65 temp_lifetime
: temp_lifetime
,
66 temp_lifetime_was_shrunk
: was_shrunk
,
69 kind
: ExprKind
::NeverToAny { source: expr.to_ref() }
,
72 Some((ty
::adjustment
::Adjust
::MutToConstPointer
, adjusted_ty
)) => {
74 temp_lifetime
: temp_lifetime
,
75 temp_lifetime_was_shrunk
: was_shrunk
,
78 kind
: ExprKind
::Cast { source: expr.to_ref() }
,
81 Some((ty
::adjustment
::Adjust
::DerefRef { autoderefs, autoref, unsize }
,
83 for i
in 0..autoderefs
{
86 expr
.ty
.adjust_for_autoderef(cx
.tcx
, self.id
, self.span
, i
, |mc
| {
87 cx
.tables().method_map
.get(&mc
).map(|m
| m
.ty
)
89 debug
!("make_mirror: autoderef #{}, adjusted_ty={:?}",
92 let method_key
= ty
::MethodCall
::autoderef(self.id
, i
);
93 let meth_ty
= cx
.tables().method_map
.get(&method_key
).map(|m
| m
.ty
);
94 let kind
= if let Some(meth_ty
) = meth_ty
{
95 debug
!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty
);
97 let ref_ty
= cx
.tcx
.no_late_bound_regions(&meth_ty
.fn_ret());
98 let (region
, mutbl
) = match ref_ty
{
99 Some(&ty
::TyS { sty: ty::TyRef(region, mt), .. }
) => (region
, mt
.mutbl
),
100 _
=> span_bug
!(expr
.span
, "autoderef returned bad type"),
104 temp_lifetime
: temp_lifetime
,
105 temp_lifetime_was_shrunk
: was_shrunk
,
106 ty
: cx
.tcx
.mk_ref(region
,
112 kind
: ExprKind
::Borrow
{
114 borrow_kind
: to_borrow_kind(mutbl
),
119 overloaded_lvalue(cx
,
126 debug
!("make_mirror: built-in autoderef");
127 ExprKind
::Deref { arg: expr.to_ref() }
130 temp_lifetime
: temp_lifetime
,
131 temp_lifetime_was_shrunk
: was_shrunk
,
138 if let Some(autoref
) = autoref
{
139 let adjusted_ty
= expr
.ty
.adjust_for_autoref(cx
.tcx
, Some(autoref
));
141 ty
::adjustment
::AutoBorrow
::Ref(r
, m
) => {
143 temp_lifetime
: temp_lifetime
,
144 temp_lifetime_was_shrunk
: was_shrunk
,
147 kind
: ExprKind
::Borrow
{
149 borrow_kind
: to_borrow_kind(m
),
154 ty
::adjustment
::AutoBorrow
::RawPtr(m
) => {
155 // Convert this to a suitable `&foo` and
156 // then an unsafe coercion. Limit the region to be just this
158 let region
= ty
::ReScope(expr_extent
);
159 let region
= cx
.tcx
.mk_region(region
);
161 temp_lifetime
: temp_lifetime
,
162 temp_lifetime_was_shrunk
: was_shrunk
,
163 ty
: cx
.tcx
.mk_ref(region
,
169 kind
: ExprKind
::Borrow
{
171 borrow_kind
: to_borrow_kind(m
),
176 temp_lifetime
: temp_lifetime
,
177 temp_lifetime_was_shrunk
: was_shrunk
,
180 kind
: ExprKind
::Cast { source: expr.to_ref() }
,
188 temp_lifetime
: temp_lifetime
,
189 temp_lifetime_was_shrunk
: was_shrunk
,
192 kind
: ExprKind
::Unsize { source: expr.to_ref() }
,
198 // Next, wrap this up in the expr's scope.
200 temp_lifetime
: temp_lifetime
,
201 temp_lifetime_was_shrunk
: was_shrunk
,
204 kind
: ExprKind
::Scope
{
206 value
: expr
.to_ref(),
210 // Finally, create a destruction scope, if any.
211 if let Some(extent
) = cx
.tcx
.region_maps
.opt_destruction_extent(self.id
) {
213 temp_lifetime
: temp_lifetime
,
214 temp_lifetime_was_shrunk
: was_shrunk
,
217 kind
: ExprKind
::Scope
{
219 value
: expr
.to_ref(),
229 fn make_mirror_unadjusted
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>,
230 expr
: &'tcx hir
::Expr
)
232 let expr_ty
= cx
.tables().expr_ty(expr
);
233 let (temp_lifetime
, was_shrunk
) = cx
.tcx
.region_maps
.temporary_scope2(expr
.id
);
235 let kind
= match expr
.node
{
236 // Here comes the interesting stuff:
237 hir
::ExprMethodCall(.., ref args
) => {
238 // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
239 let expr
= method_callee(cx
, expr
, ty
::MethodCall
::expr(expr
.id
));
240 let args
= args
.iter()
250 hir
::ExprCall(ref fun
, ref args
) => {
251 if cx
.tables().is_method_call(expr
.id
) {
252 // The callee is something implementing Fn, FnMut, or FnOnce.
253 // Find the actual method implementation being called and
254 // build the appropriate UFCS call expression with the
255 // callee-object as expr parameter.
257 // rewrite f(u, v) into FnOnce::call_once(f, (u, v))
259 let method
= method_callee(cx
, expr
, ty
::MethodCall
::expr(expr
.id
));
261 let sig
= match method
.ty
.sty
{
262 ty
::TyFnDef(.., fn_ty
) => &fn_ty
.sig
,
263 _
=> span_bug
!(expr
.span
, "type of method is not an fn"),
267 .no_late_bound_regions(sig
)
268 .unwrap_or_else(|| span_bug
!(expr
.span
, "method call has late-bound regions"));
270 assert_eq
!(sig
.inputs().len(), 2);
272 let tupled_args
= Expr
{
274 temp_lifetime
: temp_lifetime
,
275 temp_lifetime_was_shrunk
: was_shrunk
,
277 kind
: ExprKind
::Tuple { fields: args.iter().map(ToRef::to_ref).collect() }
,
282 fun
: method
.to_ref(),
283 args
: vec
![fun
.to_ref(), tupled_args
.to_ref()],
286 let adt_data
= if let hir
::ExprPath(hir
::QPath
::Resolved(_
, ref path
)) = fun
.node
{
287 // Tuple-like ADTs are represented as ExprCall. We convert them here.
288 expr_ty
.ty_adt_def().and_then(|adt_def
| {
290 Def
::VariantCtor(variant_id
, CtorKind
::Fn
) => {
291 Some((adt_def
, adt_def
.variant_index_with_id(variant_id
)))
293 Def
::StructCtor(_
, CtorKind
::Fn
) => Some((adt_def
, 0)),
300 if let Some((adt_def
, index
)) = adt_data
{
301 let substs
= cx
.tables().node_id_item_substs(fun
.id
)
302 .unwrap_or_else(|| cx
.tcx
.intern_substs(&[]));
303 let field_refs
= args
.iter()
307 name
: Field
::new(idx
),
315 variant_index
: index
,
321 ty
: cx
.tables().node_id_to_type(fun
.id
),
329 hir
::ExprAddrOf(mutbl
, ref expr
) => {
330 let region
= match expr_ty
.sty
{
331 ty
::TyRef(r
, _
) => r
,
332 _
=> span_bug
!(expr
.span
, "type of & not region"),
336 borrow_kind
: to_borrow_kind(mutbl
),
341 hir
::ExprBlock(ref blk
) => ExprKind
::Block { body: &blk }
,
343 hir
::ExprAssign(ref lhs
, ref rhs
) => {
350 hir
::ExprAssignOp(op
, ref lhs
, ref rhs
) => {
351 if cx
.tables().is_method_call(expr
.id
) {
352 let pass_args
= if op
.node
.is_by_value() {
357 overloaded_operator(cx
,
359 ty
::MethodCall
::expr(expr
.id
),
372 hir
::ExprLit(..) => ExprKind
::Literal { literal: cx.const_eval_literal(expr) }
,
374 hir
::ExprBinary(op
, ref lhs
, ref rhs
) => {
375 if cx
.tables().is_method_call(expr
.id
) {
376 let pass_args
= if op
.node
.is_by_value() {
381 overloaded_operator(cx
,
383 ty
::MethodCall
::expr(expr
.id
),
389 match (op
.node
, cx
.constness
) {
390 // FIXME(eddyb) use logical ops in constants when
391 // they can handle that kind of control-flow.
392 (hir
::BinOp_
::BiAnd
, hir
::Constness
::Const
) => {
399 (hir
::BinOp_
::BiOr
, hir
::Constness
::Const
) => {
407 (hir
::BinOp_
::BiAnd
, hir
::Constness
::NotConst
) => {
408 ExprKind
::LogicalOp
{
414 (hir
::BinOp_
::BiOr
, hir
::Constness
::NotConst
) => {
415 ExprKind
::LogicalOp
{
423 let op
= bin_op(op
.node
);
434 hir
::ExprIndex(ref lhs
, ref index
) => {
435 if cx
.tables().is_method_call(expr
.id
) {
436 overloaded_lvalue(cx
,
438 ty
::MethodCall
::expr(expr
.id
),
445 index
: index
.to_ref(),
450 hir
::ExprUnary(hir
::UnOp
::UnDeref
, ref arg
) => {
451 if cx
.tables().is_method_call(expr
.id
) {
452 overloaded_lvalue(cx
,
454 ty
::MethodCall
::expr(expr
.id
),
459 ExprKind
::Deref { arg: arg.to_ref() }
463 hir
::ExprUnary(hir
::UnOp
::UnNot
, ref arg
) => {
464 if cx
.tables().is_method_call(expr
.id
) {
465 overloaded_operator(cx
,
467 ty
::MethodCall
::expr(expr
.id
),
479 hir
::ExprUnary(hir
::UnOp
::UnNeg
, ref arg
) => {
480 if cx
.tables().is_method_call(expr
.id
) {
481 overloaded_operator(cx
,
483 ty
::MethodCall
::expr(expr
.id
),
488 // FIXME runtime-overflow
489 if let hir
::ExprLit(_
) = arg
.node
{
490 ExprKind
::Literal { literal: cx.const_eval_literal(expr) }
500 hir
::ExprStruct(ref qpath
, ref fields
, ref base
) => {
502 ty
::TyAdt(adt
, substs
) => {
503 match adt
.adt_kind() {
504 AdtKind
::Struct
| AdtKind
::Union
=> {
505 let field_refs
= field_refs(&adt
.variants
[0], fields
);
511 base
: base
.as_ref().map(|base
| {
514 field_types
: cx
.tables().fru_field_types
[&expr
.id
].clone(),
520 let def
= match *qpath
{
521 hir
::QPath
::Resolved(_
, ref path
) => path
.def
,
522 hir
::QPath
::TypeRelative(..) => Def
::Err
,
525 Def
::Variant(variant_id
) => {
526 assert
!(base
.is_none());
528 let index
= adt
.variant_index_with_id(variant_id
);
529 let field_refs
= field_refs(&adt
.variants
[index
], fields
);
532 variant_index
: index
,
539 span_bug
!(expr
.span
, "unexpected def: {:?}", def
);
547 "unexpected type for struct literal: {:?}",
553 hir
::ExprClosure(..) => {
554 let closure_ty
= cx
.tables().expr_ty(expr
);
555 let (def_id
, substs
) = match closure_ty
.sty
{
556 ty
::TyClosure(def_id
, substs
) => (def_id
, substs
),
558 span_bug
!(expr
.span
, "closure expr w/o closure type: {:?}", closure_ty
);
561 let upvars
= cx
.tcx
.with_freevars(expr
.id
, |freevars
| {
563 .zip(substs
.upvar_tys(def_id
, cx
.tcx
))
564 .map(|(fv
, ty
)| capture_freevar(cx
, expr
, fv
, ty
))
574 hir
::ExprPath(ref qpath
) => {
575 let def
= cx
.tables().qpath_def(qpath
, expr
.id
);
576 convert_path_expr(cx
, expr
, def
)
579 hir
::ExprInlineAsm(ref asm
, ref outputs
, ref inputs
) => {
580 ExprKind
::InlineAsm
{
582 outputs
: outputs
.to_ref(),
583 inputs
: inputs
.to_ref(),
587 // Now comes the rote stuff:
588 hir
::ExprRepeat(ref v
, count
) => {
589 let tcx
= cx
.tcx
.global_tcx();
590 let c
= &cx
.tcx
.hir
.body(count
).value
;
591 let count
= match ConstContext
::new(tcx
, count
).eval(c
, EvalHint
::ExprTypeChecked
) {
592 Ok(ConstVal
::Integral(ConstInt
::Usize(u
))) => u
,
593 Ok(other
) => bug
!("constant evaluation of repeat count yielded {:?}", other
),
594 Err(s
) => fatal_const_eval_err(tcx
, &s
, c
.span
, "expression")
599 count
: TypedConstVal
{
600 ty
: cx
.tcx
.types
.usize,
606 hir
::ExprRet(ref v
) => ExprKind
::Return { value: v.to_ref() }
,
607 hir
::ExprBreak(label
, ref value
) => {
609 label
: label
.map(|label
| cx
.tcx
.region_maps
.node_extent(label
.loop_id
)),
610 value
: value
.to_ref(),
613 hir
::ExprAgain(label
) => {
615 label
: label
.map(|label
| cx
.tcx
.region_maps
.node_extent(label
.loop_id
)),
618 hir
::ExprMatch(ref discr
, ref arms
, _
) => {
620 discriminant
: discr
.to_ref(),
621 arms
: arms
.iter().map(|a
| convert_arm(cx
, a
)).collect(),
624 hir
::ExprIf(ref cond
, ref then
, ref otherwise
) => {
626 condition
: cond
.to_ref(),
627 then
: block
::to_expr_ref(cx
, then
),
628 otherwise
: otherwise
.to_ref(),
631 hir
::ExprWhile(ref cond
, ref body
, _
) => {
633 condition
: Some(cond
.to_ref()),
634 body
: block
::to_expr_ref(cx
, body
),
637 hir
::ExprLoop(ref body
, _
, _
) => {
640 body
: block
::to_expr_ref(cx
, body
),
643 hir
::ExprField(ref source
, name
) => {
644 let index
= match cx
.tables().expr_ty_adjusted(source
).sty
{
645 ty
::TyAdt(adt_def
, _
) => adt_def
.variants
[0].index_of_field_named(name
.node
),
646 ref ty
=> span_bug
!(expr
.span
, "field of non-ADT: {:?}", ty
),
649 index
.unwrap_or_else(|| {
650 span_bug
!(expr
.span
, "no index found for field `{}`", name
.node
)
653 lhs
: source
.to_ref(),
654 name
: Field
::new(index
),
657 hir
::ExprTupField(ref source
, index
) => {
659 lhs
: source
.to_ref(),
660 name
: Field
::new(index
.node
as usize),
663 hir
::ExprCast(ref source
, _
) => {
664 // Check to see if this cast is a "coercion cast", where the cast is actually done
665 // using a coercion (or is a no-op).
666 if let Some(&TyCastKind
::CoercionCast
) = cx
.tables().cast_kinds
.get(&source
.id
) {
667 // Convert the lexpr to a vexpr.
668 ExprKind
::Use { source: source.to_ref() }
670 ExprKind
::Cast { source: source.to_ref() }
673 hir
::ExprType(ref source
, _
) => return source
.make_mirror(cx
),
674 hir
::ExprBox(ref value
) => {
676 value
: value
.to_ref(),
677 value_extents
: cx
.tcx
.region_maps
.node_extent(value
.id
),
680 hir
::ExprArray(ref fields
) => ExprKind
::Array { fields: fields.to_ref() }
,
681 hir
::ExprTup(ref fields
) => ExprKind
::Tuple { fields: fields.to_ref() }
,
685 temp_lifetime
: temp_lifetime
,
686 temp_lifetime_was_shrunk
: was_shrunk
,
693 fn method_callee
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>,
695 method_call
: ty
::MethodCall
)
697 let callee
= cx
.tables().method_map
[&method_call
];
698 let (temp_lifetime
, was_shrunk
) = cx
.tcx
.region_maps
.temporary_scope2(expr
.id
);
700 temp_lifetime
: temp_lifetime
,
701 temp_lifetime_was_shrunk
: was_shrunk
,
704 kind
: ExprKind
::Literal
{
705 literal
: Literal
::Item
{
706 def_id
: callee
.def_id
,
707 substs
: callee
.substs
,
713 fn to_borrow_kind(m
: hir
::Mutability
) -> BorrowKind
{
715 hir
::MutMutable
=> BorrowKind
::Mut
,
716 hir
::MutImmutable
=> BorrowKind
::Shared
,
720 fn convert_arm
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>, arm
: &'tcx hir
::Arm
) -> Arm
<'tcx
> {
722 patterns
: arm
.pats
.iter().map(|p
| Pattern
::from_hir(cx
.tcx
, cx
.tables(), p
)).collect(),
723 guard
: arm
.guard
.to_ref(),
724 body
: arm
.body
.to_ref(),
728 fn convert_path_expr
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>,
729 expr
: &'tcx hir
::Expr
,
732 let substs
= cx
.tables().node_id_item_substs(expr
.id
)
733 .unwrap_or_else(|| cx
.tcx
.intern_substs(&[]));
734 let def_id
= match def
{
735 // A regular function, constructor function or a constant.
737 Def
::Method(def_id
) |
738 Def
::StructCtor(def_id
, CtorKind
::Fn
) |
739 Def
::VariantCtor(def_id
, CtorKind
::Fn
) |
741 Def
::AssociatedConst(def_id
) => def_id
,
743 Def
::StructCtor(def_id
, CtorKind
::Const
) |
744 Def
::VariantCtor(def_id
, CtorKind
::Const
) => {
745 match cx
.tables().node_id_to_type(expr
.id
).sty
{
746 // A unit struct/variant which is used as a value.
747 // We return a completely different ExprKind here to account for this special case.
748 ty
::TyAdt(adt_def
, substs
) => {
749 return ExprKind
::Adt
{
751 variant_index
: adt_def
.variant_index_with_id(def_id
),
757 ref sty
=> bug
!("unexpected sty: {:?}", sty
),
761 Def
::Static(node_id
, _
) => return ExprKind
::StaticRef { id: node_id }
,
763 Def
::Local(..) | Def
::Upvar(..) => return convert_var(cx
, expr
, def
),
765 _
=> span_bug
!(expr
.span
, "def `{:?}` not yet implemented", def
),
768 literal
: Literal
::Item
{
775 fn convert_var
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>,
776 expr
: &'tcx hir
::Expr
,
779 let (temp_lifetime
, was_shrunk
) = cx
.tcx
.region_maps
.temporary_scope2(expr
.id
);
782 Def
::Local(def_id
) => {
783 let node_id
= cx
.tcx
.hir
.as_local_node_id(def_id
).unwrap();
784 ExprKind
::VarRef { id: node_id }
787 Def
::Upvar(def_id
, index
, closure_expr_id
) => {
788 let id_var
= cx
.tcx
.hir
.as_local_node_id(def_id
).unwrap();
789 debug
!("convert_var(upvar({:?}, {:?}, {:?}))",
793 let var_ty
= cx
.tables().node_id_to_type(id_var
);
795 let body_id
= match cx
.tcx
.hir
.find(closure_expr_id
) {
796 Some(map
::NodeExpr(expr
)) => {
798 hir
::ExprClosure(.., body
, _
) => body
.node_id
,
800 span_bug
!(expr
.span
, "closure expr is not a closure expr");
805 span_bug
!(expr
.span
, "ast-map has garbage for closure expr");
809 // FIXME free regions in closures are not right
810 let closure_ty
= cx
.tables().node_id_to_type(closure_expr_id
);
812 // FIXME we're just hard-coding the idea that the
813 // signature will be &self or &mut self and hence will
814 // have a bound region with number 0
815 let region
= ty
::Region
::ReFree(ty
::FreeRegion
{
816 scope
: cx
.tcx
.region_maps
.node_extent(body_id
),
817 bound_region
: ty
::BoundRegion
::BrAnon(0),
819 let region
= cx
.tcx
.mk_region(region
);
821 let self_expr
= match cx
.tcx
.closure_kind(cx
.tcx
.hir
.local_def_id(closure_expr_id
)) {
822 ty
::ClosureKind
::Fn
=> {
823 let ref_closure_ty
= cx
.tcx
.mk_ref(region
,
826 mutbl
: hir
::MutImmutable
,
830 temp_lifetime
: temp_lifetime
,
831 temp_lifetime_was_shrunk
: was_shrunk
,
833 kind
: ExprKind
::Deref
{
836 temp_lifetime
: temp_lifetime
,
837 temp_lifetime_was_shrunk
: was_shrunk
,
839 kind
: ExprKind
::SelfRef
,
845 ty
::ClosureKind
::FnMut
=> {
846 let ref_closure_ty
= cx
.tcx
.mk_ref(region
,
849 mutbl
: hir
::MutMutable
,
853 temp_lifetime
: temp_lifetime
,
854 temp_lifetime_was_shrunk
: was_shrunk
,
856 kind
: ExprKind
::Deref
{
859 temp_lifetime
: temp_lifetime
,
860 temp_lifetime_was_shrunk
: was_shrunk
,
862 kind
: ExprKind
::SelfRef
,
867 ty
::ClosureKind
::FnOnce
=> {
870 temp_lifetime
: temp_lifetime
,
871 temp_lifetime_was_shrunk
: was_shrunk
,
873 kind
: ExprKind
::SelfRef
,
878 // at this point we have `self.n`, which loads up the upvar
879 let field_kind
= ExprKind
::Field
{
880 lhs
: self_expr
.to_ref(),
881 name
: Field
::new(index
),
884 // ...but the upvar might be an `&T` or `&mut T` capture, at which
885 // point we need an implicit deref
886 let upvar_id
= ty
::UpvarId
{
888 closure_expr_id
: closure_expr_id
,
890 let upvar_capture
= match cx
.tables().upvar_capture(upvar_id
) {
893 span_bug
!(expr
.span
, "no upvar_capture for {:?}", upvar_id
);
896 match upvar_capture
{
897 ty
::UpvarCapture
::ByValue
=> field_kind
,
898 ty
::UpvarCapture
::ByRef(borrow
) => {
901 temp_lifetime
: temp_lifetime
,
902 temp_lifetime_was_shrunk
: was_shrunk
,
903 ty
: cx
.tcx
.mk_ref(borrow
.region
,
906 mutbl
: borrow
.kind
.to_mutbl_lossy(),
916 _
=> span_bug
!(expr
.span
, "type of & not region"),
921 fn bin_op(op
: hir
::BinOp_
) -> BinOp
{
923 hir
::BinOp_
::BiAdd
=> BinOp
::Add
,
924 hir
::BinOp_
::BiSub
=> BinOp
::Sub
,
925 hir
::BinOp_
::BiMul
=> BinOp
::Mul
,
926 hir
::BinOp_
::BiDiv
=> BinOp
::Div
,
927 hir
::BinOp_
::BiRem
=> BinOp
::Rem
,
928 hir
::BinOp_
::BiBitXor
=> BinOp
::BitXor
,
929 hir
::BinOp_
::BiBitAnd
=> BinOp
::BitAnd
,
930 hir
::BinOp_
::BiBitOr
=> BinOp
::BitOr
,
931 hir
::BinOp_
::BiShl
=> BinOp
::Shl
,
932 hir
::BinOp_
::BiShr
=> BinOp
::Shr
,
933 hir
::BinOp_
::BiEq
=> BinOp
::Eq
,
934 hir
::BinOp_
::BiLt
=> BinOp
::Lt
,
935 hir
::BinOp_
::BiLe
=> BinOp
::Le
,
936 hir
::BinOp_
::BiNe
=> BinOp
::Ne
,
937 hir
::BinOp_
::BiGe
=> BinOp
::Ge
,
938 hir
::BinOp_
::BiGt
=> BinOp
::Gt
,
939 _
=> bug
!("no equivalent for ast binop {:?}", op
),
948 fn overloaded_operator
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>,
949 expr
: &'tcx hir
::Expr
,
950 method_call
: ty
::MethodCall
,
952 receiver
: ExprRef
<'tcx
>,
953 args
: Vec
<&'tcx P
<hir
::Expr
>>)
955 // the receiver has all the adjustments that are needed, so we can
956 // just push a reference to it
957 let mut argrefs
= vec
![receiver
];
959 // the arguments, unfortunately, do not, so if this is a ByRef
960 // operator, we have to gin up the autorefs (but by value is easy)
962 PassArgs
::ByValue
=> argrefs
.extend(args
.iter().map(|arg
| arg
.to_ref())),
965 let region
= cx
.tcx
.node_scope_region(expr
.id
);
966 let (temp_lifetime
, was_shrunk
) =
967 cx
.tcx
.region_maps
.temporary_scope2(expr
.id
);
968 argrefs
.extend(args
.iter()
970 let arg_ty
= cx
.tables().expr_ty_adjusted(arg
);
971 let adjusted_ty
= cx
.tcx
.mk_ref(region
,
974 mutbl
: hir
::MutImmutable
,
977 temp_lifetime
: temp_lifetime
,
978 temp_lifetime_was_shrunk
: was_shrunk
,
981 kind
: ExprKind
::Borrow
{
983 borrow_kind
: BorrowKind
::Shared
,
992 // now create the call itself
993 let fun
= method_callee(cx
, expr
, method_call
);
1001 fn overloaded_lvalue
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>,
1002 expr
: &'tcx hir
::Expr
,
1003 method_call
: ty
::MethodCall
,
1004 pass_args
: PassArgs
,
1005 receiver
: ExprRef
<'tcx
>,
1006 args
: Vec
<&'tcx P
<hir
::Expr
>>)
1008 // For an overloaded *x or x[y] expression of type T, the method
1009 // call returns an &T and we must add the deref so that the types
1010 // line up (this is because `*x` and `x[y]` represent lvalues):
1012 // to find the type &T of the content returned by the method;
1013 let ref_ty
= cx
.tables().method_map
[&method_call
].ty
.fn_ret();
1014 let ref_ty
= cx
.tcx
.no_late_bound_regions(&ref_ty
).unwrap();
1015 // callees always have all late-bound regions fully instantiated,
1017 // construct the complete expression `foo()` for the overloaded call,
1018 // which will yield the &T type
1019 let (temp_lifetime
, was_shrunk
) = cx
.tcx
.region_maps
.temporary_scope2(expr
.id
);
1020 let ref_kind
= overloaded_operator(cx
, expr
, method_call
, pass_args
, receiver
, args
);
1021 let ref_expr
= Expr
{
1022 temp_lifetime
: temp_lifetime
,
1023 temp_lifetime_was_shrunk
: was_shrunk
,
1029 // construct and return a deref wrapper `*foo()`
1030 ExprKind
::Deref { arg: ref_expr.to_ref() }
1033 fn capture_freevar
<'a
, 'gcx
, 'tcx
>(cx
: &mut Cx
<'a
, 'gcx
, 'tcx
>,
1034 closure_expr
: &'tcx hir
::Expr
,
1035 freevar
: &hir
::Freevar
,
1036 freevar_ty
: Ty
<'tcx
>)
1038 let id_var
= cx
.tcx
.hir
.as_local_node_id(freevar
.def
.def_id()).unwrap();
1039 let upvar_id
= ty
::UpvarId
{
1041 closure_expr_id
: closure_expr
.id
,
1043 let upvar_capture
= cx
.tables().upvar_capture(upvar_id
).unwrap();
1044 let (temp_lifetime
, was_shrunk
) = cx
.tcx
.region_maps
.temporary_scope2(closure_expr
.id
);
1045 let var_ty
= cx
.tables().node_id_to_type(id_var
);
1046 let captured_var
= Expr
{
1047 temp_lifetime
: temp_lifetime
,
1048 temp_lifetime_was_shrunk
: was_shrunk
,
1050 span
: closure_expr
.span
,
1051 kind
: convert_var(cx
, closure_expr
, freevar
.def
),
1053 match upvar_capture
{
1054 ty
::UpvarCapture
::ByValue
=> captured_var
.to_ref(),
1055 ty
::UpvarCapture
::ByRef(upvar_borrow
) => {
1056 let borrow_kind
= match upvar_borrow
.kind
{
1057 ty
::BorrowKind
::ImmBorrow
=> BorrowKind
::Shared
,
1058 ty
::BorrowKind
::UniqueImmBorrow
=> BorrowKind
::Unique
,
1059 ty
::BorrowKind
::MutBorrow
=> BorrowKind
::Mut
,
1062 temp_lifetime
: temp_lifetime
,
1063 temp_lifetime_was_shrunk
: was_shrunk
,
1065 span
: closure_expr
.span
,
1066 kind
: ExprKind
::Borrow
{
1067 region
: upvar_borrow
.region
,
1068 borrow_kind
: borrow_kind
,
1069 arg
: captured_var
.to_ref(),
1076 /// Converts a list of named fields (i.e. for struct-like struct/enum ADTs) into FieldExprRef.
1077 fn field_refs
<'tcx
>(variant
: &'tcx VariantDef
,
1078 fields
: &'tcx
[hir
::Field
])
1079 -> Vec
<FieldExprRef
<'tcx
>> {
1083 name
: Field
::new(variant
.index_of_field_named(field
.name
.node
).unwrap()),
1084 expr
: field
.expr
.to_ref(),