]>
Commit | Line | Data |
---|---|---|
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 | ||
11 | use hair::*; | |
e9174d1e | 12 | use rustc_data_structures::fnv::FnvHashMap; |
54a0048b | 13 | use rustc_const_math::ConstInt; |
92a42be0 SL |
14 | use hair::cx::Cx; |
15 | use hair::cx::block; | |
16 | use hair::cx::to_ref::ToRef; | |
54a0048b SL |
17 | use rustc::hir::map; |
18 | use rustc::hir::def::Def; | |
19 | use rustc::middle::const_val::ConstVal; | |
20 | use rustc_const_eval as const_eval; | |
b039eaaf | 21 | use rustc::middle::region::CodeExtent; |
54a0048b SL |
22 | use rustc::hir::pat_util; |
23 | use rustc::ty::{self, VariantDef, Ty}; | |
92a42be0 | 24 | use rustc::mir::repr::*; |
54a0048b | 25 | use rustc::hir; |
b039eaaf SL |
26 | use syntax::ptr::P; |
27 | ||
28 | impl<'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 |
590 | fn 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 | ||
610 | fn 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 |
617 | fn 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 | 636 | fn 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 |
708 | fn 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 | ||
846 | fn 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 | ||
868 | enum PassArgs { | |
869 | ByValue, | |
b039eaaf | 870 | ByRef, |
e9174d1e SL |
871 | } |
872 | ||
b039eaaf SL |
873 | fn 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 |
924 | fn 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 |
959 | fn 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 | 1000 | fn 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 |
1010 | fn 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 | } |