]> git.proxmox.com Git - rustc.git/blame - src/librustc_mir/hair/cx/expr.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_mir / hair / cx / expr.rs
CommitLineData
e9174d1e
SL
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.
4//
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.
10
11use hair::*;
e9174d1e 12use rustc_data_structures::fnv::FnvHashMap;
54a0048b 13use rustc_const_math::ConstInt;
92a42be0
SL
14use hair::cx::Cx;
15use hair::cx::block;
16use hair::cx::to_ref::ToRef;
54a0048b
SL
17use rustc::hir::map;
18use rustc::hir::def::Def;
19use rustc::middle::const_val::ConstVal;
20use rustc_const_eval as const_eval;
b039eaaf 21use rustc::middle::region::CodeExtent;
54a0048b
SL
22use rustc::hir::pat_util;
23use rustc::ty::{self, VariantDef, Ty};
92a42be0 24use rustc::mir::repr::*;
54a0048b 25use rustc::hir;
b039eaaf
SL
26use syntax::ptr::P;
27
28impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
29 type Output = Expr<'tcx>;
30
31 fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Expr<'tcx> {
e9174d1e
SL
32 debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
33
34 let expr_ty = cx.tcx.expr_ty(self); // note: no adjustments (yet)!
7453a54e
SL
35 let temp_lifetime = cx.tcx.region_maps.temporary_scope(self.id);
36 let expr_extent = cx.tcx.region_maps.node_extent(self.id);
e9174d1e
SL
37
38 let kind = match self.node {
39 // Here comes the interesting stuff:
e9174d1e
SL
40 hir::ExprMethodCall(_, _, ref args) => {
41 // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
42 let expr = method_callee(cx, self, ty::MethodCall::expr(self.id));
43 let args = args.iter()
44 .map(|e| e.to_ref())
45 .collect();
46 ExprKind::Call {
9cc50fc6 47 ty: expr.ty,
e9174d1e 48 fun: expr.to_ref(),
b039eaaf 49 args: args,
e9174d1e
SL
50 }
51 }
52
9cc50fc6
SL
53 hir::ExprCall(ref fun, ref args) => {
54 if cx.tcx.is_method_call(self.id) {
55 // The callee is something implementing Fn, FnMut, or FnOnce.
56 // Find the actual method implementation being called and
57 // build the appropriate UFCS call expression with the
58 // callee-object as self parameter.
7453a54e
SL
59
60 // rewrite f(u, v) into FnOnce::call_once(f, (u, v))
61
9cc50fc6 62 let method = method_callee(cx, self, ty::MethodCall::expr(self.id));
7453a54e
SL
63
64 let sig = match method.ty.sty {
54a0048b
SL
65 ty::TyFnDef(_, _, fn_ty) => &fn_ty.sig,
66 _ => span_bug!(self.span, "type of method is not an fn")
7453a54e
SL
67 };
68
69 let sig = cx.tcx.no_late_bound_regions(sig).unwrap_or_else(|| {
54a0048b 70 span_bug!(self.span, "method call has late-bound regions")
7453a54e
SL
71 });
72
73 assert_eq!(sig.inputs.len(), 2);
74
75 let tupled_args = Expr {
76 ty: sig.inputs[1],
77 temp_lifetime: temp_lifetime,
78 span: self.span,
79 kind: ExprKind::Tuple {
80 fields: args.iter().map(ToRef::to_ref).collect()
81 }
82 };
9cc50fc6
SL
83
84 ExprKind::Call {
85 ty: method.ty,
86 fun: method.to_ref(),
7453a54e 87 args: vec![fun.to_ref(), tupled_args.to_ref()]
9cc50fc6
SL
88 }
89 } else {
90 let adt_data = if let hir::ExprPath(..) = fun.node {
91 // Tuple-like ADTs are represented as ExprCall. We convert them here.
92 expr_ty.ty_adt_def().and_then(|adt_def|{
93 match cx.tcx.def_map.borrow()[&fun.id].full_def() {
7453a54e 94 Def::Variant(_, variant_id) => {
9cc50fc6
SL
95 Some((adt_def, adt_def.variant_index_with_id(variant_id)))
96 },
7453a54e 97 Def::Struct(..) => {
9cc50fc6
SL
98 Some((adt_def, 0))
99 },
100 _ => None
101 }
102 })
103 } else { None };
104 if let Some((adt_def, index)) = adt_data {
105 let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(fun.id).substs);
106 let field_refs = args.iter().enumerate().map(|(idx, e)| FieldExprRef {
107 name: Field::new(idx),
108 expr: e.to_ref()
109 }).collect();
110 ExprKind::Adt {
111 adt_def: adt_def,
112 substs: substs,
113 variant_index: index,
114 fields: field_refs,
115 base: None
116 }
117 } else {
118 ExprKind::Call {
119 ty: cx.tcx.node_id_to_type(fun.id),
120 fun: fun.to_ref(),
121 args: args.to_ref(),
122 }
123 }
124 }
125 }
126
e9174d1e
SL
127 hir::ExprAddrOf(mutbl, ref expr) => {
128 let region = match expr_ty.sty {
129 ty::TyRef(r, _) => r,
54a0048b 130 _ => span_bug!(expr.span, "type of & not region"),
e9174d1e 131 };
b039eaaf
SL
132 ExprKind::Borrow {
133 region: *region,
134 borrow_kind: to_borrow_kind(mutbl),
135 arg: expr.to_ref(),
136 }
e9174d1e
SL
137 }
138
139 hir::ExprBlock(ref blk) => {
7453a54e 140 ExprKind::Block { body: &blk }
e9174d1e
SL
141 }
142
143 hir::ExprAssign(ref lhs, ref rhs) => {
144 ExprKind::Assign {
145 lhs: lhs.to_ref(),
146 rhs: rhs.to_ref(),
147 }
148 }
149
150 hir::ExprAssignOp(op, ref lhs, ref rhs) => {
7453a54e 151 if cx.tcx.is_method_call(self.id) {
54a0048b 152 let pass_args = if op.node.is_by_value() {
7453a54e
SL
153 PassArgs::ByValue
154 } else {
155 PassArgs::ByRef
156 };
157 overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
158 pass_args, lhs.to_ref(), vec![rhs])
159 } else {
160 ExprKind::AssignOp {
161 op: bin_op(op.node),
162 lhs: lhs.to_ref(),
163 rhs: rhs.to_ref(),
164 }
e9174d1e
SL
165 }
166 }
167
92a42be0
SL
168 hir::ExprLit(..) => ExprKind::Literal {
169 literal: cx.const_eval_literal(self)
170 },
e9174d1e
SL
171
172 hir::ExprBinary(op, ref lhs, ref rhs) => {
173 if cx.tcx.is_method_call(self.id) {
54a0048b 174 let pass_args = if op.node.is_by_value() {
e9174d1e
SL
175 PassArgs::ByValue
176 } else {
177 PassArgs::ByRef
178 };
179 overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
180 pass_args, lhs.to_ref(), vec![rhs])
181 } else {
182 // FIXME overflow
183 match op.node {
184 hir::BinOp_::BiAnd => {
b039eaaf
SL
185 ExprKind::LogicalOp {
186 op: LogicalOp::And,
187 lhs: lhs.to_ref(),
188 rhs: rhs.to_ref(),
189 }
e9174d1e
SL
190 }
191 hir::BinOp_::BiOr => {
b039eaaf
SL
192 ExprKind::LogicalOp {
193 op: LogicalOp::Or,
194 lhs: lhs.to_ref(),
195 rhs: rhs.to_ref(),
196 }
e9174d1e
SL
197 }
198 _ => {
199 let op = bin_op(op.node);
b039eaaf
SL
200 ExprKind::Binary {
201 op: op,
202 lhs: lhs.to_ref(),
203 rhs: rhs.to_ref(),
204 }
e9174d1e
SL
205 }
206 }
207 }
208 }
209
210 hir::ExprIndex(ref lhs, ref index) => {
211 if cx.tcx.is_method_call(self.id) {
212 overloaded_lvalue(cx, self, ty::MethodCall::expr(self.id),
213 PassArgs::ByValue, lhs.to_ref(), vec![index])
214 } else {
b039eaaf
SL
215 ExprKind::Index {
216 lhs: lhs.to_ref(),
217 index: index.to_ref(),
218 }
e9174d1e
SL
219 }
220 }
221
222 hir::ExprUnary(hir::UnOp::UnDeref, ref arg) => {
223 if cx.tcx.is_method_call(self.id) {
224 overloaded_lvalue(cx, self, ty::MethodCall::expr(self.id),
225 PassArgs::ByValue, arg.to_ref(), vec![])
226 } else {
227 ExprKind::Deref { arg: arg.to_ref() }
228 }
229 }
230
54a0048b 231 hir::ExprUnary(hir::UnOp::UnNot, ref arg) => {
e9174d1e
SL
232 if cx.tcx.is_method_call(self.id) {
233 overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
234 PassArgs::ByValue, arg.to_ref(), vec![])
235 } else {
b039eaaf 236 ExprKind::Unary {
54a0048b 237 op: UnOp::Not,
b039eaaf
SL
238 arg: arg.to_ref(),
239 }
e9174d1e
SL
240 }
241 }
242
54a0048b
SL
243 hir::ExprUnary(hir::UnOp::UnNeg, ref arg) => {
244 if cx.tcx.is_method_call(self.id) {
245 overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
246 PassArgs::ByValue, arg.to_ref(), vec![])
247 } else {
248 // FIXME runtime-overflow
249 if let hir::ExprLit(_) = arg.node {
250 ExprKind::Literal {
251 literal: cx.const_eval_literal(self),
252 }
253 } else {
254 ExprKind::Unary {
255 op: UnOp::Neg,
256 arg: arg.to_ref(),
257 }
258 }
259 }
260 }
261
e9174d1e
SL
262 hir::ExprStruct(_, ref fields, ref base) => {
263 match expr_ty.sty {
264 ty::TyStruct(adt, substs) => {
92a42be0 265 let field_refs = field_refs(&adt.variants[0], fields);
e9174d1e
SL
266 ExprKind::Adt {
267 adt_def: adt,
268 variant_index: 0,
269 substs: substs,
92a42be0 270 fields: field_refs,
7453a54e
SL
271 base: base.as_ref().map(|base| {
272 FruInfo {
273 base: base.to_ref(),
274 field_types: cx.tcx.tables
275 .borrow()
276 .fru_field_types[&self.id]
277 .clone()
278 }
279 })
e9174d1e
SL
280 }
281 }
282 ty::TyEnum(adt, substs) => {
283 match cx.tcx.def_map.borrow()[&self.id].full_def() {
7453a54e 284 Def::Variant(enum_id, variant_id) => {
e9174d1e 285 debug_assert!(adt.did == enum_id);
7453a54e
SL
286 assert!(base.is_none());
287
e9174d1e 288 let index = adt.variant_index_with_id(variant_id);
92a42be0 289 let field_refs = field_refs(&adt.variants[index], fields);
e9174d1e
SL
290 ExprKind::Adt {
291 adt_def: adt,
292 variant_index: index,
293 substs: substs,
92a42be0 294 fields: field_refs,
7453a54e 295 base: None
e9174d1e
SL
296 }
297 }
298 ref def => {
54a0048b 299 span_bug!(
e9174d1e 300 self.span,
54a0048b
SL
301 "unexpected def: {:?}",
302 def);
e9174d1e
SL
303 }
304 }
305 }
306 _ => {
54a0048b 307 span_bug!(
e9174d1e 308 self.span,
54a0048b
SL
309 "unexpected type for struct literal: {:?}",
310 expr_ty);
e9174d1e
SL
311 }
312 }
313 }
314
315 hir::ExprClosure(..) => {
316 let closure_ty = cx.tcx.expr_ty(self);
317 let (def_id, substs) = match closure_ty.sty {
318 ty::TyClosure(def_id, ref substs) => (def_id, substs),
319 _ => {
54a0048b
SL
320 span_bug!(self.span,
321 "closure expr w/o closure type: {:?}",
322 closure_ty);
e9174d1e
SL
323 }
324 };
325 let upvars = cx.tcx.with_freevars(self.id, |freevars| {
326 freevars.iter()
327 .enumerate()
328 .map(|(i, fv)| capture_freevar(cx, self, fv, substs.upvar_tys[i]))
329 .collect()
330 });
331 ExprKind::Closure {
332 closure_id: def_id,
7453a54e 333 substs: &substs,
e9174d1e
SL
334 upvars: upvars,
335 }
336 }
337
e9174d1e
SL
338 hir::ExprPath(..) => {
339 convert_path_expr(cx, self)
340 }
341
54a0048b
SL
342 hir::ExprInlineAsm(ref asm, ref outputs, ref inputs) => {
343 ExprKind::InlineAsm {
344 asm: asm,
345 outputs: outputs.to_ref(),
346 inputs: inputs.to_ref()
347 }
e9174d1e
SL
348 }
349
350 // Now comes the rote stuff:
351
92a42be0
SL
352 hir::ExprRepeat(ref v, ref c) => ExprKind::Repeat {
353 value: v.to_ref(),
7453a54e 354 count: TypedConstVal {
92a42be0 355 ty: cx.tcx.expr_ty(c),
92a42be0 356 span: c.span,
54a0048b
SL
357 value: match const_eval::eval_const_expr(cx.tcx, c) {
358 ConstVal::Integral(ConstInt::Usize(u)) => u,
359 other => bug!("constant evaluation of repeat count yielded {:?}", other),
360 },
7453a54e 361 }
92a42be0 362 },
e9174d1e
SL
363 hir::ExprRet(ref v) =>
364 ExprKind::Return { value: v.to_ref() },
365 hir::ExprBreak(label) =>
366 ExprKind::Break { label: label.map(|_| loop_label(cx, self)) },
367 hir::ExprAgain(label) =>
368 ExprKind::Continue { label: label.map(|_| loop_label(cx, self)) },
369 hir::ExprMatch(ref discr, ref arms, _) =>
370 ExprKind::Match { discriminant: discr.to_ref(),
371 arms: arms.iter().map(|a| convert_arm(cx, a)).collect() },
372 hir::ExprIf(ref cond, ref then, ref otherwise) =>
373 ExprKind::If { condition: cond.to_ref(),
374 then: block::to_expr_ref(cx, then),
375 otherwise: otherwise.to_ref() },
376 hir::ExprWhile(ref cond, ref body, _) =>
377 ExprKind::Loop { condition: Some(cond.to_ref()),
378 body: block::to_expr_ref(cx, body) },
379 hir::ExprLoop(ref body, _) =>
380 ExprKind::Loop { condition: None,
381 body: block::to_expr_ref(cx, body) },
92a42be0
SL
382 hir::ExprField(ref source, name) => {
383 let index = match cx.tcx.expr_ty_adjusted(source).sty {
384 ty::TyStruct(adt_def, _) =>
385 adt_def.variants[0].index_of_field_named(name.node),
386 ref ty =>
54a0048b 387 span_bug!(
92a42be0 388 self.span,
54a0048b
SL
389 "field of non-struct: {:?}",
390 ty),
92a42be0
SL
391 };
392 let index = index.unwrap_or_else(|| {
54a0048b 393 span_bug!(
92a42be0 394 self.span,
54a0048b
SL
395 "no index found for field `{}`",
396 name.node)
92a42be0
SL
397 });
398 ExprKind::Field { lhs: source.to_ref(), name: Field::new(index) }
399 }
b039eaaf 400 hir::ExprTupField(ref source, index) =>
e9174d1e 401 ExprKind::Field { lhs: source.to_ref(),
92a42be0 402 name: Field::new(index.node as usize) },
e9174d1e
SL
403 hir::ExprCast(ref source, _) =>
404 ExprKind::Cast { source: source.to_ref() },
9cc50fc6
SL
405 hir::ExprType(ref source, _) =>
406 return source.make_mirror(cx),
b039eaaf 407 hir::ExprBox(ref value) =>
7453a54e
SL
408 ExprKind::Box {
409 value: value.to_ref(),
410 value_extents: cx.tcx.region_maps.node_extent(value.id)
411 },
e9174d1e
SL
412 hir::ExprVec(ref fields) =>
413 ExprKind::Vec { fields: fields.to_ref() },
414 hir::ExprTup(ref fields) =>
415 ExprKind::Tuple { fields: fields.to_ref() },
e9174d1e
SL
416 };
417
e9174d1e
SL
418 let mut expr = Expr {
419 temp_lifetime: temp_lifetime,
420 ty: expr_ty,
421 span: self.span,
422 kind: kind,
423 };
424
7453a54e
SL
425 debug!("make_mirror: unadjusted-expr={:?} applying adjustments={:?}",
426 expr, cx.tcx.tables.borrow().adjustments.get(&self.id));
427
e9174d1e
SL
428 // Now apply adjustments, if any.
429 match cx.tcx.tables.borrow().adjustments.get(&self.id) {
b039eaaf 430 None => {}
e9174d1e
SL
431 Some(&ty::adjustment::AdjustReifyFnPointer) => {
432 let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
433 expr = Expr {
434 temp_lifetime: temp_lifetime,
435 ty: adjusted_ty,
436 span: self.span,
437 kind: ExprKind::ReifyFnPointer { source: expr.to_ref() },
438 };
439 }
440 Some(&ty::adjustment::AdjustUnsafeFnPointer) => {
441 let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
442 expr = Expr {
443 temp_lifetime: temp_lifetime,
444 ty: adjusted_ty,
445 span: self.span,
446 kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
447 };
448 }
7453a54e
SL
449 Some(&ty::adjustment::AdjustMutToConstPointer) => {
450 let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
451 expr = Expr {
452 temp_lifetime: temp_lifetime,
453 ty: adjusted_ty,
454 span: self.span,
455 kind: ExprKind::Cast { source: expr.to_ref() },
456 };
457 }
e9174d1e
SL
458 Some(&ty::adjustment::AdjustDerefRef(ref adj)) => {
459 for i in 0..adj.autoderefs {
460 let i = i as u32;
461 let adjusted_ty =
462 expr.ty.adjust_for_autoderef(
463 cx.tcx,
464 self.id,
465 self.span,
466 i,
467 |mc| cx.tcx.tables.borrow().method_map.get(&mc).map(|m| m.ty));
7453a54e
SL
468 debug!("make_mirror: autoderef #{}, adjusted_ty={:?}", i, adjusted_ty);
469 let method_key = ty::MethodCall::autoderef(self.id, i);
470 let meth_ty =
471 cx.tcx.tables.borrow().method_map.get(&method_key).map(|m| m.ty);
472 let kind = if let Some(meth_ty) = meth_ty {
473 debug!("make_mirror: overloaded autoderef (meth_ty={:?})", meth_ty);
474
475 let ref_ty = cx.tcx.no_late_bound_regions(&meth_ty.fn_ret());
476 let (region, mutbl) = match ref_ty {
477 Some(ty::FnConverging(&ty::TyS {
478 sty: ty::TyRef(region, mt), ..
479 })) => (region, mt.mutbl),
54a0048b 480 _ => span_bug!(expr.span, "autoderef returned bad type")
7453a54e
SL
481 };
482
483 expr = Expr {
484 temp_lifetime: temp_lifetime,
485 ty: cx.tcx.mk_ref(
486 region, ty::TypeAndMut { ty: expr.ty, mutbl: mutbl }),
487 span: expr.span,
488 kind: ExprKind::Borrow {
489 region: *region,
490 borrow_kind: to_borrow_kind(mutbl),
491 arg: expr.to_ref()
492 }
493 };
494
495 overloaded_lvalue(cx, self, method_key,
496 PassArgs::ByRef, expr.to_ref(), vec![])
e9174d1e 497 } else {
7453a54e 498 debug!("make_mirror: built-in autoderef");
e9174d1e
SL
499 ExprKind::Deref { arg: expr.to_ref() }
500 };
501 expr = Expr {
502 temp_lifetime: temp_lifetime,
503 ty: adjusted_ty,
504 span: self.span,
b039eaaf 505 kind: kind,
e9174d1e
SL
506 };
507 }
508
92a42be0 509 if let Some(autoref) = adj.autoref {
e9174d1e
SL
510 let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref));
511 match autoref {
512 ty::adjustment::AutoPtr(r, m) => {
513 expr = Expr {
514 temp_lifetime: temp_lifetime,
515 ty: adjusted_ty,
516 span: self.span,
b039eaaf
SL
517 kind: ExprKind::Borrow {
518 region: *r,
519 borrow_kind: to_borrow_kind(m),
520 arg: expr.to_ref(),
521 },
e9174d1e
SL
522 };
523 }
524 ty::adjustment::AutoUnsafe(m) => {
525 // Convert this to a suitable `&foo` and
526 // then an unsafe coercion. Limit the region to be just this
527 // expression.
528 let region = ty::ReScope(expr_extent);
529 let region = cx.tcx.mk_region(region);
530 expr = Expr {
531 temp_lifetime: temp_lifetime,
532 ty: cx.tcx.mk_ref(region, ty::TypeAndMut { ty: expr.ty, mutbl: m }),
533 span: self.span,
b039eaaf
SL
534 kind: ExprKind::Borrow {
535 region: *region,
536 borrow_kind: to_borrow_kind(m),
537 arg: expr.to_ref(),
538 },
e9174d1e
SL
539 };
540 expr = Expr {
541 temp_lifetime: temp_lifetime,
542 ty: adjusted_ty,
543 span: self.span,
b039eaaf 544 kind: ExprKind::Cast { source: expr.to_ref() },
e9174d1e
SL
545 };
546 }
547 }
548 }
92a42be0
SL
549
550 if let Some(target) = adj.unsize {
551 expr = Expr {
552 temp_lifetime: temp_lifetime,
553 ty: target,
554 span: self.span,
555 kind: ExprKind::Unsize { source: expr.to_ref() },
556 };
557 }
e9174d1e
SL
558 }
559 }
560
561 // Next, wrap this up in the expr's scope.
562 expr = Expr {
563 temp_lifetime: temp_lifetime,
564 ty: expr.ty,
565 span: self.span,
b039eaaf
SL
566 kind: ExprKind::Scope {
567 extent: expr_extent,
568 value: expr.to_ref(),
569 },
e9174d1e
SL
570 };
571
572 // Finally, create a destruction scope, if any.
573 if let Some(extent) = cx.tcx.region_maps.opt_destruction_extent(self.id) {
574 expr = Expr {
575 temp_lifetime: temp_lifetime,
576 ty: expr.ty,
577 span: self.span,
b039eaaf
SL
578 kind: ExprKind::Scope {
579 extent: extent,
580 value: expr.to_ref(),
581 },
e9174d1e
SL
582 };
583 }
584
585 // OK, all done!
586 expr
587 }
588}
589
b039eaaf
SL
590fn method_callee<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
591 expr: &hir::Expr,
592 method_call: ty::MethodCall)
593 -> Expr<'tcx> {
e9174d1e
SL
594 let tables = cx.tcx.tables.borrow();
595 let callee = &tables.method_map[&method_call];
596 let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
597 Expr {
598 temp_lifetime: temp_lifetime,
599 ty: callee.ty,
600 span: expr.span,
601 kind: ExprKind::Literal {
602 literal: Literal::Item {
603 def_id: callee.def_id,
604 substs: callee.substs,
b039eaaf
SL
605 },
606 },
e9174d1e
SL
607 }
608}
609
610fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
611 match m {
612 hir::MutMutable => BorrowKind::Mut,
613 hir::MutImmutable => BorrowKind::Shared,
614 }
615}
616
92a42be0
SL
617fn convert_arm<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
618 let mut map;
619 let opt_map = if arm.pats.len() == 1 {
e9174d1e
SL
620 None
621 } else {
92a42be0
SL
622 map = FnvHashMap();
623 pat_util::pat_bindings(&cx.tcx.def_map, &arm.pats[0], |_, p_id, _, path| {
624 map.insert(path.node, p_id);
e9174d1e 625 });
92a42be0 626 Some(&map)
e9174d1e
SL
627 };
628
b039eaaf 629 Arm {
92a42be0 630 patterns: arm.pats.iter().map(|p| cx.refutable_pat(opt_map, p)).collect(),
b039eaaf
SL
631 guard: arm.guard.to_ref(),
632 body: arm.body.to_ref(),
633 }
e9174d1e
SL
634}
635
b039eaaf 636fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> ExprKind<'tcx> {
e9174d1e 637 let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs);
9cc50fc6
SL
638 // Otherwise there may be def_map borrow conflicts
639 let def = cx.tcx.def_map.borrow()[&expr.id].full_def();
54a0048b 640 let def_id = match def {
9cc50fc6 641 // A regular function.
54a0048b 642 Def::Fn(def_id) | Def::Method(def_id) => def_id,
7453a54e 643 Def::Struct(def_id) => match cx.tcx.node_id_to_type(expr.id).sty {
9cc50fc6
SL
644 // A tuple-struct constructor. Should only be reached if not called in the same
645 // expression.
54a0048b 646 ty::TyFnDef(..) => def_id,
9cc50fc6
SL
647 // A unit struct which is used as a value. We return a completely different ExprKind
648 // here to account for this special case.
649 ty::TyStruct(adt_def, substs) => return ExprKind::Adt {
650 adt_def: adt_def,
651 variant_index: 0,
652 substs: substs,
653 fields: vec![],
654 base: None
e9174d1e 655 },
54a0048b 656 ref sty => bug!("unexpected sty: {:?}", sty)
9cc50fc6 657 },
7453a54e 658 Def::Variant(enum_id, variant_id) => match cx.tcx.node_id_to_type(expr.id).sty {
9cc50fc6
SL
659 // A variant constructor. Should only be reached if not called in the same
660 // expression.
54a0048b 661 ty::TyFnDef(..) => variant_id,
9cc50fc6
SL
662 // A unit variant, similar special case to the struct case above.
663 ty::TyEnum(adt_def, substs) => {
664 debug_assert!(adt_def.did == enum_id);
665 let index = adt_def.variant_index_with_id(variant_id);
666 return ExprKind::Adt {
667 adt_def: adt_def,
668 substs: substs,
669 variant_index: index,
670 fields: vec![],
671 base: None
672 };
e9174d1e 673 },
54a0048b 674 ref sty => bug!("unexpected sty: {:?}", sty)
9cc50fc6 675 },
7453a54e
SL
676 Def::Const(def_id) |
677 Def::AssociatedConst(def_id) => {
54a0048b
SL
678 let substs = Some(cx.tcx.node_id_item_substs(expr.id).substs);
679 if let Some((e, _)) = const_eval::lookup_const_by_id(cx.tcx, def_id, substs) {
680 // FIXME ConstVal can't be yet used with adjustments, as they would be lost.
681 if !cx.tcx.tables.borrow().adjustments.contains_key(&e.id) {
682 if let Some(v) = cx.try_const_eval_literal(e) {
683 return ExprKind::Literal { literal: v };
684 }
685 }
9cc50fc6 686 }
54a0048b 687 def_id
9cc50fc6
SL
688 }
689
7453a54e 690 Def::Static(node_id, _) => return ExprKind::StaticRef {
9cc50fc6
SL
691 id: node_id,
692 },
e9174d1e 693
7453a54e
SL
694 def @ Def::Local(..) |
695 def @ Def::Upvar(..) => return convert_var(cx, expr, def),
e9174d1e
SL
696
697 def =>
54a0048b 698 span_bug!(
e9174d1e 699 expr.span,
54a0048b
SL
700 "def `{:?}` not yet implemented",
701 def),
9cc50fc6
SL
702 };
703 ExprKind::Literal {
54a0048b 704 literal: Literal::Item { def_id: def_id, substs: substs }
e9174d1e
SL
705 }
706}
707
b039eaaf
SL
708fn convert_var<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
709 expr: &'tcx hir::Expr,
7453a54e 710 def: Def)
b039eaaf 711 -> ExprKind<'tcx> {
e9174d1e
SL
712 let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
713
714 match def {
7453a54e 715 Def::Local(_, node_id) => {
e9174d1e
SL
716 ExprKind::VarRef {
717 id: node_id,
718 }
719 }
720
7453a54e 721 Def::Upvar(_, id_var, index, closure_expr_id) => {
e9174d1e
SL
722 debug!("convert_var(upvar({:?}, {:?}, {:?}))", id_var, index, closure_expr_id);
723 let var_ty = cx.tcx.node_id_to_type(id_var);
724
725 let body_id = match cx.tcx.map.find(closure_expr_id) {
726 Some(map::NodeExpr(expr)) => {
727 match expr.node {
728 hir::ExprClosure(_, _, ref body) => body.id,
729 _ => {
54a0048b 730 span_bug!(expr.span, "closure expr is not a closure expr");
e9174d1e
SL
731 }
732 }
733 }
734 _ => {
54a0048b 735 span_bug!(expr.span, "ast-map has garbage for closure expr");
e9174d1e
SL
736 }
737 };
738
739 // FIXME free regions in closures are not right
b039eaaf 740 let closure_ty = cx.tcx.node_id_to_type(closure_expr_id);
e9174d1e
SL
741
742 // FIXME we're just hard-coding the idea that the
743 // signature will be &self or &mut self and hence will
744 // have a bound region with number 0
b039eaaf
SL
745 let region = ty::Region::ReFree(ty::FreeRegion {
746 scope: cx.tcx.region_maps.node_extent(body_id),
747 bound_region: ty::BoundRegion::BrAnon(0),
748 });
749 let region = cx.tcx.mk_region(region);
750
751 let self_expr = match cx.tcx.closure_kind(cx.tcx.map.local_def_id(closure_expr_id)) {
54a0048b 752 ty::ClosureKind::Fn => {
e9174d1e
SL
753 let ref_closure_ty =
754 cx.tcx.mk_ref(region,
755 ty::TypeAndMut { ty: closure_ty,
756 mutbl: hir::MutImmutable });
757 Expr {
758 ty: closure_ty,
759 temp_lifetime: temp_lifetime,
760 span: expr.span,
761 kind: ExprKind::Deref {
762 arg: Expr {
763 ty: ref_closure_ty,
764 temp_lifetime: temp_lifetime,
765 span: expr.span,
766 kind: ExprKind::SelfRef
767 }.to_ref()
768 }
769 }
770 }
54a0048b 771 ty::ClosureKind::FnMut => {
e9174d1e
SL
772 let ref_closure_ty =
773 cx.tcx.mk_ref(region,
774 ty::TypeAndMut { ty: closure_ty,
775 mutbl: hir::MutMutable });
776 Expr {
777 ty: closure_ty,
778 temp_lifetime: temp_lifetime,
779 span: expr.span,
780 kind: ExprKind::Deref {
781 arg: Expr {
782 ty: ref_closure_ty,
783 temp_lifetime: temp_lifetime,
784 span: expr.span,
785 kind: ExprKind::SelfRef
786 }.to_ref()
787 }
788 }
789 }
54a0048b 790 ty::ClosureKind::FnOnce => {
e9174d1e
SL
791 Expr {
792 ty: closure_ty,
793 temp_lifetime: temp_lifetime,
794 span: expr.span,
b039eaaf 795 kind: ExprKind::SelfRef,
e9174d1e
SL
796 }
797 }
798 };
799
800 // at this point we have `self.n`, which loads up the upvar
b039eaaf
SL
801 let field_kind = ExprKind::Field {
802 lhs: self_expr.to_ref(),
92a42be0 803 name: Field::new(index),
b039eaaf 804 };
e9174d1e
SL
805
806 // ...but the upvar might be an `&T` or `&mut T` capture, at which
807 // point we need an implicit deref
b039eaaf
SL
808 let upvar_id = ty::UpvarId {
809 var_id: id_var,
810 closure_expr_id: closure_expr_id,
811 };
e9174d1e
SL
812 let upvar_capture = match cx.tcx.upvar_capture(upvar_id) {
813 Some(c) => c,
814 None => {
54a0048b 815 span_bug!(
e9174d1e 816 expr.span,
54a0048b
SL
817 "no upvar_capture for {:?}",
818 upvar_id);
e9174d1e
SL
819 }
820 };
821 match upvar_capture {
822 ty::UpvarCapture::ByValue => field_kind,
7453a54e 823 ty::UpvarCapture::ByRef(borrow) => {
e9174d1e
SL
824 ExprKind::Deref {
825 arg: Expr {
826 temp_lifetime: temp_lifetime,
7453a54e
SL
827 ty: cx.tcx.mk_ref(
828 cx.tcx.mk_region(borrow.region),
829 ty::TypeAndMut {
830 ty: var_ty,
831 mutbl: borrow.kind.to_mutbl_lossy()
832 }),
e9174d1e
SL
833 span: expr.span,
834 kind: field_kind,
835 }.to_ref()
836 }
837 }
838 }
839 }
840
54a0048b 841 _ => span_bug!(expr.span, "type of & not region"),
e9174d1e
SL
842 }
843}
844
845
846fn bin_op(op: hir::BinOp_) -> BinOp {
847 match op {
848 hir::BinOp_::BiAdd => BinOp::Add,
849 hir::BinOp_::BiSub => BinOp::Sub,
850 hir::BinOp_::BiMul => BinOp::Mul,
851 hir::BinOp_::BiDiv => BinOp::Div,
852 hir::BinOp_::BiRem => BinOp::Rem,
853 hir::BinOp_::BiBitXor => BinOp::BitXor,
854 hir::BinOp_::BiBitAnd => BinOp::BitAnd,
855 hir::BinOp_::BiBitOr => BinOp::BitOr,
856 hir::BinOp_::BiShl => BinOp::Shl,
857 hir::BinOp_::BiShr => BinOp::Shr,
858 hir::BinOp_::BiEq => BinOp::Eq,
859 hir::BinOp_::BiLt => BinOp::Lt,
860 hir::BinOp_::BiLe => BinOp::Le,
861 hir::BinOp_::BiNe => BinOp::Ne,
862 hir::BinOp_::BiGe => BinOp::Ge,
863 hir::BinOp_::BiGt => BinOp::Gt,
54a0048b 864 _ => bug!("no equivalent for ast binop {:?}", op),
e9174d1e
SL
865 }
866}
867
868enum PassArgs {
869 ByValue,
b039eaaf 870 ByRef,
e9174d1e
SL
871}
872
b039eaaf
SL
873fn overloaded_operator<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
874 expr: &'tcx hir::Expr,
875 method_call: ty::MethodCall,
876 pass_args: PassArgs,
877 receiver: ExprRef<'tcx>,
878 args: Vec<&'tcx P<hir::Expr>>)
879 -> ExprKind<'tcx> {
e9174d1e
SL
880 // the receiver has all the adjustments that are needed, so we can
881 // just push a reference to it
882 let mut argrefs = vec![receiver];
883
884 // the arguments, unfortunately, do not, so if this is a ByRef
885 // operator, we have to gin up the autorefs (but by value is easy)
886 match pass_args {
887 PassArgs::ByValue => {
b039eaaf 888 argrefs.extend(args.iter().map(|arg| arg.to_ref()))
e9174d1e
SL
889 }
890
891 PassArgs::ByRef => {
892 let scope = cx.tcx.region_maps.node_extent(expr.id);
893 let region = cx.tcx.mk_region(ty::ReScope(scope));
894 let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
895 argrefs.extend(
896 args.iter()
897 .map(|arg| {
898 let arg_ty = cx.tcx.expr_ty_adjusted(arg);
899 let adjusted_ty =
900 cx.tcx.mk_ref(region,
901 ty::TypeAndMut { ty: arg_ty,
902 mutbl: hir::MutImmutable });
903 Expr {
904 temp_lifetime: temp_lifetime,
905 ty: adjusted_ty,
906 span: expr.span,
907 kind: ExprKind::Borrow { region: *region,
908 borrow_kind: BorrowKind::Shared,
909 arg: arg.to_ref() }
910 }.to_ref()
911 }))
912 }
913 }
914
915 // now create the call itself
916 let fun = method_callee(cx, expr, method_call);
917 ExprKind::Call {
9cc50fc6 918 ty: fun.ty,
e9174d1e
SL
919 fun: fun.to_ref(),
920 args: argrefs,
921 }
922}
923
b039eaaf
SL
924fn overloaded_lvalue<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
925 expr: &'tcx hir::Expr,
926 method_call: ty::MethodCall,
927 pass_args: PassArgs,
928 receiver: ExprRef<'tcx>,
929 args: Vec<&'tcx P<hir::Expr>>)
930 -> ExprKind<'tcx> {
e9174d1e
SL
931 // For an overloaded *x or x[y] expression of type T, the method
932 // call returns an &T and we must add the deref so that the types
933 // line up (this is because `*x` and `x[y]` represent lvalues):
934
935 // to find the type &T of the content returned by the method;
936 let tables = cx.tcx.tables.borrow();
937 let callee = &tables.method_map[&method_call];
938 let ref_ty = callee.ty.fn_ret();
939 let ref_ty = cx.tcx.no_late_bound_regions(&ref_ty).unwrap().unwrap();
940 // 1~~~~~ 2~~~~~
941 // (1) callees always have all late-bound regions fully instantiated,
942 // (2) overloaded methods don't return `!`
943
944 // construct the complete expression `foo()` for the overloaded call,
945 // which will yield the &T type
946 let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
947 let ref_kind = overloaded_operator(cx, expr, method_call, pass_args, receiver, args);
948 let ref_expr = Expr {
949 temp_lifetime: temp_lifetime,
950 ty: ref_ty,
951 span: expr.span,
952 kind: ref_kind,
953 };
954
955 // construct and return a deref wrapper `*foo()`
956 ExprKind::Deref { arg: ref_expr.to_ref() }
957}
958
b039eaaf
SL
959fn capture_freevar<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
960 closure_expr: &'tcx hir::Expr,
54a0048b 961 freevar: &hir::Freevar,
b039eaaf
SL
962 freevar_ty: Ty<'tcx>)
963 -> ExprRef<'tcx> {
964 let id_var = freevar.def.var_id();
965 let upvar_id = ty::UpvarId {
966 var_id: id_var,
967 closure_expr_id: closure_expr.id,
968 };
e9174d1e
SL
969 let upvar_capture = cx.tcx.upvar_capture(upvar_id).unwrap();
970 let temp_lifetime = cx.tcx.region_maps.temporary_scope(closure_expr.id);
971 let var_ty = cx.tcx.node_id_to_type(id_var);
b039eaaf
SL
972 let captured_var = Expr {
973 temp_lifetime: temp_lifetime,
974 ty: var_ty,
975 span: closure_expr.span,
976 kind: convert_var(cx, closure_expr, freevar.def),
977 };
e9174d1e
SL
978 match upvar_capture {
979 ty::UpvarCapture::ByValue => {
980 captured_var.to_ref()
981 }
982 ty::UpvarCapture::ByRef(upvar_borrow) => {
983 let borrow_kind = match upvar_borrow.kind {
984 ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
985 ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique,
986 ty::BorrowKind::MutBorrow => BorrowKind::Mut,
987 };
988 Expr {
989 temp_lifetime: temp_lifetime,
990 ty: freevar_ty,
991 span: closure_expr.span,
992 kind: ExprKind::Borrow { region: upvar_borrow.region,
993 borrow_kind: borrow_kind,
994 arg: captured_var.to_ref() }
995 }.to_ref()
996 }
997 }
998}
999
b039eaaf 1000fn loop_label<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> CodeExtent {
e9174d1e 1001 match cx.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
7453a54e 1002 Some(Def::Label(loop_id)) => cx.tcx.region_maps.node_extent(loop_id),
e9174d1e 1003 d => {
54a0048b 1004 span_bug!(expr.span, "loop scope resolved to {:?}", d);
e9174d1e
SL
1005 }
1006 }
1007}
92a42be0 1008
9cc50fc6 1009/// Converts a list of named fields (i.e. for struct-like struct/enum ADTs) into FieldExprRef.
92a42be0
SL
1010fn field_refs<'tcx>(variant: VariantDef<'tcx>,
1011 fields: &'tcx [hir::Field])
1012 -> Vec<FieldExprRef<'tcx>>
1013{
1014 fields.iter()
1015 .map(|field| FieldExprRef {
1016 name: Field::new(variant.index_of_field_named(field.name.node).unwrap()),
1017 expr: field.expr.to_ref(),
1018 })
1019 .collect()
1020}