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