]>
Commit | Line | Data |
---|---|---|
9fa01778 XL |
1 | use crate::hair::*; |
2 | use crate::hair::cx::Cx; | |
3 | use crate::hair::cx::block; | |
4 | use crate::hair::cx::to_ref::ToRef; | |
5 | use crate::hair::util::UserAnnotatedTyHelpers; | |
e74abb32 | 6 | use rustc_index::vec::Idx; |
48663c56 | 7 | use rustc::hir::def::{CtorOf, Res, DefKind, CtorKind}; |
60c5eb7d | 8 | use rustc::mir::interpret::{GlobalId, ErrorHandled, Scalar}; |
83c7162d | 9 | use rustc::ty::{self, AdtKind, Ty}; |
48663c56 | 10 | use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability, PointerCast}; |
532ac7d7 | 11 | use rustc::ty::subst::{InternalSubsts, SubstsRef}; |
54a0048b | 12 | use rustc::hir; |
abe05a73 | 13 | use rustc::hir::def_id::LocalDefId; |
0731742a | 14 | use rustc::mir::BorrowKind; |
0bf4aa26 | 15 | use syntax_pos::Span; |
b039eaaf SL |
16 | |
17 | impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { | |
18 | type Output = Expr<'tcx>; | |
19 | ||
dc9dc135 | 20 | fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Expr<'tcx> { |
ea8adc8c | 21 | let temp_lifetime = cx.region_scope_tree.temporary_scope(self.hir_id.local_id); |
b7449926 XL |
22 | let expr_scope = region::Scope { |
23 | id: self.hir_id.local_id, | |
24 | data: region::ScopeData::Node | |
25 | }; | |
e9174d1e | 26 | |
532ac7d7 | 27 | debug!("Expr::make_mirror(): id={}, span={:?}", self.hir_id, self.span); |
e9174d1e | 28 | |
a7813a04 | 29 | let mut expr = make_mirror_unadjusted(cx, self); |
7453a54e | 30 | |
e9174d1e | 31 | // Now apply adjustments, if any. |
7cac9316 XL |
32 | for adjustment in cx.tables().expr_adjustments(self) { |
33 | debug!("make_mirror: expr={:?} applying adjustment={:?}", | |
34 | expr, | |
35 | adjustment); | |
36 | expr = apply_adjustment(cx, self, expr, adjustment); | |
e9174d1e SL |
37 | } |
38 | ||
39 | // Next, wrap this up in the expr's scope. | |
40 | expr = Expr { | |
3b2f2976 | 41 | temp_lifetime, |
e9174d1e SL |
42 | ty: expr.ty, |
43 | span: self.span, | |
b039eaaf | 44 | kind: ExprKind::Scope { |
ea8adc8c | 45 | region_scope: expr_scope, |
b039eaaf | 46 | value: expr.to_ref(), |
532ac7d7 | 47 | lint_level: LintLevel::Explicit(self.hir_id), |
b039eaaf | 48 | }, |
e9174d1e SL |
49 | }; |
50 | ||
51 | // Finally, create a destruction scope, if any. | |
ea8adc8c XL |
52 | if let Some(region_scope) = |
53 | cx.region_scope_tree.opt_destruction_scope(self.hir_id.local_id) { | |
54 | expr = Expr { | |
55 | temp_lifetime, | |
56 | ty: expr.ty, | |
57 | span: self.span, | |
58 | kind: ExprKind::Scope { | |
59 | region_scope, | |
60 | value: expr.to_ref(), | |
61 | lint_level: LintLevel::Inherited, | |
62 | }, | |
63 | }; | |
64 | } | |
e9174d1e SL |
65 | |
66 | // OK, all done! | |
67 | expr | |
68 | } | |
69 | } | |
70 | ||
dc9dc135 XL |
71 | fn apply_adjustment<'a, 'tcx>( |
72 | cx: &mut Cx<'a, 'tcx>, | |
73 | hir_expr: &'tcx hir::Expr, | |
74 | mut expr: Expr<'tcx>, | |
75 | adjustment: &Adjustment<'tcx> | |
76 | ) -> Expr<'tcx> { | |
b7449926 | 77 | let Expr { temp_lifetime, mut span, .. } = expr; |
48663c56 XL |
78 | |
79 | // Adjust the span from the block, to the last expression of the | |
80 | // block. This is a better span when returning a mutable reference | |
81 | // with too short a lifetime. The error message will use the span | |
82 | // from the assignment to the return place, which should only point | |
83 | // at the returned value, not the entire function body. | |
84 | // | |
85 | // fn return_short_lived<'a>(x: &'a mut i32) -> &'static mut i32 { | |
86 | // x | |
87 | // // ^ error message points at this expression. | |
88 | // } | |
89 | let mut adjust_span = |expr: &mut Expr<'tcx>| { | |
90 | if let ExprKind::Block { body } = expr.kind { | |
91 | if let Some(ref last_expr) = body.expr { | |
92 | span = last_expr.span; | |
93 | expr.span = span; | |
94 | } | |
7cac9316 | 95 | } |
48663c56 XL |
96 | }; |
97 | ||
98 | let kind = match adjustment.kind { | |
99 | Adjust::Pointer(PointerCast::Unsize) => { | |
100 | adjust_span(&mut expr); | |
101 | ExprKind::Pointer { cast: PointerCast::Unsize, source: expr.to_ref() } | |
7cac9316 | 102 | } |
48663c56 XL |
103 | Adjust::Pointer(cast) => { |
104 | ExprKind::Pointer { cast, source: expr.to_ref() } | |
7cac9316 XL |
105 | } |
106 | Adjust::NeverToAny => { | |
107 | ExprKind::NeverToAny { source: expr.to_ref() } | |
108 | } | |
7cac9316 | 109 | Adjust::Deref(None) => { |
48663c56 | 110 | adjust_span(&mut expr); |
7cac9316 XL |
111 | ExprKind::Deref { arg: expr.to_ref() } |
112 | } | |
113 | Adjust::Deref(Some(deref)) => { | |
48663c56 XL |
114 | // We don't need to do call adjust_span here since |
115 | // deref coercions always start with a built-in deref. | |
0531ce1d | 116 | let call = deref.method_call(cx.tcx(), expr.ty); |
7cac9316 XL |
117 | |
118 | expr = Expr { | |
119 | temp_lifetime, | |
120 | ty: cx.tcx.mk_ref(deref.region, | |
121 | ty::TypeAndMut { | |
122 | ty: expr.ty, | |
123 | mutbl: deref.mutbl, | |
124 | }), | |
125 | span, | |
126 | kind: ExprKind::Borrow { | |
2c00a5a8 | 127 | borrow_kind: deref.mutbl.to_borrow_kind(), |
7cac9316 XL |
128 | arg: expr.to_ref(), |
129 | }, | |
130 | }; | |
131 | ||
ff7c6d11 | 132 | overloaded_place(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()]) |
7cac9316 | 133 | } |
0731742a | 134 | Adjust::Borrow(AutoBorrow::Ref(_, m)) => { |
7cac9316 | 135 | ExprKind::Borrow { |
2c00a5a8 | 136 | borrow_kind: m.to_borrow_kind(), |
7cac9316 XL |
137 | arg: expr.to_ref(), |
138 | } | |
139 | } | |
60c5eb7d XL |
140 | Adjust::Borrow(AutoBorrow::RawPtr(mutbl)) => { |
141 | raw_ref_shim(cx, expr.to_ref(), adjustment.target, mutbl, span, temp_lifetime) | |
7cac9316 | 142 | } |
7cac9316 XL |
143 | }; |
144 | ||
145 | Expr { | |
146 | temp_lifetime, | |
147 | ty: adjustment.target, | |
148 | span, | |
149 | kind, | |
150 | } | |
151 | } | |
152 | ||
dc9dc135 XL |
153 | fn make_mirror_unadjusted<'a, 'tcx>( |
154 | cx: &mut Cx<'a, 'tcx>, | |
155 | expr: &'tcx hir::Expr, | |
156 | ) -> Expr<'tcx> { | |
32a655c1 | 157 | let expr_ty = cx.tables().expr_ty(expr); |
ea8adc8c | 158 | let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); |
a7813a04 | 159 | |
e74abb32 | 160 | let kind = match expr.kind { |
a7813a04 | 161 | // Here comes the interesting stuff: |
0bf4aa26 | 162 | hir::ExprKind::MethodCall(_, method_span, ref args) => { |
a7813a04 | 163 | // Rewrite a.b(c) into UFCS form like Trait::b(a, c) |
0bf4aa26 | 164 | let expr = method_callee(cx, expr, method_span,None); |
a7813a04 XL |
165 | let args = args.iter() |
166 | .map(|e| e.to_ref()) | |
167 | .collect(); | |
168 | ExprKind::Call { | |
169 | ty: expr.ty, | |
170 | fun: expr.to_ref(), | |
3b2f2976 | 171 | args, |
0bf4aa26 | 172 | from_hir_call: true, |
a7813a04 XL |
173 | } |
174 | } | |
175 | ||
8faf50e0 | 176 | hir::ExprKind::Call(ref fun, ref args) => { |
7cac9316 | 177 | if cx.tables().is_method_call(expr) { |
a7813a04 XL |
178 | // The callee is something implementing Fn, FnMut, or FnOnce. |
179 | // Find the actual method implementation being called and | |
180 | // build the appropriate UFCS call expression with the | |
181 | // callee-object as expr parameter. | |
182 | ||
183 | // rewrite f(u, v) into FnOnce::call_once(f, (u, v)) | |
184 | ||
0bf4aa26 | 185 | let method = method_callee(cx, expr, fun.span,None); |
a7813a04 | 186 | |
7cac9316 | 187 | let arg_tys = args.iter().map(|e| cx.tables().expr_ty_adjusted(e)); |
a7813a04 | 188 | let tupled_args = Expr { |
0531ce1d | 189 | ty: cx.tcx.mk_tup(arg_tys), |
3b2f2976 | 190 | temp_lifetime, |
a7813a04 | 191 | span: expr.span, |
476ff2be | 192 | kind: ExprKind::Tuple { fields: args.iter().map(ToRef::to_ref).collect() }, |
a7813a04 XL |
193 | }; |
194 | ||
195 | ExprKind::Call { | |
196 | ty: method.ty, | |
197 | fun: method.to_ref(), | |
476ff2be | 198 | args: vec![fun.to_ref(), tupled_args.to_ref()], |
0bf4aa26 | 199 | from_hir_call: true, |
a7813a04 XL |
200 | } |
201 | } else { | |
8faf50e0 | 202 | let adt_data = if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = |
e74abb32 | 203 | fun.kind |
8faf50e0 XL |
204 | { |
205 | // Tuple-like ADTs are represented as ExprKind::Call. We convert them here. | |
476ff2be | 206 | expr_ty.ty_adt_def().and_then(|adt_def| { |
48663c56 XL |
207 | match path.res { |
208 | Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => | |
532ac7d7 | 209 | Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id))), |
48663c56 | 210 | Res::SelfCtor(..) => Some((adt_def, VariantIdx::new(0))), |
476ff2be | 211 | _ => None, |
a7813a04 XL |
212 | } |
213 | }) | |
476ff2be SL |
214 | } else { |
215 | None | |
216 | }; | |
a7813a04 | 217 | if let Some((adt_def, index)) = adt_data { |
3b2f2976 | 218 | let substs = cx.tables().node_substs(fun.hir_id); |
0731742a XL |
219 | let user_provided_types = cx.tables().user_provided_types(); |
220 | let user_ty = user_provided_types.get(fun.hir_id) | |
221 | .map(|u_ty| *u_ty) | |
222 | .map(|mut u_ty| { | |
9fa01778 | 223 | if let UserType::TypeOf(ref mut did, _) = &mut u_ty.value { |
0731742a XL |
224 | *did = adt_def.did; |
225 | } | |
226 | u_ty | |
227 | }); | |
228 | debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty); | |
b7449926 | 229 | |
476ff2be SL |
230 | let field_refs = args.iter() |
231 | .enumerate() | |
232 | .map(|(idx, e)| { | |
233 | FieldExprRef { | |
234 | name: Field::new(idx), | |
235 | expr: e.to_ref(), | |
236 | } | |
237 | }) | |
238 | .collect(); | |
a7813a04 | 239 | ExprKind::Adt { |
3b2f2976 XL |
240 | adt_def, |
241 | substs, | |
a7813a04 XL |
242 | variant_index: index, |
243 | fields: field_refs, | |
b7449926 | 244 | user_ty, |
476ff2be | 245 | base: None, |
a7813a04 XL |
246 | } |
247 | } else { | |
248 | ExprKind::Call { | |
9fa01778 | 249 | ty: cx.tables().node_type(fun.hir_id), |
a7813a04 XL |
250 | fun: fun.to_ref(), |
251 | args: args.to_ref(), | |
0bf4aa26 | 252 | from_hir_call: true, |
a7813a04 XL |
253 | } |
254 | } | |
255 | } | |
256 | } | |
257 | ||
60c5eb7d | 258 | hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, ref arg) => { |
a7813a04 | 259 | ExprKind::Borrow { |
2c00a5a8 | 260 | borrow_kind: mutbl.to_borrow_kind(), |
60c5eb7d | 261 | arg: arg.to_ref(), |
a7813a04 XL |
262 | } |
263 | } | |
264 | ||
60c5eb7d XL |
265 | hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutbl, ref arg) => { |
266 | cx.tcx.sess | |
267 | .struct_span_err( | |
268 | expr.span, | |
269 | "raw borrows are not yet implemented" | |
270 | ) | |
271 | .note("for more information, see https://github.com/rust-lang/rust/issues/64490") | |
272 | .emit(); | |
273 | ||
274 | // Lower to an approximation to avoid further errors. | |
275 | raw_ref_shim(cx, arg.to_ref(), expr_ty, mutbl, expr.span, temp_lifetime) | |
276 | } | |
277 | ||
8faf50e0 | 278 | hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: &blk }, |
a7813a04 | 279 | |
8faf50e0 | 280 | hir::ExprKind::Assign(ref lhs, ref rhs) => { |
a7813a04 XL |
281 | ExprKind::Assign { |
282 | lhs: lhs.to_ref(), | |
283 | rhs: rhs.to_ref(), | |
284 | } | |
285 | } | |
286 | ||
8faf50e0 | 287 | hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => { |
7cac9316 XL |
288 | if cx.tables().is_method_call(expr) { |
289 | overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()]) | |
a7813a04 XL |
290 | } else { |
291 | ExprKind::AssignOp { | |
292 | op: bin_op(op.node), | |
293 | lhs: lhs.to_ref(), | |
294 | rhs: rhs.to_ref(), | |
295 | } | |
296 | } | |
297 | } | |
298 | ||
8faf50e0 | 299 | hir::ExprKind::Lit(ref lit) => ExprKind::Literal { |
dc9dc135 | 300 | literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false), |
b7449926 | 301 | user_ty: None, |
0531ce1d | 302 | }, |
a7813a04 | 303 | |
8faf50e0 | 304 | hir::ExprKind::Binary(op, ref lhs, ref rhs) => { |
7cac9316 XL |
305 | if cx.tables().is_method_call(expr) { |
306 | overloaded_operator(cx, expr, vec![lhs.to_ref(), rhs.to_ref()]) | |
a7813a04 XL |
307 | } else { |
308 | // FIXME overflow | |
309 | match (op.node, cx.constness) { | |
60c5eb7d XL |
310 | // Destroy control flow if `#![feature(const_if_match)]` is not enabled. |
311 | (hir::BinOpKind::And, hir::Constness::Const) | |
312 | if !cx.tcx.features().const_if_match => | |
313 | { | |
0731742a XL |
314 | cx.control_flow_destroyed.push(( |
315 | op.span, | |
316 | "`&&` operator".into(), | |
317 | )); | |
a7813a04 XL |
318 | ExprKind::Binary { |
319 | op: BinOp::BitAnd, | |
320 | lhs: lhs.to_ref(), | |
321 | rhs: rhs.to_ref(), | |
322 | } | |
323 | } | |
60c5eb7d XL |
324 | (hir::BinOpKind::Or, hir::Constness::Const) |
325 | if !cx.tcx.features().const_if_match => | |
326 | { | |
0731742a XL |
327 | cx.control_flow_destroyed.push(( |
328 | op.span, | |
329 | "`||` operator".into(), | |
330 | )); | |
a7813a04 XL |
331 | ExprKind::Binary { |
332 | op: BinOp::BitOr, | |
333 | lhs: lhs.to_ref(), | |
334 | rhs: rhs.to_ref(), | |
335 | } | |
336 | } | |
337 | ||
60c5eb7d | 338 | (hir::BinOpKind::And, _) => { |
a7813a04 XL |
339 | ExprKind::LogicalOp { |
340 | op: LogicalOp::And, | |
341 | lhs: lhs.to_ref(), | |
342 | rhs: rhs.to_ref(), | |
343 | } | |
344 | } | |
60c5eb7d | 345 | (hir::BinOpKind::Or, _) => { |
a7813a04 XL |
346 | ExprKind::LogicalOp { |
347 | op: LogicalOp::Or, | |
348 | lhs: lhs.to_ref(), | |
349 | rhs: rhs.to_ref(), | |
350 | } | |
351 | } | |
352 | ||
353 | _ => { | |
354 | let op = bin_op(op.node); | |
355 | ExprKind::Binary { | |
3b2f2976 | 356 | op, |
a7813a04 XL |
357 | lhs: lhs.to_ref(), |
358 | rhs: rhs.to_ref(), | |
359 | } | |
360 | } | |
361 | } | |
362 | } | |
363 | } | |
364 | ||
8faf50e0 | 365 | hir::ExprKind::Index(ref lhs, ref index) => { |
7cac9316 | 366 | if cx.tables().is_method_call(expr) { |
ff7c6d11 | 367 | overloaded_place(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()]) |
a7813a04 XL |
368 | } else { |
369 | ExprKind::Index { | |
370 | lhs: lhs.to_ref(), | |
371 | index: index.to_ref(), | |
372 | } | |
373 | } | |
374 | } | |
375 | ||
8faf50e0 | 376 | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref arg) => { |
7cac9316 | 377 | if cx.tables().is_method_call(expr) { |
ff7c6d11 | 378 | overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()]) |
a7813a04 XL |
379 | } else { |
380 | ExprKind::Deref { arg: arg.to_ref() } | |
381 | } | |
382 | } | |
383 | ||
8faf50e0 | 384 | hir::ExprKind::Unary(hir::UnOp::UnNot, ref arg) => { |
7cac9316 XL |
385 | if cx.tables().is_method_call(expr) { |
386 | overloaded_operator(cx, expr, vec![arg.to_ref()]) | |
a7813a04 XL |
387 | } else { |
388 | ExprKind::Unary { | |
389 | op: UnOp::Not, | |
390 | arg: arg.to_ref(), | |
391 | } | |
392 | } | |
393 | } | |
394 | ||
8faf50e0 | 395 | hir::ExprKind::Unary(hir::UnOp::UnNeg, ref arg) => { |
7cac9316 XL |
396 | if cx.tables().is_method_call(expr) { |
397 | overloaded_operator(cx, expr, vec![arg.to_ref()]) | |
a7813a04 | 398 | } else { |
e74abb32 | 399 | if let hir::ExprKind::Lit(ref lit) = arg.kind { |
0531ce1d | 400 | ExprKind::Literal { |
dc9dc135 | 401 | literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), |
b7449926 | 402 | user_ty: None, |
0531ce1d | 403 | } |
a7813a04 XL |
404 | } else { |
405 | ExprKind::Unary { | |
406 | op: UnOp::Neg, | |
407 | arg: arg.to_ref(), | |
408 | } | |
409 | } | |
410 | } | |
411 | } | |
412 | ||
8faf50e0 | 413 | hir::ExprKind::Struct(ref qpath, ref fields, ref base) => { |
e74abb32 | 414 | match expr_ty.kind { |
b7449926 | 415 | ty::Adt(adt, substs) => { |
476ff2be SL |
416 | match adt.adt_kind() { |
417 | AdtKind::Struct | AdtKind::Union => { | |
0731742a XL |
418 | let user_provided_types = cx.tables().user_provided_types(); |
419 | let user_ty = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty); | |
420 | debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty); | |
476ff2be SL |
421 | ExprKind::Adt { |
422 | adt_def: adt, | |
a1dfa0c6 | 423 | variant_index: VariantIdx::new(0), |
3b2f2976 | 424 | substs, |
0731742a | 425 | user_ty, |
83c7162d | 426 | fields: field_refs(cx, fields), |
476ff2be SL |
427 | base: base.as_ref().map(|base| { |
428 | FruInfo { | |
429 | base: base.to_ref(), | |
3b2f2976 XL |
430 | field_types: cx.tables() |
431 | .fru_field_types()[expr.hir_id] | |
432 | .clone(), | |
476ff2be SL |
433 | } |
434 | }), | |
435 | } | |
9e0c209e | 436 | } |
476ff2be | 437 | AdtKind::Enum => { |
48663c56 XL |
438 | let res = cx.tables().qpath_res(qpath, expr.hir_id); |
439 | match res { | |
440 | Res::Def(DefKind::Variant, variant_id) => { | |
476ff2be SL |
441 | assert!(base.is_none()); |
442 | ||
443 | let index = adt.variant_index_with_id(variant_id); | |
0731742a XL |
444 | let user_provided_types = cx.tables().user_provided_types(); |
445 | let user_ty = user_provided_types.get(expr.hir_id) | |
446 | .map(|u_ty| *u_ty); | |
447 | debug!( | |
448 | "make_mirror_unadjusted: (variant) user_ty={:?}", | |
449 | user_ty | |
450 | ); | |
476ff2be SL |
451 | ExprKind::Adt { |
452 | adt_def: adt, | |
453 | variant_index: index, | |
3b2f2976 | 454 | substs, |
0731742a | 455 | user_ty, |
83c7162d | 456 | fields: field_refs(cx, fields), |
476ff2be SL |
457 | base: None, |
458 | } | |
459 | } | |
460 | _ => { | |
48663c56 | 461 | span_bug!(expr.span, "unexpected res: {:?}", res); |
9e0c209e | 462 | } |
a7813a04 | 463 | } |
a7813a04 XL |
464 | } |
465 | } | |
476ff2be | 466 | } |
a7813a04 | 467 | _ => { |
476ff2be SL |
468 | span_bug!(expr.span, |
469 | "unexpected type for struct literal: {:?}", | |
470 | expr_ty); | |
a7813a04 XL |
471 | } |
472 | } | |
473 | } | |
474 | ||
8faf50e0 | 475 | hir::ExprKind::Closure(..) => { |
32a655c1 | 476 | let closure_ty = cx.tables().expr_ty(expr); |
e74abb32 XL |
477 | let (def_id, substs, movability) = match closure_ty.kind { |
478 | ty::Closure(def_id, substs) => (def_id, | |
479 | UpvarSubsts::Closure(substs), None), | |
b7449926 | 480 | ty::Generator(def_id, substs, movability) => { |
94b46f34 XL |
481 | (def_id, UpvarSubsts::Generator(substs), Some(movability)) |
482 | } | |
a7813a04 | 483 | _ => { |
476ff2be | 484 | span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty); |
a7813a04 XL |
485 | } |
486 | }; | |
48663c56 XL |
487 | let upvars = cx.tcx.upvars(def_id).iter() |
488 | .flat_map(|upvars| upvars.iter()) | |
489 | .zip(substs.upvar_tys(def_id, cx.tcx)) | |
dc9dc135 | 490 | .map(|((&var_hir_id, _), ty)| capture_upvar(cx, expr, var_hir_id, ty)) |
48663c56 | 491 | .collect(); |
a7813a04 XL |
492 | ExprKind::Closure { |
493 | closure_id: def_id, | |
3b2f2976 XL |
494 | substs, |
495 | upvars, | |
94b46f34 | 496 | movability, |
a7813a04 XL |
497 | } |
498 | } | |
499 | ||
8faf50e0 | 500 | hir::ExprKind::Path(ref qpath) => { |
48663c56 XL |
501 | let res = cx.tables().qpath_res(qpath, expr.hir_id); |
502 | convert_path_expr(cx, expr, res) | |
a7813a04 XL |
503 | } |
504 | ||
60c5eb7d | 505 | hir::ExprKind::InlineAsm(ref asm) => { |
a7813a04 | 506 | ExprKind::InlineAsm { |
60c5eb7d XL |
507 | asm: &asm.inner, |
508 | outputs: asm.outputs_exprs.to_ref(), | |
509 | inputs: asm.inputs_exprs.to_ref(), | |
a7813a04 XL |
510 | } |
511 | } | |
512 | ||
513 | // Now comes the rote stuff: | |
8faf50e0 | 514 | hir::ExprKind::Repeat(ref v, ref count) => { |
416331ca | 515 | let def_id = cx.tcx.hir().local_def_id(count.hir_id); |
e74abb32 | 516 | let substs = InternalSubsts::identity_for_item(cx.tcx, def_id); |
0531ce1d | 517 | let instance = ty::Instance::resolve( |
e74abb32 | 518 | cx.tcx, |
0531ce1d XL |
519 | cx.param_env, |
520 | def_id, | |
521 | substs, | |
522 | ).unwrap(); | |
523 | let global_id = GlobalId { | |
524 | instance, | |
525 | promoted: None | |
526 | }; | |
94b46f34 XL |
527 | let span = cx.tcx.def_span(def_id); |
528 | let count = match cx.tcx.at(span).const_eval(cx.param_env.and(global_id)) { | |
416331ca | 529 | Ok(cv) => cv.eval_usize(cx.tcx, cx.param_env), |
a1dfa0c6 XL |
530 | Err(ErrorHandled::Reported) => 0, |
531 | Err(ErrorHandled::TooGeneric) => { | |
532 | cx.tcx.sess.span_err(span, "array lengths can't depend on generic parameters"); | |
0531ce1d XL |
533 | 0 |
534 | }, | |
32a655c1 SL |
535 | }; |
536 | ||
476ff2be SL |
537 | ExprKind::Repeat { |
538 | value: v.to_ref(), | |
3b2f2976 | 539 | count, |
a7813a04 | 540 | } |
476ff2be | 541 | } |
8faf50e0 XL |
542 | hir::ExprKind::Ret(ref v) => ExprKind::Return { value: v.to_ref() }, |
543 | hir::ExprKind::Break(dest, ref value) => { | |
cc61c64b | 544 | match dest.target_id { |
94b46f34 | 545 | Ok(target_id) => ExprKind::Break { |
b7449926 | 546 | label: region::Scope { |
532ac7d7 | 547 | id: target_id.local_id, |
b7449926 XL |
548 | data: region::ScopeData::Node |
549 | }, | |
8bb4bdeb XL |
550 | value: value.to_ref(), |
551 | }, | |
94b46f34 | 552 | Err(err) => bug!("invalid loop id for break: {}", err) |
476ff2be SL |
553 | } |
554 | } | |
8faf50e0 | 555 | hir::ExprKind::Continue(dest) => { |
cc61c64b | 556 | match dest.target_id { |
94b46f34 | 557 | Ok(loop_id) => ExprKind::Continue { |
b7449926 | 558 | label: region::Scope { |
532ac7d7 | 559 | id: loop_id.local_id, |
b7449926 XL |
560 | data: region::ScopeData::Node |
561 | }, | |
8bb4bdeb | 562 | }, |
94b46f34 | 563 | Err(err) => bug!("invalid loop id for continue: {}", err) |
476ff2be SL |
564 | } |
565 | } | |
8faf50e0 | 566 | hir::ExprKind::Match(ref discr, ref arms, _) => { |
476ff2be | 567 | ExprKind::Match { |
9fa01778 | 568 | scrutinee: discr.to_ref(), |
476ff2be SL |
569 | arms: arms.iter().map(|a| convert_arm(cx, a)).collect(), |
570 | } | |
571 | } | |
8faf50e0 | 572 | hir::ExprKind::Loop(ref body, _, _) => { |
476ff2be | 573 | ExprKind::Loop { |
476ff2be SL |
574 | body: block::to_expr_ref(cx, body), |
575 | } | |
576 | } | |
8faf50e0 | 577 | hir::ExprKind::Field(ref source, ..) => { |
476ff2be SL |
578 | ExprKind::Field { |
579 | lhs: source.to_ref(), | |
532ac7d7 | 580 | name: Field::new(cx.tcx.field_index(expr.hir_id, cx.tables)), |
476ff2be | 581 | } |
a7813a04 | 582 | } |
0bf4aa26 XL |
583 | hir::ExprKind::Cast(ref source, ref cast_ty) => { |
584 | // Check for a user-given type annotation on this `cast` | |
0731742a XL |
585 | let user_provided_types = cx.tables.user_provided_types(); |
586 | let user_ty = user_provided_types.get(cast_ty.hir_id); | |
0bf4aa26 XL |
587 | |
588 | debug!( | |
589 | "cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}", | |
590 | expr, | |
591 | cast_ty.hir_id, | |
592 | user_ty, | |
593 | ); | |
594 | ||
a7813a04 XL |
595 | // Check to see if this cast is a "coercion cast", where the cast is actually done |
596 | // using a coercion (or is a no-op). | |
532ac7d7 | 597 | let cast = if cx.tables().is_coercion_cast(source.hir_id) { |
1bb2cb6e SL |
598 | // Convert the lexpr to a vexpr. |
599 | ExprKind::Use { source: source.to_ref() } | |
60c5eb7d XL |
600 | } else if cx.tables().expr_ty(source).is_region_ptr() { |
601 | // Special cased so that we can type check that the element | |
602 | // type of the source matches the pointed to type of the | |
603 | // destination. | |
604 | ExprKind::Pointer { source: source.to_ref(), cast: PointerCast::ArrayToPointer } | |
a7813a04 | 605 | } else { |
0531ce1d XL |
606 | // check whether this is casting an enum variant discriminant |
607 | // to prevent cycles, we refer to the discriminant initializer | |
608 | // which is always an integer and thus doesn't need to know the | |
609 | // enum's layout (or its tag type) to compute it during const eval | |
610 | // Example: | |
611 | // enum Foo { | |
612 | // A, | |
613 | // B = A as isize + 4, | |
614 | // } | |
615 | // The correct solution would be to add symbolic computations to miri, | |
616 | // so we wouldn't have to compute and store the actual value | |
e74abb32 | 617 | let var = if let hir::ExprKind::Path(ref qpath) = source.kind { |
48663c56 | 618 | let res = cx.tables().qpath_res(qpath, source.hir_id); |
0531ce1d XL |
619 | cx |
620 | .tables() | |
9fa01778 | 621 | .node_type(source.hir_id) |
0531ce1d XL |
622 | .ty_adt_def() |
623 | .and_then(|adt_def| { | |
48663c56 XL |
624 | match res { |
625 | Res::Def( | |
626 | DefKind::Ctor(CtorOf::Variant, CtorKind::Const), | |
627 | variant_ctor_id, | |
628 | ) => { | |
532ac7d7 | 629 | let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id); |
0531ce1d XL |
630 | let (d, o) = adt_def.discriminant_def_for_variant(idx); |
631 | use rustc::ty::util::IntTypeExt; | |
94b46f34 XL |
632 | let ty = adt_def.repr.discr_type(); |
633 | let ty = ty.to_ty(cx.tcx()); | |
0531ce1d XL |
634 | Some((d, o, ty)) |
635 | } | |
636 | _ => None, | |
637 | } | |
638 | }) | |
639 | } else { | |
640 | None | |
641 | }; | |
0bf4aa26 XL |
642 | |
643 | let source = if let Some((did, offset, var_ty)) = var { | |
8faf50e0 | 644 | let mk_const = |literal| Expr { |
0531ce1d | 645 | temp_lifetime, |
0bf4aa26 | 646 | ty: var_ty, |
0531ce1d | 647 | span: expr.span, |
0731742a | 648 | kind: ExprKind::Literal { |
dc9dc135 | 649 | literal, |
0731742a XL |
650 | user_ty: None |
651 | }, | |
0531ce1d | 652 | }.to_ref(); |
532ac7d7 | 653 | let offset = mk_const(ty::Const::from_bits( |
94b46f34 XL |
654 | cx.tcx, |
655 | offset as u128, | |
0bf4aa26 | 656 | cx.param_env.and(var_ty), |
532ac7d7 | 657 | )); |
0531ce1d XL |
658 | match did { |
659 | Some(did) => { | |
660 | // in case we are offsetting from a computed discriminant | |
661 | // and not the beginning of discriminants (which is always `0`) | |
532ac7d7 | 662 | let substs = InternalSubsts::identity_for_item(cx.tcx(), did); |
dc9dc135 | 663 | let lhs = mk_const(cx.tcx().mk_const(ty::Const { |
60c5eb7d | 664 | val: ty::ConstKind::Unevaluated(did, substs), |
532ac7d7 | 665 | ty: var_ty, |
dc9dc135 | 666 | })); |
0531ce1d XL |
667 | let bin = ExprKind::Binary { |
668 | op: BinOp::Add, | |
669 | lhs, | |
670 | rhs: offset, | |
671 | }; | |
672 | Expr { | |
673 | temp_lifetime, | |
0bf4aa26 | 674 | ty: var_ty, |
0531ce1d XL |
675 | span: expr.span, |
676 | kind: bin, | |
677 | }.to_ref() | |
678 | }, | |
679 | None => offset, | |
680 | } | |
681 | } else { | |
682 | source.to_ref() | |
683 | }; | |
0bf4aa26 | 684 | |
0531ce1d | 685 | ExprKind::Cast { source } |
0bf4aa26 XL |
686 | }; |
687 | ||
688 | if let Some(user_ty) = user_ty { | |
689 | // NOTE: Creating a new Expr and wrapping a Cast inside of it may be | |
690 | // inefficient, revisit this when performance becomes an issue. | |
691 | let cast_expr = Expr { | |
692 | temp_lifetime, | |
693 | ty: expr_ty, | |
694 | span: expr.span, | |
695 | kind: cast, | |
696 | }; | |
0731742a | 697 | debug!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty); |
0bf4aa26 XL |
698 | |
699 | ExprKind::ValueTypeAscription { | |
700 | source: cast_expr.to_ref(), | |
0731742a | 701 | user_ty: Some(*user_ty), |
0bf4aa26 XL |
702 | } |
703 | } else { | |
704 | cast | |
705 | } | |
706 | } | |
707 | hir::ExprKind::Type(ref source, ref ty) => { | |
0731742a XL |
708 | let user_provided_types = cx.tables.user_provided_types(); |
709 | let user_ty = user_provided_types.get(ty.hir_id).map(|u_ty| *u_ty); | |
710 | debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty); | |
60c5eb7d | 711 | if source.is_syntactic_place_expr() { |
0bf4aa26 XL |
712 | ExprKind::PlaceTypeAscription { |
713 | source: source.to_ref(), | |
714 | user_ty, | |
715 | } | |
716 | } else { | |
717 | ExprKind::ValueTypeAscription { | |
718 | source: source.to_ref(), | |
719 | user_ty, | |
720 | } | |
a7813a04 XL |
721 | } |
722 | } | |
48663c56 XL |
723 | hir::ExprKind::DropTemps(ref source) => { |
724 | ExprKind::Use { source: source.to_ref() } | |
725 | } | |
8faf50e0 | 726 | hir::ExprKind::Box(ref value) => { |
a7813a04 XL |
727 | ExprKind::Box { |
728 | value: value.to_ref(), | |
476ff2be SL |
729 | } |
730 | } | |
8faf50e0 XL |
731 | hir::ExprKind::Array(ref fields) => ExprKind::Array { fields: fields.to_ref() }, |
732 | hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() }, | |
ea8adc8c | 733 | |
dc9dc135 | 734 | hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: v.to_ref() }, |
0731742a | 735 | hir::ExprKind::Err => unreachable!(), |
a7813a04 XL |
736 | }; |
737 | ||
738 | Expr { | |
3b2f2976 | 739 | temp_lifetime, |
a7813a04 XL |
740 | ty: expr_ty, |
741 | span: expr.span, | |
3b2f2976 | 742 | kind, |
a7813a04 XL |
743 | } |
744 | } | |
745 | ||
48663c56 | 746 | fn user_substs_applied_to_res( |
dc9dc135 | 747 | cx: &mut Cx<'a, 'tcx>, |
b7449926 | 748 | hir_id: hir::HirId, |
48663c56 | 749 | res: Res, |
9fa01778 | 750 | ) -> Option<ty::CanonicalUserType<'tcx>> { |
48663c56 XL |
751 | debug!("user_substs_applied_to_res: res={:?}", res); |
752 | let user_provided_type = match res { | |
b7449926 XL |
753 | // A reference to something callable -- e.g., a fn, method, or |
754 | // a tuple-struct or tuple-variant. This has the type of a | |
755 | // `Fn` but with the user-given substitutions. | |
48663c56 XL |
756 | Res::Def(DefKind::Fn, _) | |
757 | Res::Def(DefKind::Method, _) | | |
758 | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | | |
759 | Res::Def(DefKind::Const, _) | | |
dc9dc135 | 760 | Res::Def(DefKind::AssocConst, _) => |
48663c56 | 761 | cx.tables().user_provided_types().get(hir_id).map(|u_ty| *u_ty), |
b7449926 XL |
762 | |
763 | // A unit struct/variant which is used as a value (e.g., | |
764 | // `None`). This has the type of the enum/struct that defines | |
765 | // this variant -- but with the substitutions given by the | |
766 | // user. | |
48663c56 | 767 | Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => |
0bf4aa26 | 768 | cx.user_substs_applied_to_ty_of_hir_id(hir_id), |
b7449926 XL |
769 | |
770 | // `Self` is used in expression as a tuple struct constructor or an unit struct constructor | |
48663c56 | 771 | Res::SelfCtor(_) => |
0bf4aa26 XL |
772 | cx.user_substs_applied_to_ty_of_hir_id(hir_id), |
773 | ||
b7449926 | 774 | _ => |
48663c56 | 775 | bug!("user_substs_applied_to_res: unexpected res {:?} at {:?}", res, hir_id) |
0731742a | 776 | }; |
48663c56 | 777 | debug!("user_substs_applied_to_res: user_provided_type={:?}", user_provided_type); |
0731742a | 778 | user_provided_type |
b7449926 XL |
779 | } |
780 | ||
dc9dc135 XL |
781 | fn method_callee<'a, 'tcx>( |
782 | cx: &mut Cx<'a, 'tcx>, | |
b7449926 | 783 | expr: &hir::Expr, |
0bf4aa26 | 784 | span: Span, |
532ac7d7 | 785 | overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>, |
b7449926 | 786 | ) -> Expr<'tcx> { |
ea8adc8c | 787 | let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); |
b7449926 XL |
788 | let (def_id, substs, user_ty) = match overloaded_callee { |
789 | Some((def_id, substs)) => (def_id, substs, None), | |
790 | None => { | |
48663c56 | 791 | let (kind, def_id) = cx.tables().type_dependent_def(expr.hir_id) |
b7449926 XL |
792 | .unwrap_or_else(|| { |
793 | span_bug!(expr.span, "no type-dependent def for method callee") | |
794 | }); | |
48663c56 | 795 | let user_ty = user_substs_applied_to_res(cx, expr.hir_id, Res::Def(kind, def_id)); |
0731742a | 796 | debug!("method_callee: user_ty={:?}", user_ty); |
48663c56 | 797 | (def_id, cx.tables().node_substs(expr.hir_id), user_ty) |
8faf50e0 | 798 | } |
b7449926 | 799 | }; |
ea8adc8c | 800 | let ty = cx.tcx().mk_fn_def(def_id, substs); |
e9174d1e | 801 | Expr { |
3b2f2976 | 802 | temp_lifetime, |
ea8adc8c | 803 | ty, |
0bf4aa26 | 804 | span, |
e9174d1e | 805 | kind: ExprKind::Literal { |
dc9dc135 | 806 | literal: ty::Const::zero_sized(cx.tcx(), ty), |
b7449926 | 807 | user_ty, |
b039eaaf | 808 | }, |
e9174d1e SL |
809 | } |
810 | } | |
811 | ||
2c00a5a8 XL |
812 | trait ToBorrowKind { fn to_borrow_kind(&self) -> BorrowKind; } |
813 | ||
814 | impl ToBorrowKind for AutoBorrowMutability { | |
815 | fn to_borrow_kind(&self) -> BorrowKind { | |
83c7162d | 816 | use rustc::ty::adjustment::AllowTwoPhase; |
2c00a5a8 XL |
817 | match *self { |
818 | AutoBorrowMutability::Mutable { allow_two_phase_borrow } => | |
83c7162d XL |
819 | BorrowKind::Mut { allow_two_phase_borrow: match allow_two_phase_borrow { |
820 | AllowTwoPhase::Yes => true, | |
821 | AllowTwoPhase::No => false | |
822 | }}, | |
2c00a5a8 XL |
823 | AutoBorrowMutability::Immutable => |
824 | BorrowKind::Shared, | |
825 | } | |
826 | } | |
827 | } | |
828 | ||
829 | impl ToBorrowKind for hir::Mutability { | |
830 | fn to_borrow_kind(&self) -> BorrowKind { | |
831 | match *self { | |
60c5eb7d XL |
832 | hir::Mutability::Mutable => BorrowKind::Mut { allow_two_phase_borrow: false }, |
833 | hir::Mutability::Immutable => BorrowKind::Shared, | |
2c00a5a8 | 834 | } |
e9174d1e SL |
835 | } |
836 | } | |
837 | ||
e74abb32 | 838 | fn convert_arm<'tcx>(cx: &mut Cx<'_, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> { |
b039eaaf | 839 | Arm { |
e74abb32 | 840 | pattern: cx.pattern_from_hir(&arm.pat), |
b7449926 XL |
841 | guard: match arm.guard { |
842 | Some(hir::Guard::If(ref e)) => Some(Guard::If(e.to_ref())), | |
843 | _ => None, | |
844 | }, | |
b039eaaf | 845 | body: arm.body.to_ref(), |
dc9dc135 XL |
846 | lint_level: LintLevel::Explicit(arm.hir_id), |
847 | scope: region::Scope { | |
848 | id: arm.hir_id.local_id, | |
849 | data: region::ScopeData::Node | |
850 | }, | |
851 | span: arm.span, | |
b039eaaf | 852 | } |
e9174d1e SL |
853 | } |
854 | ||
dc9dc135 XL |
855 | fn convert_path_expr<'a, 'tcx>( |
856 | cx: &mut Cx<'a, 'tcx>, | |
857 | expr: &'tcx hir::Expr, | |
858 | res: Res, | |
859 | ) -> ExprKind<'tcx> { | |
3b2f2976 | 860 | let substs = cx.tables().node_substs(expr.hir_id); |
48663c56 | 861 | match res { |
c30ab7b3 | 862 | // A regular function, constructor function or a constant. |
48663c56 XL |
863 | Res::Def(DefKind::Fn, _) | |
864 | Res::Def(DefKind::Method, _) | | |
865 | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | | |
866 | Res::SelfCtor(..) => { | |
867 | let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res); | |
0731742a | 868 | debug!("convert_path_expr: user_ty={:?}", user_ty); |
b7449926 | 869 | ExprKind::Literal { |
dc9dc135 XL |
870 | literal: ty::Const::zero_sized( |
871 | cx.tcx, | |
9fa01778 | 872 | cx.tables().node_type(expr.hir_id), |
dc9dc135 | 873 | ), |
b7449926 XL |
874 | user_ty, |
875 | } | |
532ac7d7 XL |
876 | } |
877 | ||
48663c56 | 878 | Res::Def(DefKind::ConstParam, def_id) => { |
dc9dc135 XL |
879 | let hir_id = cx.tcx.hir().as_local_hir_id(def_id).unwrap(); |
880 | let item_id = cx.tcx.hir().get_parent_node(hir_id); | |
416331ca | 881 | let item_def_id = cx.tcx.hir().local_def_id(item_id); |
532ac7d7 | 882 | let generics = cx.tcx.generics_of(item_def_id); |
416331ca | 883 | let local_def_id = cx.tcx.hir().local_def_id(hir_id); |
dc9dc135 | 884 | let index = generics.param_def_id_to_index[&local_def_id]; |
e74abb32 | 885 | let name = cx.tcx.hir().name(hir_id); |
60c5eb7d | 886 | let val = ty::ConstKind::Param(ty::ParamConst::new(index, name)); |
532ac7d7 XL |
887 | ExprKind::Literal { |
888 | literal: cx.tcx.mk_const( | |
889 | ty::Const { | |
890 | val, | |
891 | ty: cx.tables().node_type(expr.hir_id), | |
892 | } | |
893 | ), | |
894 | user_ty: None, | |
895 | } | |
896 | } | |
cc61c64b | 897 | |
48663c56 | 898 | Res::Def(DefKind::Const, def_id) | |
dc9dc135 | 899 | Res::Def(DefKind::AssocConst, def_id) => { |
48663c56 | 900 | let user_ty = user_substs_applied_to_res(cx, expr.hir_id, res); |
0731742a | 901 | debug!("convert_path_expr: (const) user_ty={:?}", user_ty); |
0bf4aa26 | 902 | ExprKind::Literal { |
532ac7d7 | 903 | literal: cx.tcx.mk_const(ty::Const { |
60c5eb7d | 904 | val: ty::ConstKind::Unevaluated(def_id, substs), |
e1599b0c | 905 | ty: cx.tables().node_type(expr.hir_id), |
532ac7d7 | 906 | }), |
0bf4aa26 XL |
907 | user_ty, |
908 | } | |
cc61c64b | 909 | }, |
c30ab7b3 | 910 | |
48663c56 | 911 | Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id) => { |
0731742a XL |
912 | let user_provided_types = cx.tables.user_provided_types(); |
913 | let user_provided_type = user_provided_types.get(expr.hir_id).map(|u_ty| *u_ty); | |
914 | debug!("convert_path_expr: user_provided_type={:?}", user_provided_type); | |
532ac7d7 | 915 | let ty = cx.tables().node_type(expr.hir_id); |
e74abb32 | 916 | match ty.kind { |
c30ab7b3 SL |
917 | // A unit struct/variant which is used as a value. |
918 | // We return a completely different ExprKind here to account for this special case. | |
b7449926 | 919 | ty::Adt(adt_def, substs) => { |
cc61c64b | 920 | ExprKind::Adt { |
3b2f2976 | 921 | adt_def, |
532ac7d7 | 922 | variant_index: adt_def.variant_index_with_ctor_id(def_id), |
3b2f2976 | 923 | substs, |
0731742a | 924 | user_ty: user_provided_type, |
476ff2be SL |
925 | fields: vec![], |
926 | base: None, | |
927 | } | |
928 | } | |
532ac7d7 | 929 | _ => bug!("unexpected ty: {:?}", ty), |
c30ab7b3 SL |
930 | } |
931 | } | |
9cc50fc6 | 932 | |
60c5eb7d XL |
933 | // We encode uses of statics as a `*&STATIC` where the `&STATIC` part is |
934 | // a constant reference (or constant raw pointer for `static mut`) in MIR | |
935 | Res::Def(DefKind::Static, id) => { | |
936 | let ty = cx.tcx.static_ptr_ty(id); | |
937 | let ptr = cx.tcx.alloc_map.lock().create_static_alloc(id); | |
938 | let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); | |
939 | ExprKind::Deref { arg: Expr { | |
940 | ty, | |
941 | temp_lifetime, | |
942 | span: expr.span, | |
943 | kind: ExprKind::StaticRef { | |
944 | literal: ty::Const::from_scalar(cx.tcx, Scalar::Ptr(ptr.into()), ty), | |
945 | def_id: id, | |
946 | } | |
947 | }.to_ref() } | |
948 | }, | |
e9174d1e | 949 | |
dc9dc135 | 950 | Res::Local(var_hir_id) => convert_var(cx, expr, var_hir_id), |
e9174d1e | 951 | |
48663c56 | 952 | _ => span_bug!(expr.span, "res `{:?}` not yet implemented", res), |
e9174d1e SL |
953 | } |
954 | } | |
955 | ||
dc9dc135 XL |
956 | fn convert_var( |
957 | cx: &mut Cx<'_, 'tcx>, | |
958 | expr: &'tcx hir::Expr, | |
959 | var_hir_id: hir::HirId, | |
960 | ) -> ExprKind<'tcx> { | |
961 | let upvar_index = cx.tables().upvar_list.get(&cx.body_owner) | |
962 | .and_then(|upvars| upvars.get_full(&var_hir_id).map(|(i, _, _)| i)); | |
963 | ||
964 | debug!("convert_var({:?}): upvar_index={:?}, body_owner={:?}", | |
965 | var_hir_id, upvar_index, cx.body_owner); | |
966 | ||
ea8adc8c | 967 | let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); |
e9174d1e | 968 | |
dc9dc135 XL |
969 | match upvar_index { |
970 | None => ExprKind::VarRef { id: var_hir_id }, | |
e9174d1e | 971 | |
dc9dc135 XL |
972 | Some(upvar_index) => { |
973 | let closure_def_id = cx.body_owner; | |
974 | let upvar_id = ty::UpvarId { | |
975 | var_path: ty::UpvarPath {hir_id: var_hir_id}, | |
976 | closure_expr_id: LocalDefId::from_def_id(closure_def_id), | |
977 | }; | |
9fa01778 | 978 | let var_ty = cx.tables().node_type(var_hir_id); |
e9174d1e | 979 | |
e9174d1e | 980 | // FIXME free regions in closures are not right |
dc9dc135 XL |
981 | let closure_ty = cx.tables().node_type( |
982 | cx.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id), | |
983 | ); | |
e9174d1e SL |
984 | |
985 | // FIXME we're just hard-coding the idea that the | |
986 | // signature will be &self or &mut self and hence will | |
987 | // have a bound region with number 0 | |
7cac9316 XL |
988 | let region = ty::ReFree(ty::FreeRegion { |
989 | scope: closure_def_id, | |
b039eaaf SL |
990 | bound_region: ty::BoundRegion::BrAnon(0), |
991 | }); | |
992 | let region = cx.tcx.mk_region(region); | |
993 | ||
e74abb32 | 994 | let self_expr = if let ty::Closure(_, closure_substs) = closure_ty.kind { |
ff7c6d11 | 995 | match cx.infcx.closure_kind(closure_def_id, closure_substs).unwrap() { |
ea8adc8c XL |
996 | ty::ClosureKind::Fn => { |
997 | let ref_closure_ty = cx.tcx.mk_ref(region, | |
998 | ty::TypeAndMut { | |
999 | ty: closure_ty, | |
60c5eb7d | 1000 | mutbl: hir::Mutability::Immutable, |
ea8adc8c XL |
1001 | }); |
1002 | Expr { | |
1003 | ty: closure_ty, | |
e74abb32 | 1004 | temp_lifetime, |
ea8adc8c XL |
1005 | span: expr.span, |
1006 | kind: ExprKind::Deref { | |
1007 | arg: Expr { | |
1008 | ty: ref_closure_ty, | |
1009 | temp_lifetime, | |
1010 | span: expr.span, | |
1011 | kind: ExprKind::SelfRef, | |
1012 | } | |
1013 | .to_ref(), | |
1014 | }, | |
1015 | } | |
e9174d1e | 1016 | } |
ea8adc8c XL |
1017 | ty::ClosureKind::FnMut => { |
1018 | let ref_closure_ty = cx.tcx.mk_ref(region, | |
1019 | ty::TypeAndMut { | |
1020 | ty: closure_ty, | |
60c5eb7d | 1021 | mutbl: hir::Mutability::Mutable, |
ea8adc8c XL |
1022 | }); |
1023 | Expr { | |
1024 | ty: closure_ty, | |
1025 | temp_lifetime, | |
1026 | span: expr.span, | |
1027 | kind: ExprKind::Deref { | |
1028 | arg: Expr { | |
1029 | ty: ref_closure_ty, | |
1030 | temp_lifetime, | |
1031 | span: expr.span, | |
1032 | kind: ExprKind::SelfRef, | |
1033 | }.to_ref(), | |
1034 | }, | |
1035 | } | |
e9174d1e | 1036 | } |
ea8adc8c XL |
1037 | ty::ClosureKind::FnOnce => { |
1038 | Expr { | |
1039 | ty: closure_ty, | |
1040 | temp_lifetime, | |
1041 | span: expr.span, | |
1042 | kind: ExprKind::SelfRef, | |
1043 | } | |
e9174d1e SL |
1044 | } |
1045 | } | |
ea8adc8c XL |
1046 | } else { |
1047 | Expr { | |
1048 | ty: closure_ty, | |
1049 | temp_lifetime, | |
1050 | span: expr.span, | |
1051 | kind: ExprKind::SelfRef, | |
1052 | } | |
e9174d1e SL |
1053 | }; |
1054 | ||
1055 | // at this point we have `self.n`, which loads up the upvar | |
b039eaaf SL |
1056 | let field_kind = ExprKind::Field { |
1057 | lhs: self_expr.to_ref(), | |
dc9dc135 | 1058 | name: Field::new(upvar_index), |
b039eaaf | 1059 | }; |
e9174d1e SL |
1060 | |
1061 | // ...but the upvar might be an `&T` or `&mut T` capture, at which | |
1062 | // point we need an implicit deref | |
041b39d2 | 1063 | match cx.tables().upvar_capture(upvar_id) { |
e9174d1e | 1064 | ty::UpvarCapture::ByValue => field_kind, |
7453a54e | 1065 | ty::UpvarCapture::ByRef(borrow) => { |
e9174d1e SL |
1066 | ExprKind::Deref { |
1067 | arg: Expr { | |
3b2f2976 | 1068 | temp_lifetime, |
32a655c1 SL |
1069 | ty: cx.tcx.mk_ref(borrow.region, |
1070 | ty::TypeAndMut { | |
1071 | ty: var_ty, | |
1072 | mutbl: borrow.kind.to_mutbl_lossy(), | |
1073 | }), | |
1074 | span: expr.span, | |
1075 | kind: field_kind, | |
1076 | }.to_ref(), | |
e9174d1e SL |
1077 | } |
1078 | } | |
1079 | } | |
1080 | } | |
e9174d1e SL |
1081 | } |
1082 | } | |
1083 | ||
1084 | ||
60c5eb7d XL |
1085 | /// Fake `&raw [mut|const] expr` using a borrow and a cast until `AddressOf` |
1086 | /// exists in MIR. | |
1087 | fn raw_ref_shim<'tcx>( | |
1088 | cx: &mut Cx<'_, 'tcx>, | |
1089 | arg: ExprRef<'tcx>, | |
1090 | ty: Ty<'tcx>, | |
1091 | mutbl: hir::Mutability, | |
1092 | span: Span, | |
1093 | temp_lifetime: Option<region::Scope>, | |
1094 | ) -> ExprKind<'tcx> { | |
1095 | let arg_tm = if let ty::RawPtr(type_mutbl) = ty.kind { | |
1096 | type_mutbl | |
1097 | } else { | |
1098 | bug!("raw_ref_shim called with non-raw pointer type"); | |
1099 | }; | |
1100 | // Convert this to a suitable `&foo` and | |
1101 | // then an unsafe coercion. | |
1102 | let borrow_expr = Expr { | |
1103 | temp_lifetime, | |
1104 | ty: cx.tcx.mk_ref(cx.tcx.lifetimes.re_erased, arg_tm), | |
1105 | span, | |
1106 | kind: ExprKind::Borrow { | |
1107 | borrow_kind: mutbl.to_borrow_kind(), | |
1108 | arg, | |
1109 | }, | |
1110 | }; | |
1111 | let cast_expr = Expr { | |
1112 | temp_lifetime, | |
1113 | ty, | |
1114 | span, | |
1115 | kind: ExprKind::Cast { source: borrow_expr.to_ref() } | |
1116 | }; | |
1117 | ||
1118 | // To ensure that both implicit and explicit coercions are | |
1119 | // handled the same way, we insert an extra layer of indirection here. | |
1120 | // For explicit casts (e.g., 'foo as *const T'), the source of the 'Use' | |
1121 | // will be an ExprKind::Hair with the appropriate cast expression. Here, | |
1122 | // we make our Use source the generated Cast from the original coercion. | |
1123 | // | |
1124 | // In both cases, this outer 'Use' ensures that the inner 'Cast' is handled by | |
1125 | // as_operand, not by as_rvalue - causing the cast result to be stored in a temporary. | |
1126 | // Ordinary, this is identical to using the cast directly as an rvalue. However, if the | |
1127 | // source of the cast was previously borrowed as mutable, storing the cast in a | |
1128 | // temporary gives the source a chance to expire before the cast is used. For | |
1129 | // structs with a self-referential *mut ptr, this allows assignment to work as | |
1130 | // expected. | |
1131 | // | |
1132 | // For example, consider the type 'struct Foo { field: *mut Foo }', | |
1133 | // The method 'fn bar(&mut self) { self.field = self }' | |
1134 | // triggers a coercion from '&mut self' to '*mut self'. In order | |
1135 | // for the assignment to be valid, the implicit borrow | |
1136 | // of 'self' involved in the coercion needs to end before the local | |
1137 | // containing the '*mut T' is assigned to 'self.field' - otherwise, | |
1138 | // we end up trying to assign to 'self.field' while we have another mutable borrow | |
1139 | // active. | |
1140 | // | |
1141 | // We only need to worry about this kind of thing for coercions from refs to ptrs, | |
1142 | // since they get rid of a borrow implicitly. | |
1143 | ExprKind::Use { source: cast_expr.to_ref() } | |
1144 | } | |
1145 | ||
8faf50e0 | 1146 | fn bin_op(op: hir::BinOpKind) -> BinOp { |
e9174d1e | 1147 | match op { |
8faf50e0 XL |
1148 | hir::BinOpKind::Add => BinOp::Add, |
1149 | hir::BinOpKind::Sub => BinOp::Sub, | |
1150 | hir::BinOpKind::Mul => BinOp::Mul, | |
1151 | hir::BinOpKind::Div => BinOp::Div, | |
1152 | hir::BinOpKind::Rem => BinOp::Rem, | |
1153 | hir::BinOpKind::BitXor => BinOp::BitXor, | |
1154 | hir::BinOpKind::BitAnd => BinOp::BitAnd, | |
1155 | hir::BinOpKind::BitOr => BinOp::BitOr, | |
1156 | hir::BinOpKind::Shl => BinOp::Shl, | |
1157 | hir::BinOpKind::Shr => BinOp::Shr, | |
1158 | hir::BinOpKind::Eq => BinOp::Eq, | |
1159 | hir::BinOpKind::Lt => BinOp::Lt, | |
1160 | hir::BinOpKind::Le => BinOp::Le, | |
1161 | hir::BinOpKind::Ne => BinOp::Ne, | |
1162 | hir::BinOpKind::Ge => BinOp::Ge, | |
1163 | hir::BinOpKind::Gt => BinOp::Gt, | |
54a0048b | 1164 | _ => bug!("no equivalent for ast binop {:?}", op), |
e9174d1e SL |
1165 | } |
1166 | } | |
1167 | ||
dc9dc135 XL |
1168 | fn overloaded_operator<'a, 'tcx>( |
1169 | cx: &mut Cx<'a, 'tcx>, | |
1170 | expr: &'tcx hir::Expr, | |
1171 | args: Vec<ExprRef<'tcx>> | |
1172 | ) -> ExprKind<'tcx> { | |
0bf4aa26 | 1173 | let fun = method_callee(cx, expr, expr.span, None); |
e9174d1e | 1174 | ExprKind::Call { |
9cc50fc6 | 1175 | ty: fun.ty, |
e9174d1e | 1176 | fun: fun.to_ref(), |
7cac9316 | 1177 | args, |
0bf4aa26 | 1178 | from_hir_call: false, |
e9174d1e SL |
1179 | } |
1180 | } | |
1181 | ||
dc9dc135 XL |
1182 | fn overloaded_place<'a, 'tcx>( |
1183 | cx: &mut Cx<'a, 'tcx>, | |
b7449926 XL |
1184 | expr: &'tcx hir::Expr, |
1185 | place_ty: Ty<'tcx>, | |
532ac7d7 | 1186 | overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>, |
b7449926 XL |
1187 | args: Vec<ExprRef<'tcx>>, |
1188 | ) -> ExprKind<'tcx> { | |
e9174d1e SL |
1189 | // For an overloaded *x or x[y] expression of type T, the method |
1190 | // call returns an &T and we must add the deref so that the types | |
ff7c6d11 | 1191 | // line up (this is because `*x` and `x[y]` represent places): |
e9174d1e | 1192 | |
7cac9316 XL |
1193 | let recv_ty = match args[0] { |
1194 | ExprRef::Hair(e) => cx.tables().expr_ty_adjusted(e), | |
1195 | ExprRef::Mirror(ref e) => e.ty | |
1196 | }; | |
1197 | ||
1198 | // Reconstruct the output assuming it's a reference with the | |
1199 | // same region and mutability as the receiver. This holds for | |
1200 | // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. | |
e74abb32 | 1201 | let (region, mutbl) = match recv_ty.kind { |
b7449926 | 1202 | ty::Ref(region, _, mutbl) => (region, mutbl), |
ff7c6d11 | 1203 | _ => span_bug!(expr.span, "overloaded_place: receiver is not a reference"), |
7cac9316 XL |
1204 | }; |
1205 | let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { | |
ff7c6d11 | 1206 | ty: place_ty, |
94b46f34 | 1207 | mutbl, |
7cac9316 | 1208 | }); |
e9174d1e SL |
1209 | |
1210 | // construct the complete expression `foo()` for the overloaded call, | |
1211 | // which will yield the &T type | |
ea8adc8c | 1212 | let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); |
0bf4aa26 | 1213 | let fun = method_callee(cx, expr, expr.span, overloaded_callee); |
e9174d1e | 1214 | let ref_expr = Expr { |
3b2f2976 | 1215 | temp_lifetime, |
e9174d1e SL |
1216 | ty: ref_ty, |
1217 | span: expr.span, | |
7cac9316 XL |
1218 | kind: ExprKind::Call { |
1219 | ty: fun.ty, | |
1220 | fun: fun.to_ref(), | |
1221 | args, | |
0bf4aa26 | 1222 | from_hir_call: false, |
7cac9316 | 1223 | }, |
e9174d1e SL |
1224 | }; |
1225 | ||
1226 | // construct and return a deref wrapper `*foo()` | |
1227 | ExprKind::Deref { arg: ref_expr.to_ref() } | |
1228 | } | |
1229 | ||
dc9dc135 XL |
1230 | fn capture_upvar<'tcx>( |
1231 | cx: &mut Cx<'_, 'tcx>, | |
1232 | closure_expr: &'tcx hir::Expr, | |
1233 | var_hir_id: hir::HirId, | |
1234 | upvar_ty: Ty<'tcx> | |
1235 | ) -> ExprRef<'tcx> { | |
b039eaaf | 1236 | let upvar_id = ty::UpvarId { |
a1dfa0c6 | 1237 | var_path: ty::UpvarPath { hir_id: var_hir_id }, |
416331ca | 1238 | closure_expr_id: cx.tcx.hir().local_def_id(closure_expr.hir_id).to_local(), |
b039eaaf | 1239 | }; |
041b39d2 | 1240 | let upvar_capture = cx.tables().upvar_capture(upvar_id); |
ea8adc8c | 1241 | let temp_lifetime = cx.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); |
9fa01778 | 1242 | let var_ty = cx.tables().node_type(var_hir_id); |
b039eaaf | 1243 | let captured_var = Expr { |
3b2f2976 | 1244 | temp_lifetime, |
b039eaaf SL |
1245 | ty: var_ty, |
1246 | span: closure_expr.span, | |
dc9dc135 | 1247 | kind: convert_var(cx, closure_expr, var_hir_id), |
b039eaaf | 1248 | }; |
e9174d1e | 1249 | match upvar_capture { |
476ff2be | 1250 | ty::UpvarCapture::ByValue => captured_var.to_ref(), |
e9174d1e SL |
1251 | ty::UpvarCapture::ByRef(upvar_borrow) => { |
1252 | let borrow_kind = match upvar_borrow.kind { | |
1253 | ty::BorrowKind::ImmBorrow => BorrowKind::Shared, | |
1254 | ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique, | |
2c00a5a8 | 1255 | ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false } |
e9174d1e SL |
1256 | }; |
1257 | Expr { | |
3b2f2976 | 1258 | temp_lifetime, |
48663c56 | 1259 | ty: upvar_ty, |
32a655c1 SL |
1260 | span: closure_expr.span, |
1261 | kind: ExprKind::Borrow { | |
3b2f2976 | 1262 | borrow_kind, |
32a655c1 SL |
1263 | arg: captured_var.to_ref(), |
1264 | }, | |
1265 | }.to_ref() | |
e9174d1e SL |
1266 | } |
1267 | } | |
1268 | } | |
1269 | ||
0731742a | 1270 | /// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExprRef. |
dc9dc135 XL |
1271 | fn field_refs<'a, 'tcx>( |
1272 | cx: &mut Cx<'a, 'tcx>, | |
1273 | fields: &'tcx [hir::Field] | |
1274 | ) -> Vec<FieldExprRef<'tcx>> { | |
92a42be0 | 1275 | fields.iter() |
476ff2be SL |
1276 | .map(|field| { |
1277 | FieldExprRef { | |
532ac7d7 | 1278 | name: Field::new(cx.tcx.field_index(field.hir_id, cx.tables)), |
476ff2be SL |
1279 | expr: field.expr.to_ref(), |
1280 | } | |
1281 | }) | |
1282 | .collect() | |
92a42be0 | 1283 | } |