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