]>
Commit | Line | Data |
---|---|---|
3dfed10e XL |
1 | use crate::thir::cx::Cx; |
2 | use crate::thir::util::UserAnnotatedTyHelpers; | |
6a06907d | 3 | use rustc_data_structures::stack::ensure_sufficient_stack; |
dfeec247 XL |
4 | use rustc_hir as hir; |
5 | use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; | |
dfeec247 | 6 | use rustc_index::vec::Idx; |
6a06907d | 7 | use rustc_middle::hir::place::Place as HirPlace; |
fc512014 XL |
8 | use rustc_middle::hir::place::PlaceBase as HirPlaceBase; |
9 | use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; | |
17df50a5 | 10 | use rustc_middle::middle::region; |
17df50a5 XL |
11 | use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp}; |
12 | use rustc_middle::thir::*; | |
ba9703b0 XL |
13 | use rustc_middle::ty::adjustment::{ |
14 | Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast, | |
15 | }; | |
16 | use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; | |
17df50a5 XL |
17 | use rustc_middle::ty::{self, AdtKind, Ty, UpvarSubsts, UserType}; |
18 | use rustc_span::def_id::DefId; | |
dfeec247 | 19 | use rustc_span::Span; |
17df50a5 | 20 | use rustc_target::abi::VariantIdx; |
b039eaaf | 21 | |
17df50a5 XL |
22 | impl<'tcx> Cx<'tcx> { |
23 | crate fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId { | |
6a06907d | 24 | // `mirror_expr` is recursing very deep. Make sure the stack doesn't overflow. |
17df50a5 | 25 | ensure_sufficient_stack(|| self.mirror_expr_inner(expr)) |
6a06907d XL |
26 | } |
27 | ||
17df50a5 XL |
28 | crate fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> { |
29 | exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect() | |
6a06907d | 30 | } |
e9174d1e | 31 | |
17df50a5 | 32 | pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId { |
6a06907d XL |
33 | let temp_lifetime = self.region_scope_tree.temporary_scope(hir_expr.hir_id.local_id); |
34 | let expr_scope = | |
35 | region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node }; | |
e9174d1e | 36 | |
6a06907d XL |
37 | debug!("Expr::make_mirror(): id={}, span={:?}", hir_expr.hir_id, hir_expr.span); |
38 | ||
39 | let mut expr = self.make_mirror_unadjusted(hir_expr); | |
7453a54e | 40 | |
c295e0f8 XL |
41 | let adjustment_span = match self.adjustment_span { |
42 | Some((hir_id, span)) if hir_id == hir_expr.hir_id => Some(span), | |
43 | _ => None, | |
44 | }; | |
45 | ||
e9174d1e | 46 | // Now apply adjustments, if any. |
6a06907d | 47 | for adjustment in self.typeck_results.expr_adjustments(hir_expr) { |
dfeec247 | 48 | debug!("make_mirror: expr={:?} applying adjustment={:?}", expr, adjustment); |
c295e0f8 XL |
49 | let span = expr.span; |
50 | expr = | |
51 | self.apply_adjustment(hir_expr, expr, adjustment, adjustment_span.unwrap_or(span)); | |
e9174d1e SL |
52 | } |
53 | ||
54 | // Next, wrap this up in the expr's scope. | |
55 | expr = Expr { | |
3b2f2976 | 56 | temp_lifetime, |
e9174d1e | 57 | ty: expr.ty, |
6a06907d | 58 | span: hir_expr.span, |
b039eaaf | 59 | kind: ExprKind::Scope { |
ea8adc8c | 60 | region_scope: expr_scope, |
17df50a5 | 61 | value: self.thir.exprs.push(expr), |
6a06907d | 62 | lint_level: LintLevel::Explicit(hir_expr.hir_id), |
b039eaaf | 63 | }, |
e9174d1e SL |
64 | }; |
65 | ||
66 | // Finally, create a destruction scope, if any. | |
6a06907d XL |
67 | if let Some(region_scope) = |
68 | self.region_scope_tree.opt_destruction_scope(hir_expr.hir_id.local_id) | |
dfeec247 XL |
69 | { |
70 | expr = Expr { | |
71 | temp_lifetime, | |
72 | ty: expr.ty, | |
6a06907d | 73 | span: hir_expr.span, |
dfeec247 XL |
74 | kind: ExprKind::Scope { |
75 | region_scope, | |
17df50a5 | 76 | value: self.thir.exprs.push(expr), |
dfeec247 XL |
77 | lint_level: LintLevel::Inherited, |
78 | }, | |
79 | }; | |
80 | } | |
e9174d1e SL |
81 | |
82 | // OK, all done! | |
17df50a5 | 83 | self.thir.exprs.push(expr) |
e9174d1e | 84 | } |
e9174d1e | 85 | |
6a06907d XL |
86 | fn apply_adjustment( |
87 | &mut self, | |
88 | hir_expr: &'tcx hir::Expr<'tcx>, | |
17df50a5 | 89 | mut expr: Expr<'tcx>, |
6a06907d | 90 | adjustment: &Adjustment<'tcx>, |
c295e0f8 | 91 | mut span: Span, |
17df50a5 | 92 | ) -> Expr<'tcx> { |
c295e0f8 | 93 | let Expr { temp_lifetime, .. } = expr; |
6a06907d XL |
94 | |
95 | // Adjust the span from the block, to the last expression of the | |
96 | // block. This is a better span when returning a mutable reference | |
97 | // with too short a lifetime. The error message will use the span | |
98 | // from the assignment to the return place, which should only point | |
99 | // at the returned value, not the entire function body. | |
100 | // | |
101 | // fn return_short_lived<'a>(x: &'a mut i32) -> &'static mut i32 { | |
102 | // x | |
103 | // // ^ error message points at this expression. | |
104 | // } | |
17df50a5 | 105 | let mut adjust_span = |expr: &mut Expr<'tcx>| { |
6a06907d | 106 | if let ExprKind::Block { body } = &expr.kind { |
17df50a5 XL |
107 | if let Some(last_expr) = body.expr { |
108 | span = self.thir[last_expr].span; | |
6a06907d XL |
109 | expr.span = span; |
110 | } | |
48663c56 | 111 | } |
6a06907d | 112 | }; |
48663c56 | 113 | |
6a06907d XL |
114 | let kind = match adjustment.kind { |
115 | Adjust::Pointer(PointerCast::Unsize) => { | |
116 | adjust_span(&mut expr); | |
17df50a5 | 117 | ExprKind::Pointer { cast: PointerCast::Unsize, source: self.thir.exprs.push(expr) } |
6a06907d | 118 | } |
17df50a5 XL |
119 | Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: self.thir.exprs.push(expr) }, |
120 | Adjust::NeverToAny => ExprKind::NeverToAny { source: self.thir.exprs.push(expr) }, | |
6a06907d XL |
121 | Adjust::Deref(None) => { |
122 | adjust_span(&mut expr); | |
17df50a5 | 123 | ExprKind::Deref { arg: self.thir.exprs.push(expr) } |
6a06907d XL |
124 | } |
125 | Adjust::Deref(Some(deref)) => { | |
126 | // We don't need to do call adjust_span here since | |
127 | // deref coercions always start with a built-in deref. | |
128 | let call = deref.method_call(self.tcx(), expr.ty); | |
7cac9316 | 129 | |
6a06907d XL |
130 | expr = Expr { |
131 | temp_lifetime, | |
132 | ty: self | |
133 | .tcx | |
134 | .mk_ref(deref.region, ty::TypeAndMut { ty: expr.ty, mutbl: deref.mutbl }), | |
135 | span, | |
136 | kind: ExprKind::Borrow { | |
137 | borrow_kind: deref.mutbl.to_borrow_kind(), | |
17df50a5 | 138 | arg: self.thir.exprs.push(expr), |
6a06907d XL |
139 | }, |
140 | }; | |
7cac9316 | 141 | |
94222f64 | 142 | let expr = Box::new([self.thir.exprs.push(expr)]); |
17df50a5 XL |
143 | |
144 | self.overloaded_place(hir_expr, adjustment.target, Some(call), expr, deref.span) | |
6a06907d | 145 | } |
17df50a5 XL |
146 | Adjust::Borrow(AutoBorrow::Ref(_, m)) => ExprKind::Borrow { |
147 | borrow_kind: m.to_borrow_kind(), | |
148 | arg: self.thir.exprs.push(expr), | |
149 | }, | |
6a06907d | 150 | Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => { |
17df50a5 | 151 | ExprKind::AddressOf { mutability, arg: self.thir.exprs.push(expr) } |
6a06907d XL |
152 | } |
153 | }; | |
7cac9316 | 154 | |
6a06907d XL |
155 | Expr { temp_lifetime, ty: adjustment.target, span, kind } |
156 | } | |
7cac9316 | 157 | |
17df50a5 | 158 | fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> { |
6a06907d | 159 | let expr_ty = self.typeck_results().expr_ty(expr); |
c295e0f8 | 160 | let expr_span = expr.span; |
6a06907d | 161 | let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); |
a7813a04 | 162 | |
6a06907d XL |
163 | let kind = match expr.kind { |
164 | // Here comes the interesting stuff: | |
5099ac24 | 165 | hir::ExprKind::MethodCall(segment, ref args, fn_span) => { |
6a06907d | 166 | // Rewrite a.b(c) into UFCS form like Trait::b(a, c) |
5099ac24 | 167 | let expr = self.method_callee(expr, segment.ident.span, None); |
c295e0f8 XL |
168 | // When we apply adjustments to the receiver, use the span of |
169 | // the overall method call for better diagnostics. args[0] | |
170 | // is guaranteed to exist, since a method call always has a receiver. | |
171 | let old_adjustment_span = self.adjustment_span.replace((args[0].hir_id, expr_span)); | |
172 | tracing::info!("Using method span: {:?}", expr.span); | |
6a06907d | 173 | let args = self.mirror_exprs(args); |
c295e0f8 | 174 | self.adjustment_span = old_adjustment_span; |
6a06907d XL |
175 | ExprKind::Call { |
176 | ty: expr.ty, | |
17df50a5 | 177 | fun: self.thir.exprs.push(expr), |
6a06907d XL |
178 | args, |
179 | from_hir_call: true, | |
180 | fn_span, | |
181 | } | |
182 | } | |
a7813a04 | 183 | |
6a06907d XL |
184 | hir::ExprKind::Call(ref fun, ref args) => { |
185 | if self.typeck_results().is_method_call(expr) { | |
186 | // The callee is something implementing Fn, FnMut, or FnOnce. | |
187 | // Find the actual method implementation being called and | |
188 | // build the appropriate UFCS call expression with the | |
189 | // callee-object as expr parameter. | |
a7813a04 | 190 | |
6a06907d | 191 | // rewrite f(u, v) into FnOnce::call_once(f, (u, v)) |
a7813a04 | 192 | |
6a06907d | 193 | let method = self.method_callee(expr, fun.span, None); |
a7813a04 | 194 | |
6a06907d XL |
195 | let arg_tys = args.iter().map(|e| self.typeck_results().expr_ty_adjusted(e)); |
196 | let tupled_args = Expr { | |
197 | ty: self.tcx.mk_tup(arg_tys), | |
198 | temp_lifetime, | |
199 | span: expr.span, | |
200 | kind: ExprKind::Tuple { fields: self.mirror_exprs(args) }, | |
dfeec247 | 201 | }; |
17df50a5 | 202 | let tupled_args = self.thir.exprs.push(tupled_args); |
b7449926 | 203 | |
a7813a04 | 204 | ExprKind::Call { |
6a06907d | 205 | ty: method.ty, |
17df50a5 | 206 | fun: self.thir.exprs.push(method), |
94222f64 | 207 | args: Box::new([self.mirror_expr(fun), tupled_args]), |
0bf4aa26 | 208 | from_hir_call: true, |
f035d41b | 209 | fn_span: expr.span, |
a7813a04 | 210 | } |
6a06907d XL |
211 | } else { |
212 | let adt_data = | |
213 | if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = fun.kind { | |
214 | // Tuple-like ADTs are represented as ExprKind::Call. We convert them here. | |
215 | expr_ty.ty_adt_def().and_then(|adt_def| match path.res { | |
216 | Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_id) => { | |
217 | Some((adt_def, adt_def.variant_index_with_ctor_id(ctor_id))) | |
218 | } | |
219 | Res::SelfCtor(..) => Some((adt_def, VariantIdx::new(0))), | |
220 | _ => None, | |
221 | }) | |
222 | } else { | |
223 | None | |
224 | }; | |
225 | if let Some((adt_def, index)) = adt_data { | |
226 | let substs = self.typeck_results().node_substs(fun.hir_id); | |
227 | let user_provided_types = self.typeck_results().user_provided_types(); | |
228 | let user_ty = | |
229 | user_provided_types.get(fun.hir_id).copied().map(|mut u_ty| { | |
230 | if let UserType::TypeOf(ref mut did, _) = &mut u_ty.value { | |
231 | *did = adt_def.did; | |
232 | } | |
233 | u_ty | |
234 | }); | |
235 | debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty); | |
236 | ||
17df50a5 XL |
237 | let field_refs = args |
238 | .iter() | |
239 | .enumerate() | |
240 | .map(|(idx, e)| FieldExpr { | |
241 | name: Field::new(idx), | |
242 | expr: self.mirror_expr(e), | |
243 | }) | |
244 | .collect(); | |
136023e0 | 245 | ExprKind::Adt(Box::new(Adt { |
6a06907d XL |
246 | adt_def, |
247 | substs, | |
248 | variant_index: index, | |
249 | fields: field_refs, | |
250 | user_ty, | |
251 | base: None, | |
136023e0 | 252 | })) |
6a06907d XL |
253 | } else { |
254 | ExprKind::Call { | |
255 | ty: self.typeck_results().node_type(fun.hir_id), | |
256 | fun: self.mirror_expr(fun), | |
257 | args: self.mirror_exprs(args), | |
258 | from_hir_call: true, | |
259 | fn_span: expr.span, | |
260 | } | |
261 | } | |
a7813a04 XL |
262 | } |
263 | } | |
a7813a04 | 264 | |
6a06907d XL |
265 | hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, ref arg) => { |
266 | ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: self.mirror_expr(arg) } | |
267 | } | |
a7813a04 | 268 | |
6a06907d XL |
269 | hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutability, ref arg) => { |
270 | ExprKind::AddressOf { mutability, arg: self.mirror_expr(arg) } | |
271 | } | |
60c5eb7d | 272 | |
6a06907d | 273 | hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: self.mirror_block(blk) }, |
a7813a04 | 274 | |
6a06907d XL |
275 | hir::ExprKind::Assign(ref lhs, ref rhs, _) => { |
276 | ExprKind::Assign { lhs: self.mirror_expr(lhs), rhs: self.mirror_expr(rhs) } | |
277 | } | |
a7813a04 | 278 | |
6a06907d XL |
279 | hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => { |
280 | if self.typeck_results().is_method_call(expr) { | |
17df50a5 XL |
281 | let lhs = self.mirror_expr(lhs); |
282 | let rhs = self.mirror_expr(rhs); | |
94222f64 | 283 | self.overloaded_operator(expr, Box::new([lhs, rhs])) |
6a06907d XL |
284 | } else { |
285 | ExprKind::AssignOp { | |
286 | op: bin_op(op.node), | |
287 | lhs: self.mirror_expr(lhs), | |
288 | rhs: self.mirror_expr(rhs), | |
289 | } | |
290 | } | |
a7813a04 | 291 | } |
a7813a04 | 292 | |
6a06907d XL |
293 | hir::ExprKind::Lit(ref lit) => ExprKind::Literal { |
294 | literal: self.const_eval_literal(&lit.node, expr_ty, lit.span, false), | |
295 | user_ty: None, | |
296 | const_id: None, | |
297 | }, | |
a7813a04 | 298 | |
6a06907d XL |
299 | hir::ExprKind::Binary(op, ref lhs, ref rhs) => { |
300 | if self.typeck_results().is_method_call(expr) { | |
17df50a5 XL |
301 | let lhs = self.mirror_expr(lhs); |
302 | let rhs = self.mirror_expr(rhs); | |
94222f64 | 303 | self.overloaded_operator(expr, Box::new([lhs, rhs])) |
6a06907d XL |
304 | } else { |
305 | // FIXME overflow | |
306 | match op.node { | |
307 | hir::BinOpKind::And => ExprKind::LogicalOp { | |
308 | op: LogicalOp::And, | |
309 | lhs: self.mirror_expr(lhs), | |
310 | rhs: self.mirror_expr(rhs), | |
311 | }, | |
312 | hir::BinOpKind::Or => ExprKind::LogicalOp { | |
313 | op: LogicalOp::Or, | |
314 | lhs: self.mirror_expr(lhs), | |
315 | rhs: self.mirror_expr(rhs), | |
316 | }, | |
6a06907d XL |
317 | _ => { |
318 | let op = bin_op(op.node); | |
319 | ExprKind::Binary { | |
320 | op, | |
321 | lhs: self.mirror_expr(lhs), | |
322 | rhs: self.mirror_expr(rhs), | |
323 | } | |
324 | } | |
a7813a04 XL |
325 | } |
326 | } | |
327 | } | |
a7813a04 | 328 | |
6a06907d XL |
329 | hir::ExprKind::Index(ref lhs, ref index) => { |
330 | if self.typeck_results().is_method_call(expr) { | |
17df50a5 XL |
331 | let lhs = self.mirror_expr(lhs); |
332 | let index = self.mirror_expr(index); | |
94222f64 | 333 | self.overloaded_place(expr, expr_ty, None, Box::new([lhs, index]), expr.span) |
6a06907d XL |
334 | } else { |
335 | ExprKind::Index { lhs: self.mirror_expr(lhs), index: self.mirror_expr(index) } | |
336 | } | |
a7813a04 | 337 | } |
a7813a04 | 338 | |
6a06907d XL |
339 | hir::ExprKind::Unary(hir::UnOp::Deref, ref arg) => { |
340 | if self.typeck_results().is_method_call(expr) { | |
17df50a5 | 341 | let arg = self.mirror_expr(arg); |
94222f64 | 342 | self.overloaded_place(expr, expr_ty, None, Box::new([arg]), expr.span) |
6a06907d XL |
343 | } else { |
344 | ExprKind::Deref { arg: self.mirror_expr(arg) } | |
345 | } | |
a7813a04 | 346 | } |
a7813a04 | 347 | |
6a06907d XL |
348 | hir::ExprKind::Unary(hir::UnOp::Not, ref arg) => { |
349 | if self.typeck_results().is_method_call(expr) { | |
17df50a5 | 350 | let arg = self.mirror_expr(arg); |
94222f64 | 351 | self.overloaded_operator(expr, Box::new([arg])) |
6a06907d XL |
352 | } else { |
353 | ExprKind::Unary { op: UnOp::Not, arg: self.mirror_expr(arg) } | |
354 | } | |
a7813a04 | 355 | } |
a7813a04 | 356 | |
6a06907d XL |
357 | hir::ExprKind::Unary(hir::UnOp::Neg, ref arg) => { |
358 | if self.typeck_results().is_method_call(expr) { | |
17df50a5 | 359 | let arg = self.mirror_expr(arg); |
94222f64 | 360 | self.overloaded_operator(expr, Box::new([arg])) |
6a06907d XL |
361 | } else if let hir::ExprKind::Lit(ref lit) = arg.kind { |
362 | ExprKind::Literal { | |
363 | literal: self.const_eval_literal(&lit.node, expr_ty, lit.span, true), | |
364 | user_ty: None, | |
365 | const_id: None, | |
366 | } | |
367 | } else { | |
368 | ExprKind::Unary { op: UnOp::Neg, arg: self.mirror_expr(arg) } | |
a7813a04 XL |
369 | } |
370 | } | |
a7813a04 | 371 | |
6a06907d XL |
372 | hir::ExprKind::Struct(ref qpath, ref fields, ref base) => match expr_ty.kind() { |
373 | ty::Adt(adt, substs) => match adt.adt_kind() { | |
374 | AdtKind::Struct | AdtKind::Union => { | |
375 | let user_provided_types = self.typeck_results().user_provided_types(); | |
376 | let user_ty = user_provided_types.get(expr.hir_id).copied(); | |
377 | debug!("make_mirror_unadjusted: (struct/union) user_ty={:?}", user_ty); | |
136023e0 | 378 | ExprKind::Adt(Box::new(Adt { |
6a06907d XL |
379 | adt_def: adt, |
380 | variant_index: VariantIdx::new(0), | |
381 | substs, | |
382 | user_ty, | |
383 | fields: self.field_refs(fields), | |
384 | base: base.as_ref().map(|base| FruInfo { | |
385 | base: self.mirror_expr(base), | |
17df50a5 XL |
386 | field_types: self.typeck_results().fru_field_types()[expr.hir_id] |
387 | .iter() | |
388 | .copied() | |
389 | .collect(), | |
6a06907d | 390 | }), |
136023e0 | 391 | })) |
dfeec247 | 392 | } |
6a06907d XL |
393 | AdtKind::Enum => { |
394 | let res = self.typeck_results().qpath_res(qpath, expr.hir_id); | |
395 | match res { | |
396 | Res::Def(DefKind::Variant, variant_id) => { | |
397 | assert!(base.is_none()); | |
398 | ||
399 | let index = adt.variant_index_with_id(variant_id); | |
400 | let user_provided_types = | |
401 | self.typeck_results().user_provided_types(); | |
402 | let user_ty = user_provided_types.get(expr.hir_id).copied(); | |
403 | debug!("make_mirror_unadjusted: (variant) user_ty={:?}", user_ty); | |
136023e0 | 404 | ExprKind::Adt(Box::new(Adt { |
6a06907d XL |
405 | adt_def: adt, |
406 | variant_index: index, | |
407 | substs, | |
408 | user_ty, | |
409 | fields: self.field_refs(fields), | |
410 | base: None, | |
136023e0 | 411 | })) |
6a06907d XL |
412 | } |
413 | _ => { | |
414 | span_bug!(expr.span, "unexpected res: {:?}", res); | |
476ff2be | 415 | } |
a7813a04 XL |
416 | } |
417 | } | |
6a06907d | 418 | }, |
a7813a04 | 419 | _ => { |
6a06907d | 420 | span_bug!(expr.span, "unexpected type for struct literal: {:?}", expr_ty); |
a7813a04 | 421 | } |
6a06907d | 422 | }, |
fc512014 | 423 | |
6a06907d XL |
424 | hir::ExprKind::Closure(..) => { |
425 | let closure_ty = self.typeck_results().expr_ty(expr); | |
426 | let (def_id, substs, movability) = match *closure_ty.kind() { | |
427 | ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs), None), | |
428 | ty::Generator(def_id, substs, movability) => { | |
429 | (def_id, UpvarSubsts::Generator(substs), Some(movability)) | |
430 | } | |
431 | _ => { | |
432 | span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty); | |
433 | } | |
434 | }; | |
a7813a04 | 435 | |
17df50a5 XL |
436 | let upvars = self |
437 | .typeck_results | |
438 | .closure_min_captures_flattened(def_id) | |
439 | .zip(substs.upvar_tys()) | |
440 | .map(|(captured_place, ty)| { | |
441 | let upvars = self.capture_upvar(expr, captured_place, ty); | |
442 | self.thir.exprs.push(upvars) | |
443 | }) | |
444 | .collect(); | |
6a06907d XL |
445 | |
446 | // Convert the closure fake reads, if any, from hir `Place` to ExprRef | |
447 | let fake_reads = match self.typeck_results.closure_fake_reads.get(&def_id) { | |
448 | Some(fake_reads) => fake_reads | |
449 | .iter() | |
450 | .map(|(place, cause, hir_id)| { | |
451 | let expr = self.convert_captured_hir_place(expr, place.clone()); | |
17df50a5 | 452 | (self.thir.exprs.push(expr), *cause, *hir_id) |
6a06907d XL |
453 | }) |
454 | .collect(), | |
455 | None => Vec::new(), | |
456 | }; | |
a7813a04 | 457 | |
6a06907d XL |
458 | ExprKind::Closure { closure_id: def_id, substs, upvars, movability, fake_reads } |
459 | } | |
460 | ||
461 | hir::ExprKind::Path(ref qpath) => { | |
462 | let res = self.typeck_results().qpath_res(qpath, expr.hir_id); | |
463 | self.convert_path_expr(expr, res) | |
464 | } | |
465 | ||
466 | hir::ExprKind::InlineAsm(ref asm) => ExprKind::InlineAsm { | |
467 | template: asm.template, | |
17df50a5 XL |
468 | operands: asm |
469 | .operands | |
470 | .iter() | |
471 | .map(|(op, _op_sp)| { | |
472 | match *op { | |
473 | hir::InlineAsmOperand::In { reg, ref expr } => { | |
474 | InlineAsmOperand::In { reg, expr: self.mirror_expr(expr) } | |
475 | } | |
476 | hir::InlineAsmOperand::Out { reg, late, ref expr } => { | |
477 | InlineAsmOperand::Out { | |
478 | reg, | |
479 | late, | |
480 | expr: expr.as_ref().map(|expr| self.mirror_expr(expr)), | |
481 | } | |
482 | } | |
483 | hir::InlineAsmOperand::InOut { reg, late, ref expr } => { | |
484 | InlineAsmOperand::InOut { reg, late, expr: self.mirror_expr(expr) } | |
485 | } | |
486 | hir::InlineAsmOperand::SplitInOut { | |
f9f354fc XL |
487 | reg, |
488 | late, | |
17df50a5 XL |
489 | ref in_expr, |
490 | ref out_expr, | |
491 | } => InlineAsmOperand::SplitInOut { | |
492 | reg, | |
493 | late, | |
494 | in_expr: self.mirror_expr(in_expr), | |
495 | out_expr: out_expr.as_ref().map(|expr| self.mirror_expr(expr)), | |
496 | }, | |
497 | hir::InlineAsmOperand::Const { ref anon_const } => { | |
498 | let anon_const_def_id = | |
499 | self.tcx.hir().local_def_id(anon_const.hir_id); | |
500 | let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id); | |
501 | let span = self.tcx.hir().span(anon_const.hir_id); | |
cdc7bbd5 | 502 | |
17df50a5 XL |
503 | InlineAsmOperand::Const { value, span } |
504 | } | |
505 | hir::InlineAsmOperand::Sym { ref expr } => { | |
506 | let qpath = match expr.kind { | |
507 | hir::ExprKind::Path(ref qpath) => qpath, | |
508 | _ => span_bug!( | |
509 | expr.span, | |
510 | "asm `sym` operand should be a path, found {:?}", | |
511 | expr.kind | |
512 | ), | |
513 | }; | |
514 | let temp_lifetime = | |
515 | self.region_scope_tree.temporary_scope(expr.hir_id.local_id); | |
516 | let res = self.typeck_results().qpath_res(qpath, expr.hir_id); | |
517 | let ty; | |
518 | match res { | |
519 | Res::Def(DefKind::Fn, _) | Res::Def(DefKind::AssocFn, _) => { | |
520 | ty = self.typeck_results().node_type(expr.hir_id); | |
521 | let user_ty = | |
522 | self.user_substs_applied_to_res(expr.hir_id, res); | |
523 | InlineAsmOperand::SymFn { | |
524 | expr: self.thir.exprs.push(Expr { | |
525 | ty, | |
526 | temp_lifetime, | |
527 | span: expr.span, | |
528 | kind: ExprKind::Literal { | |
529 | literal: ty::Const::zero_sized(self.tcx, ty), | |
530 | user_ty, | |
531 | const_id: None, | |
532 | }, | |
533 | }), | |
534 | } | |
f9f354fc | 535 | } |
f9f354fc | 536 | |
17df50a5 XL |
537 | Res::Def(DefKind::Static, def_id) => { |
538 | InlineAsmOperand::SymStatic { def_id } | |
539 | } | |
f9f354fc | 540 | |
17df50a5 XL |
541 | _ => { |
542 | self.tcx.sess.span_err( | |
543 | expr.span, | |
544 | "asm `sym` operand must point to a fn or static", | |
545 | ); | |
546 | ||
547 | // Not a real fn, but we're not reaching codegen anyways... | |
548 | ty = self.tcx.ty_error(); | |
549 | InlineAsmOperand::SymFn { | |
550 | expr: self.thir.exprs.push(Expr { | |
551 | ty, | |
552 | temp_lifetime, | |
553 | span: expr.span, | |
554 | kind: ExprKind::Literal { | |
555 | literal: ty::Const::zero_sized(self.tcx, ty), | |
556 | user_ty: None, | |
557 | const_id: None, | |
558 | }, | |
559 | }), | |
560 | } | |
f9f354fc XL |
561 | } |
562 | } | |
563 | } | |
564 | } | |
17df50a5 XL |
565 | }) |
566 | .collect(), | |
6a06907d XL |
567 | options: asm.options, |
568 | line_spans: asm.line_spans, | |
569 | }, | |
32a655c1 | 570 | |
6a06907d XL |
571 | hir::ExprKind::ConstBlock(ref anon_const) => { |
572 | let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); | |
3c0e092e | 573 | let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id); |
6a06907d XL |
574 | |
575 | ExprKind::ConstBlock { value } | |
576 | } | |
577 | // Now comes the rote stuff: | |
a2a8927a XL |
578 | hir::ExprKind::Repeat(ref v, _) => { |
579 | let ty = self.typeck_results().expr_ty(expr); | |
580 | let count = match ty.kind() { | |
581 | ty::Array(_, ct) => ct, | |
582 | _ => span_bug!(expr.span, "unexpected repeat expr ty: {:?}", ty), | |
583 | }; | |
6a06907d | 584 | |
5099ac24 | 585 | ExprKind::Repeat { value: self.mirror_expr(v), count: *count } |
6a06907d XL |
586 | } |
587 | hir::ExprKind::Ret(ref v) => { | |
588 | ExprKind::Return { value: v.as_ref().map(|v| self.mirror_expr(v)) } | |
589 | } | |
590 | hir::ExprKind::Break(dest, ref value) => match dest.target_id { | |
591 | Ok(target_id) => ExprKind::Break { | |
592 | label: region::Scope { id: target_id.local_id, data: region::ScopeData::Node }, | |
593 | value: value.as_ref().map(|value| self.mirror_expr(value)), | |
594 | }, | |
595 | Err(err) => bug!("invalid loop id for break: {}", err), | |
dfeec247 | 596 | }, |
6a06907d XL |
597 | hir::ExprKind::Continue(dest) => match dest.target_id { |
598 | Ok(loop_id) => ExprKind::Continue { | |
599 | label: region::Scope { id: loop_id.local_id, data: region::ScopeData::Node }, | |
600 | }, | |
601 | Err(err) => bug!("invalid loop id for continue: {}", err), | |
dfeec247 | 602 | }, |
a2a8927a XL |
603 | hir::ExprKind::Let(let_expr) => ExprKind::Let { |
604 | expr: self.mirror_expr(let_expr.init), | |
605 | pat: self.pattern_from_hir(let_expr.pat), | |
606 | }, | |
6a06907d | 607 | hir::ExprKind::If(cond, then, else_opt) => ExprKind::If { |
94222f64 XL |
608 | if_then_scope: region::Scope { |
609 | id: then.hir_id.local_id, | |
610 | data: region::ScopeData::IfThen, | |
611 | }, | |
6a06907d XL |
612 | cond: self.mirror_expr(cond), |
613 | then: self.mirror_expr(then), | |
614 | else_opt: else_opt.map(|el| self.mirror_expr(el)), | |
615 | }, | |
616 | hir::ExprKind::Match(ref discr, ref arms, _) => ExprKind::Match { | |
617 | scrutinee: self.mirror_expr(discr), | |
17df50a5 | 618 | arms: arms.iter().map(|a| self.convert_arm(a)).collect(), |
6a06907d XL |
619 | }, |
620 | hir::ExprKind::Loop(ref body, ..) => { | |
621 | let block_ty = self.typeck_results().node_type(body.hir_id); | |
622 | let temp_lifetime = self.region_scope_tree.temporary_scope(body.hir_id.local_id); | |
623 | let block = self.mirror_block(body); | |
17df50a5 | 624 | let body = self.thir.exprs.push(Expr { |
6a06907d XL |
625 | ty: block_ty, |
626 | temp_lifetime, | |
627 | span: block.span, | |
628 | kind: ExprKind::Block { body: block }, | |
629 | }); | |
630 | ExprKind::Loop { body } | |
631 | } | |
632 | hir::ExprKind::Field(ref source, ..) => ExprKind::Field { | |
633 | lhs: self.mirror_expr(source), | |
634 | name: Field::new(self.tcx.field_index(expr.hir_id, self.typeck_results)), | |
635 | }, | |
636 | hir::ExprKind::Cast(ref source, ref cast_ty) => { | |
637 | // Check for a user-given type annotation on this `cast` | |
638 | let user_provided_types = self.typeck_results.user_provided_types(); | |
639 | let user_ty = user_provided_types.get(cast_ty.hir_id); | |
640 | ||
641 | debug!( | |
642 | "cast({:?}) has ty w/ hir_id {:?} and user provided ty {:?}", | |
643 | expr, cast_ty.hir_id, user_ty, | |
644 | ); | |
645 | ||
646 | // Check to see if this cast is a "coercion cast", where the cast is actually done | |
647 | // using a coercion (or is a no-op). | |
648 | let cast = if self.typeck_results().is_coercion_cast(source.hir_id) { | |
649 | // Convert the lexpr to a vexpr. | |
650 | ExprKind::Use { source: self.mirror_expr(source) } | |
651 | } else if self.typeck_results().expr_ty(source).is_region_ptr() { | |
652 | // Special cased so that we can type check that the element | |
653 | // type of the source matches the pointed to type of the | |
654 | // destination. | |
655 | ExprKind::Pointer { | |
656 | source: self.mirror_expr(source), | |
657 | cast: PointerCast::ArrayToPointer, | |
658 | } | |
0531ce1d | 659 | } else { |
6a06907d XL |
660 | // check whether this is casting an enum variant discriminant |
661 | // to prevent cycles, we refer to the discriminant initializer | |
662 | // which is always an integer and thus doesn't need to know the | |
663 | // enum's layout (or its tag type) to compute it during const eval | |
664 | // Example: | |
665 | // enum Foo { | |
666 | // A, | |
667 | // B = A as isize + 4, | |
668 | // } | |
669 | // The correct solution would be to add symbolic computations to miri, | |
670 | // so we wouldn't have to compute and store the actual value | |
671 | let var = if let hir::ExprKind::Path(ref qpath) = source.kind { | |
672 | let res = self.typeck_results().qpath_res(qpath, source.hir_id); | |
673 | self.typeck_results().node_type(source.hir_id).ty_adt_def().and_then( | |
674 | |adt_def| match res { | |
675 | Res::Def( | |
676 | DefKind::Ctor(CtorOf::Variant, CtorKind::Const), | |
677 | variant_ctor_id, | |
678 | ) => { | |
679 | let idx = adt_def.variant_index_with_ctor_id(variant_ctor_id); | |
680 | let (d, o) = adt_def.discriminant_def_for_variant(idx); | |
681 | use rustc_middle::ty::util::IntTypeExt; | |
682 | let ty = adt_def.repr.discr_type(); | |
683 | let ty = ty.to_ty(self.tcx()); | |
684 | Some((d, o, ty)) | |
685 | } | |
686 | _ => None, | |
687 | }, | |
688 | ) | |
689 | } else { | |
690 | None | |
dfeec247 | 691 | }; |
6a06907d XL |
692 | |
693 | let source = if let Some((did, offset, var_ty)) = var { | |
17df50a5 XL |
694 | let mk_const = |literal| Expr { |
695 | temp_lifetime, | |
696 | ty: var_ty, | |
697 | span: expr.span, | |
698 | kind: ExprKind::Literal { literal, user_ty: None, const_id: None }, | |
6a06907d | 699 | }; |
17df50a5 | 700 | let offset = self.thir.exprs.push(mk_const(ty::Const::from_bits( |
6a06907d XL |
701 | self.tcx, |
702 | offset as u128, | |
703 | self.param_env.and(var_ty), | |
17df50a5 | 704 | ))); |
6a06907d XL |
705 | match did { |
706 | Some(did) => { | |
707 | // in case we are offsetting from a computed discriminant | |
708 | // and not the beginning of discriminants (which is always `0`) | |
709 | let substs = InternalSubsts::identity_for_item(self.tcx(), did); | |
5099ac24 | 710 | let lhs = ty::ConstS { |
94222f64 XL |
711 | val: ty::ConstKind::Unevaluated(ty::Unevaluated::new( |
712 | ty::WithOptConstParam::unknown(did), | |
6a06907d | 713 | substs, |
94222f64 | 714 | )), |
6a06907d | 715 | ty: var_ty, |
17df50a5 XL |
716 | }; |
717 | let lhs = self.thir.exprs.push(mk_const(self.tcx().mk_const(lhs))); | |
6a06907d XL |
718 | let bin = |
719 | ExprKind::Binary { op: BinOp::Add, lhs: lhs, rhs: offset }; | |
17df50a5 | 720 | self.thir.exprs.push(Expr { |
6a06907d XL |
721 | temp_lifetime, |
722 | ty: var_ty, | |
723 | span: expr.span, | |
724 | kind: bin, | |
725 | }) | |
726 | } | |
727 | None => offset, | |
dfeec247 | 728 | } |
6a06907d XL |
729 | } else { |
730 | self.mirror_expr(source) | |
731 | }; | |
0bf4aa26 | 732 | |
6a06907d XL |
733 | ExprKind::Cast { source: source } |
734 | }; | |
0bf4aa26 | 735 | |
6a06907d XL |
736 | if let Some(user_ty) = user_ty { |
737 | // NOTE: Creating a new Expr and wrapping a Cast inside of it may be | |
738 | // inefficient, revisit this when performance becomes an issue. | |
17df50a5 | 739 | let cast_expr = self.thir.exprs.push(Expr { |
6a06907d XL |
740 | temp_lifetime, |
741 | ty: expr_ty, | |
742 | span: expr.span, | |
743 | kind: cast, | |
744 | }); | |
745 | debug!("make_mirror_unadjusted: (cast) user_ty={:?}", user_ty); | |
0bf4aa26 | 746 | |
6a06907d XL |
747 | ExprKind::ValueTypeAscription { source: cast_expr, user_ty: Some(*user_ty) } |
748 | } else { | |
749 | cast | |
0bf4aa26 | 750 | } |
0bf4aa26 | 751 | } |
6a06907d XL |
752 | hir::ExprKind::Type(ref source, ref ty) => { |
753 | let user_provided_types = self.typeck_results.user_provided_types(); | |
754 | let user_ty = user_provided_types.get(ty.hir_id).copied(); | |
755 | debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty); | |
756 | let mirrored = self.mirror_expr(source); | |
757 | if source.is_syntactic_place_expr() { | |
758 | ExprKind::PlaceTypeAscription { source: mirrored, user_ty } | |
759 | } else { | |
760 | ExprKind::ValueTypeAscription { source: mirrored, user_ty } | |
761 | } | |
762 | } | |
763 | hir::ExprKind::DropTemps(ref source) => { | |
764 | ExprKind::Use { source: self.mirror_expr(source) } | |
765 | } | |
766 | hir::ExprKind::Box(ref value) => ExprKind::Box { value: self.mirror_expr(value) }, | |
767 | hir::ExprKind::Array(ref fields) => { | |
768 | ExprKind::Array { fields: self.mirror_exprs(fields) } | |
476ff2be | 769 | } |
6a06907d XL |
770 | hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: self.mirror_exprs(fields) }, |
771 | ||
772 | hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: self.mirror_expr(v) }, | |
773 | hir::ExprKind::Err => unreachable!(), | |
774 | }; | |
775 | ||
776 | Expr { temp_lifetime, ty: expr_ty, span: expr.span, kind } | |
777 | } | |
778 | ||
779 | fn user_substs_applied_to_res( | |
780 | &mut self, | |
781 | hir_id: hir::HirId, | |
782 | res: Res, | |
783 | ) -> Option<ty::CanonicalUserType<'tcx>> { | |
784 | debug!("user_substs_applied_to_res: res={:?}", res); | |
785 | let user_provided_type = match res { | |
786 | // A reference to something callable -- e.g., a fn, method, or | |
787 | // a tuple-struct or tuple-variant. This has the type of a | |
788 | // `Fn` but with the user-given substitutions. | |
789 | Res::Def(DefKind::Fn, _) | |
790 | | Res::Def(DefKind::AssocFn, _) | |
791 | | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | |
792 | | Res::Def(DefKind::Const, _) | |
793 | | Res::Def(DefKind::AssocConst, _) => { | |
794 | self.typeck_results().user_provided_types().get(hir_id).copied() | |
795 | } | |
796 | ||
797 | // A unit struct/variant which is used as a value (e.g., | |
798 | // `None`). This has the type of the enum/struct that defines | |
799 | // this variant -- but with the substitutions given by the | |
800 | // user. | |
801 | Res::Def(DefKind::Ctor(_, CtorKind::Const), _) => { | |
802 | self.user_substs_applied_to_ty_of_hir_id(hir_id) | |
803 | } | |
804 | ||
94222f64 | 805 | // `Self` is used in expression as a tuple struct constructor or a unit struct constructor |
6a06907d XL |
806 | Res::SelfCtor(_) => self.user_substs_applied_to_ty_of_hir_id(hir_id), |
807 | ||
808 | _ => bug!("user_substs_applied_to_res: unexpected res {:?} at {:?}", res, hir_id), | |
809 | }; | |
810 | debug!("user_substs_applied_to_res: user_provided_type={:?}", user_provided_type); | |
811 | user_provided_type | |
812 | } | |
813 | ||
814 | fn method_callee( | |
815 | &mut self, | |
816 | expr: &hir::Expr<'_>, | |
817 | span: Span, | |
818 | overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>, | |
17df50a5 | 819 | ) -> Expr<'tcx> { |
6a06907d XL |
820 | let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); |
821 | let (def_id, substs, user_ty) = match overloaded_callee { | |
822 | Some((def_id, substs)) => (def_id, substs, None), | |
823 | None => { | |
824 | let (kind, def_id) = | |
825 | self.typeck_results().type_dependent_def(expr.hir_id).unwrap_or_else(|| { | |
826 | span_bug!(expr.span, "no type-dependent def for method callee") | |
827 | }); | |
828 | let user_ty = self.user_substs_applied_to_res(expr.hir_id, Res::Def(kind, def_id)); | |
829 | debug!("method_callee: user_ty={:?}", user_ty); | |
830 | (def_id, self.typeck_results().node_substs(expr.hir_id), user_ty) | |
831 | } | |
832 | }; | |
833 | let ty = self.tcx().mk_fn_def(def_id, substs); | |
834 | Expr { | |
835 | temp_lifetime, | |
836 | ty, | |
837 | span, | |
838 | kind: ExprKind::Literal { | |
839 | literal: ty::Const::zero_sized(self.tcx(), ty), | |
840 | user_ty, | |
841 | const_id: None, | |
842 | }, | |
476ff2be | 843 | } |
6a06907d | 844 | } |
ea8adc8c | 845 | |
17df50a5 XL |
846 | fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId { |
847 | let arm = Arm { | |
6a06907d XL |
848 | pattern: self.pattern_from_hir(&arm.pat), |
849 | guard: arm.guard.as_ref().map(|g| match g { | |
850 | hir::Guard::If(ref e) => Guard::If(self.mirror_expr(e)), | |
851 | hir::Guard::IfLet(ref pat, ref e) => { | |
852 | Guard::IfLet(self.pattern_from_hir(pat), self.mirror_expr(e)) | |
853 | } | |
854 | }), | |
855 | body: self.mirror_expr(arm.body), | |
856 | lint_level: LintLevel::Explicit(arm.hir_id), | |
857 | scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node }, | |
858 | span: arm.span, | |
17df50a5 XL |
859 | }; |
860 | self.thir.arms.push(arm) | |
6a06907d | 861 | } |
a7813a04 | 862 | |
17df50a5 | 863 | fn convert_path_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, res: Res) -> ExprKind<'tcx> { |
6a06907d XL |
864 | let substs = self.typeck_results().node_substs(expr.hir_id); |
865 | match res { | |
866 | // A regular function, constructor function or a constant. | |
867 | Res::Def(DefKind::Fn, _) | |
868 | | Res::Def(DefKind::AssocFn, _) | |
869 | | Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | |
870 | | Res::SelfCtor(..) => { | |
871 | let user_ty = self.user_substs_applied_to_res(expr.hir_id, res); | |
872 | debug!("convert_path_expr: user_ty={:?}", user_ty); | |
873 | ExprKind::Literal { | |
874 | literal: ty::Const::zero_sized( | |
875 | self.tcx, | |
876 | self.typeck_results().node_type(expr.hir_id), | |
877 | ), | |
878 | user_ty, | |
879 | const_id: None, | |
880 | } | |
881 | } | |
882 | ||
883 | Res::Def(DefKind::ConstParam, def_id) => { | |
884 | let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); | |
885 | let item_id = self.tcx.hir().get_parent_node(hir_id); | |
886 | let item_def_id = self.tcx.hir().local_def_id(item_id); | |
887 | let generics = self.tcx.generics_of(item_def_id); | |
888 | let index = generics.param_def_id_to_index[&def_id]; | |
889 | let name = self.tcx.hir().name(hir_id); | |
890 | let val = ty::ConstKind::Param(ty::ParamConst::new(index, name)); | |
891 | ExprKind::Literal { | |
5099ac24 | 892 | literal: self.tcx.mk_const(ty::ConstS { |
6a06907d XL |
893 | val, |
894 | ty: self.typeck_results().node_type(expr.hir_id), | |
895 | }), | |
896 | user_ty: None, | |
897 | const_id: Some(def_id), | |
898 | } | |
899 | } | |
900 | ||
901 | Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => { | |
902 | let user_ty = self.user_substs_applied_to_res(expr.hir_id, res); | |
903 | debug!("convert_path_expr: (const) user_ty={:?}", user_ty); | |
904 | ExprKind::Literal { | |
5099ac24 | 905 | literal: self.tcx.mk_const(ty::ConstS { |
94222f64 XL |
906 | val: ty::ConstKind::Unevaluated(ty::Unevaluated::new( |
907 | ty::WithOptConstParam::unknown(def_id), | |
6a06907d | 908 | substs, |
94222f64 | 909 | )), |
6a06907d XL |
910 | ty: self.typeck_results().node_type(expr.hir_id), |
911 | }), | |
912 | user_ty, | |
913 | const_id: Some(def_id), | |
914 | } | |
915 | } | |
916 | ||
917 | Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id) => { | |
918 | let user_provided_types = self.typeck_results.user_provided_types(); | |
919 | let user_provided_type = user_provided_types.get(expr.hir_id).copied(); | |
920 | debug!("convert_path_expr: user_provided_type={:?}", user_provided_type); | |
921 | let ty = self.typeck_results().node_type(expr.hir_id); | |
922 | match ty.kind() { | |
923 | // A unit struct/variant which is used as a value. | |
924 | // We return a completely different ExprKind here to account for this special case. | |
136023e0 | 925 | ty::Adt(adt_def, substs) => ExprKind::Adt(Box::new(Adt { |
6a06907d XL |
926 | adt_def, |
927 | variant_index: adt_def.variant_index_with_ctor_id(def_id), | |
928 | substs, | |
929 | user_ty: user_provided_type, | |
94222f64 | 930 | fields: Box::new([]), |
6a06907d | 931 | base: None, |
136023e0 | 932 | })), |
6a06907d XL |
933 | _ => bug!("unexpected ty: {:?}", ty), |
934 | } | |
935 | } | |
936 | ||
937 | // We encode uses of statics as a `*&STATIC` where the `&STATIC` part is | |
938 | // a constant reference (or constant raw pointer for `static mut`) in MIR | |
939 | Res::Def(DefKind::Static, id) => { | |
940 | let ty = self.tcx.static_ptr_ty(id); | |
941 | let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); | |
942 | let kind = if self.tcx.is_thread_local_static(id) { | |
943 | ExprKind::ThreadLocalRef(id) | |
944 | } else { | |
5099ac24 FG |
945 | let alloc_id = self.tcx.create_static_alloc(id); |
946 | ExprKind::StaticRef { alloc_id, ty, def_id: id } | |
6a06907d XL |
947 | }; |
948 | ExprKind::Deref { | |
17df50a5 | 949 | arg: self.thir.exprs.push(Expr { ty, temp_lifetime, span: expr.span, kind }), |
6a06907d XL |
950 | } |
951 | } | |
952 | ||
953 | Res::Local(var_hir_id) => self.convert_var(var_hir_id), | |
a7813a04 | 954 | |
6a06907d | 955 | _ => span_bug!(expr.span, "res `{:?}` not yet implemented", res), |
dfeec247 | 956 | } |
6a06907d | 957 | } |
b7449926 | 958 | |
17df50a5 | 959 | fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'tcx> { |
6a06907d XL |
960 | // We want upvars here not captures. |
961 | // Captures will be handled in MIR. | |
962 | let is_upvar = self | |
963 | .tcx | |
964 | .upvars_mentioned(self.body_owner) | |
965 | .map_or(false, |upvars| upvars.contains_key(&var_hir_id)); | |
966 | ||
967 | debug!( | |
968 | "convert_var({:?}): is_upvar={}, body_owner={:?}", | |
969 | var_hir_id, is_upvar, self.body_owner | |
970 | ); | |
971 | ||
972 | if is_upvar { | |
973 | ExprKind::UpvarRef { closure_def_id: self.body_owner, var_hir_id } | |
974 | } else { | |
975 | ExprKind::VarRef { id: var_hir_id } | |
dfeec247 | 976 | } |
6a06907d | 977 | } |
b7449926 | 978 | |
6a06907d XL |
979 | fn overloaded_operator( |
980 | &mut self, | |
981 | expr: &'tcx hir::Expr<'tcx>, | |
17df50a5 XL |
982 | args: Box<[ExprId]>, |
983 | ) -> ExprKind<'tcx> { | |
984 | let fun = self.method_callee(expr, expr.span, None); | |
985 | let fun = self.thir.exprs.push(fun); | |
986 | ExprKind::Call { | |
987 | ty: self.thir[fun].ty, | |
988 | fun, | |
989 | args, | |
990 | from_hir_call: false, | |
991 | fn_span: expr.span, | |
992 | } | |
6a06907d | 993 | } |
0bf4aa26 | 994 | |
6a06907d XL |
995 | fn overloaded_place( |
996 | &mut self, | |
997 | expr: &'tcx hir::Expr<'tcx>, | |
998 | place_ty: Ty<'tcx>, | |
999 | overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>, | |
17df50a5 | 1000 | args: Box<[ExprId]>, |
6a06907d | 1001 | span: Span, |
17df50a5 | 1002 | ) -> ExprKind<'tcx> { |
6a06907d XL |
1003 | // For an overloaded *x or x[y] expression of type T, the method |
1004 | // call returns an &T and we must add the deref so that the types | |
1005 | // line up (this is because `*x` and `x[y]` represent places): | |
1006 | ||
1007 | // Reconstruct the output assuming it's a reference with the | |
1008 | // same region and mutability as the receiver. This holds for | |
1009 | // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. | |
17df50a5 | 1010 | let (region, mutbl) = match *self.thir[args[0]].ty.kind() { |
6a06907d XL |
1011 | ty::Ref(region, _, mutbl) => (region, mutbl), |
1012 | _ => span_bug!(span, "overloaded_place: receiver is not a reference"), | |
1013 | }; | |
1014 | let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl }); | |
1015 | ||
1016 | // construct the complete expression `foo()` for the overloaded call, | |
1017 | // which will yield the &T type | |
1018 | let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); | |
17df50a5 XL |
1019 | let fun = self.method_callee(expr, span, overloaded_callee); |
1020 | let fun = self.thir.exprs.push(fun); | |
1021 | let fun_ty = self.thir[fun].ty; | |
1022 | let ref_expr = self.thir.exprs.push(Expr { | |
6a06907d XL |
1023 | temp_lifetime, |
1024 | ty: ref_ty, | |
1025 | span, | |
17df50a5 | 1026 | kind: ExprKind::Call { ty: fun_ty, fun, args, from_hir_call: false, fn_span: span }, |
6a06907d | 1027 | }); |
b7449926 | 1028 | |
6a06907d XL |
1029 | // construct and return a deref wrapper `*foo()` |
1030 | ExprKind::Deref { arg: ref_expr } | |
1031 | } | |
1032 | ||
1033 | fn convert_captured_hir_place( | |
1034 | &mut self, | |
1035 | closure_expr: &'tcx hir::Expr<'tcx>, | |
1036 | place: HirPlace<'tcx>, | |
17df50a5 | 1037 | ) -> Expr<'tcx> { |
6a06907d XL |
1038 | let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); |
1039 | let var_ty = place.base_ty; | |
1040 | ||
1041 | // The result of capture analysis in `rustc_typeck/check/upvar.rs`represents a captured path | |
1042 | // as it's seen for use within the closure and not at the time of closure creation. | |
1043 | // | |
1044 | // That is we see expect to see it start from a captured upvar and not something that is local | |
1045 | // to the closure's parent. | |
1046 | let var_hir_id = match place.base { | |
1047 | HirPlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, | |
1048 | base => bug!("Expected an upvar, found {:?}", base), | |
1049 | }; | |
1050 | ||
1051 | let mut captured_place_expr = Expr { | |
1052 | temp_lifetime, | |
1053 | ty: var_ty, | |
1054 | span: closure_expr.span, | |
1055 | kind: self.convert_var(var_hir_id), | |
1056 | }; | |
1057 | ||
1058 | for proj in place.projections.iter() { | |
1059 | let kind = match proj.kind { | |
1060 | HirProjectionKind::Deref => { | |
17df50a5 | 1061 | ExprKind::Deref { arg: self.thir.exprs.push(captured_place_expr) } |
6a06907d XL |
1062 | } |
1063 | HirProjectionKind::Field(field, ..) => { | |
1064 | // Variant index will always be 0, because for multi-variant | |
1065 | // enums, we capture the enum entirely. | |
1066 | ExprKind::Field { | |
17df50a5 | 1067 | lhs: self.thir.exprs.push(captured_place_expr), |
6a06907d XL |
1068 | name: Field::new(field as usize), |
1069 | } | |
1070 | } | |
1071 | HirProjectionKind::Index | HirProjectionKind::Subslice => { | |
1072 | // We don't capture these projections, so we can ignore them here | |
1073 | continue; | |
1074 | } | |
1075 | }; | |
1076 | ||
1077 | captured_place_expr = | |
1078 | Expr { temp_lifetime, ty: proj.ty, span: closure_expr.span, kind }; | |
1079 | } | |
1080 | ||
1081 | captured_place_expr | |
1082 | } | |
1083 | ||
1084 | fn capture_upvar( | |
1085 | &mut self, | |
1086 | closure_expr: &'tcx hir::Expr<'tcx>, | |
1087 | captured_place: &'tcx ty::CapturedPlace<'tcx>, | |
1088 | upvar_ty: Ty<'tcx>, | |
17df50a5 | 1089 | ) -> Expr<'tcx> { |
6a06907d XL |
1090 | let upvar_capture = captured_place.info.capture_kind; |
1091 | let captured_place_expr = | |
1092 | self.convert_captured_hir_place(closure_expr, captured_place.place.clone()); | |
1093 | let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); | |
1094 | ||
1095 | match upvar_capture { | |
5099ac24 | 1096 | ty::UpvarCapture::ByValue => captured_place_expr, |
6a06907d | 1097 | ty::UpvarCapture::ByRef(upvar_borrow) => { |
5099ac24 | 1098 | let borrow_kind = match upvar_borrow { |
6a06907d XL |
1099 | ty::BorrowKind::ImmBorrow => BorrowKind::Shared, |
1100 | ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique, | |
1101 | ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false }, | |
1102 | }; | |
1103 | Expr { | |
1104 | temp_lifetime, | |
1105 | ty: upvar_ty, | |
1106 | span: closure_expr.span, | |
1107 | kind: ExprKind::Borrow { | |
1108 | borrow_kind, | |
17df50a5 | 1109 | arg: self.thir.exprs.push(captured_place_expr), |
6a06907d XL |
1110 | }, |
1111 | } | |
1112 | } | |
8faf50e0 | 1113 | } |
6a06907d XL |
1114 | } |
1115 | ||
1116 | /// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExpr. | |
17df50a5 XL |
1117 | fn field_refs(&mut self, fields: &'tcx [hir::ExprField<'tcx>]) -> Box<[FieldExpr]> { |
1118 | fields | |
1119 | .iter() | |
1120 | .map(|field| FieldExpr { | |
1121 | name: Field::new(self.tcx.field_index(field.hir_id, self.typeck_results)), | |
1122 | expr: self.mirror_expr(field.expr), | |
1123 | }) | |
1124 | .collect() | |
e9174d1e SL |
1125 | } |
1126 | } | |
1127 | ||
dfeec247 XL |
1128 | trait ToBorrowKind { |
1129 | fn to_borrow_kind(&self) -> BorrowKind; | |
1130 | } | |
2c00a5a8 XL |
1131 | |
1132 | impl ToBorrowKind for AutoBorrowMutability { | |
1133 | fn to_borrow_kind(&self) -> BorrowKind { | |
ba9703b0 | 1134 | use rustc_middle::ty::adjustment::AllowTwoPhase; |
2c00a5a8 | 1135 | match *self { |
dfeec247 XL |
1136 | AutoBorrowMutability::Mut { allow_two_phase_borrow } => BorrowKind::Mut { |
1137 | allow_two_phase_borrow: match allow_two_phase_borrow { | |
83c7162d | 1138 | AllowTwoPhase::Yes => true, |
dfeec247 XL |
1139 | AllowTwoPhase::No => false, |
1140 | }, | |
1141 | }, | |
1142 | AutoBorrowMutability::Not => BorrowKind::Shared, | |
2c00a5a8 XL |
1143 | } |
1144 | } | |
1145 | } | |
1146 | ||
1147 | impl ToBorrowKind for hir::Mutability { | |
1148 | fn to_borrow_kind(&self) -> BorrowKind { | |
1149 | match *self { | |
dfeec247 XL |
1150 | hir::Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false }, |
1151 | hir::Mutability::Not => BorrowKind::Shared, | |
2c00a5a8 | 1152 | } |
e9174d1e SL |
1153 | } |
1154 | } | |
1155 | ||
8faf50e0 | 1156 | fn bin_op(op: hir::BinOpKind) -> BinOp { |
e9174d1e | 1157 | match op { |
8faf50e0 XL |
1158 | hir::BinOpKind::Add => BinOp::Add, |
1159 | hir::BinOpKind::Sub => BinOp::Sub, | |
1160 | hir::BinOpKind::Mul => BinOp::Mul, | |
1161 | hir::BinOpKind::Div => BinOp::Div, | |
1162 | hir::BinOpKind::Rem => BinOp::Rem, | |
1163 | hir::BinOpKind::BitXor => BinOp::BitXor, | |
1164 | hir::BinOpKind::BitAnd => BinOp::BitAnd, | |
1165 | hir::BinOpKind::BitOr => BinOp::BitOr, | |
1166 | hir::BinOpKind::Shl => BinOp::Shl, | |
1167 | hir::BinOpKind::Shr => BinOp::Shr, | |
1168 | hir::BinOpKind::Eq => BinOp::Eq, | |
1169 | hir::BinOpKind::Lt => BinOp::Lt, | |
1170 | hir::BinOpKind::Le => BinOp::Le, | |
1171 | hir::BinOpKind::Ne => BinOp::Ne, | |
1172 | hir::BinOpKind::Ge => BinOp::Ge, | |
1173 | hir::BinOpKind::Gt => BinOp::Gt, | |
54a0048b | 1174 | _ => bug!("no equivalent for ast binop {:?}", op), |
e9174d1e SL |
1175 | } |
1176 | } |