]>
Commit | Line | Data |
---|---|---|
416331ca XL |
1 | use super::{LoweringContext, ParamMode, ParenthesizedGenericArgs, ImplTraitContext}; |
2 | use crate::hir::{self, HirVec}; | |
3 | use crate::hir::def::Res; | |
4 | use crate::hir::ptr::P; | |
5 | ||
6 | use rustc_data_structures::thin_vec::ThinVec; | |
7 | ||
8 | use syntax::attr; | |
9 | use syntax::ptr::P as AstP; | |
10 | use syntax::ast::*; | |
11 | use syntax::source_map::{respan, DesugaringKind, Span, Spanned}; | |
12 | use syntax::symbol::{sym, Symbol}; | |
13 | ||
14 | impl LoweringContext<'_> { | |
15 | fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> HirVec<hir::Expr> { | |
16 | exprs.iter().map(|x| self.lower_expr(x)).collect() | |
17 | } | |
18 | ||
19 | pub(super) fn lower_expr(&mut self, e: &Expr) -> hir::Expr { | |
20 | let kind = match e.node { | |
21 | ExprKind::Box(ref inner) => hir::ExprKind::Box(P(self.lower_expr(inner))), | |
22 | ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), | |
23 | ExprKind::Repeat(ref expr, ref count) => { | |
24 | let expr = P(self.lower_expr(expr)); | |
25 | let count = self.lower_anon_const(count); | |
26 | hir::ExprKind::Repeat(expr, count) | |
27 | } | |
28 | ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), | |
29 | ExprKind::Call(ref f, ref args) => { | |
30 | let f = P(self.lower_expr(f)); | |
31 | hir::ExprKind::Call(f, self.lower_exprs(args)) | |
32 | } | |
33 | ExprKind::MethodCall(ref seg, ref args) => { | |
34 | let hir_seg = P(self.lower_path_segment( | |
35 | e.span, | |
36 | seg, | |
37 | ParamMode::Optional, | |
38 | 0, | |
39 | ParenthesizedGenericArgs::Err, | |
40 | ImplTraitContext::disallowed(), | |
41 | None, | |
42 | )); | |
43 | let args = self.lower_exprs(args); | |
44 | hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args) | |
45 | } | |
46 | ExprKind::Binary(binop, ref lhs, ref rhs) => { | |
47 | let binop = self.lower_binop(binop); | |
48 | let lhs = P(self.lower_expr(lhs)); | |
49 | let rhs = P(self.lower_expr(rhs)); | |
50 | hir::ExprKind::Binary(binop, lhs, rhs) | |
51 | } | |
52 | ExprKind::Unary(op, ref ohs) => { | |
53 | let op = self.lower_unop(op); | |
54 | let ohs = P(self.lower_expr(ohs)); | |
55 | hir::ExprKind::Unary(op, ohs) | |
56 | } | |
57 | ExprKind::Lit(ref l) => hir::ExprKind::Lit(respan(l.span, l.node.clone())), | |
58 | ExprKind::Cast(ref expr, ref ty) => { | |
59 | let expr = P(self.lower_expr(expr)); | |
60 | hir::ExprKind::Cast(expr, self.lower_ty(ty, ImplTraitContext::disallowed())) | |
61 | } | |
62 | ExprKind::Type(ref expr, ref ty) => { | |
63 | let expr = P(self.lower_expr(expr)); | |
64 | hir::ExprKind::Type(expr, self.lower_ty(ty, ImplTraitContext::disallowed())) | |
65 | } | |
66 | ExprKind::AddrOf(m, ref ohs) => { | |
67 | let m = self.lower_mutability(m); | |
68 | let ohs = P(self.lower_expr(ohs)); | |
69 | hir::ExprKind::AddrOf(m, ohs) | |
70 | } | |
71 | ExprKind::Let(ref pats, ref scrutinee) => self.lower_expr_let(e.span, pats, scrutinee), | |
72 | ExprKind::If(ref cond, ref then, ref else_opt) => { | |
73 | self.lower_expr_if(e.span, cond, then, else_opt.as_deref()) | |
74 | } | |
75 | ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| { | |
76 | this.lower_expr_while_in_loop_scope(e.span, cond, body, opt_label) | |
77 | }), | |
78 | ExprKind::Loop(ref body, opt_label) => self.with_loop_scope(e.id, |this| { | |
79 | hir::ExprKind::Loop( | |
80 | this.lower_block(body, false), | |
81 | this.lower_label(opt_label), | |
82 | hir::LoopSource::Loop, | |
83 | ) | |
84 | }), | |
85 | ExprKind::TryBlock(ref body) => self.lower_expr_try_block(body), | |
86 | ExprKind::Match(ref expr, ref arms) => hir::ExprKind::Match( | |
87 | P(self.lower_expr(expr)), | |
88 | arms.iter().map(|x| self.lower_arm(x)).collect(), | |
89 | hir::MatchSource::Normal, | |
90 | ), | |
91 | ExprKind::Async(capture_clause, closure_node_id, ref block) => { | |
92 | self.make_async_expr(capture_clause, closure_node_id, None, block.span, |this| { | |
93 | this.with_new_scopes(|this| { | |
94 | let block = this.lower_block(block, false); | |
95 | this.expr_block(block, ThinVec::new()) | |
96 | }) | |
97 | }) | |
98 | } | |
99 | ExprKind::Await(ref expr) => self.lower_expr_await(e.span, expr), | |
100 | ExprKind::Closure( | |
101 | capture_clause, asyncness, movability, ref decl, ref body, fn_decl_span | |
102 | ) => if let IsAsync::Async { closure_id, .. } = asyncness { | |
103 | self.lower_expr_async_closure(capture_clause, closure_id, decl, body, fn_decl_span) | |
104 | } else { | |
105 | self.lower_expr_closure(capture_clause, movability, decl, body, fn_decl_span) | |
106 | } | |
107 | ExprKind::Block(ref blk, opt_label) => { | |
108 | hir::ExprKind::Block(self.lower_block(blk, | |
109 | opt_label.is_some()), | |
110 | self.lower_label(opt_label)) | |
111 | } | |
112 | ExprKind::Assign(ref el, ref er) => { | |
113 | hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er))) | |
114 | } | |
115 | ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp( | |
116 | self.lower_binop(op), | |
117 | P(self.lower_expr(el)), | |
118 | P(self.lower_expr(er)), | |
119 | ), | |
120 | ExprKind::Field(ref el, ident) => hir::ExprKind::Field(P(self.lower_expr(el)), ident), | |
121 | ExprKind::Index(ref el, ref er) => { | |
122 | hir::ExprKind::Index(P(self.lower_expr(el)), P(self.lower_expr(er))) | |
123 | } | |
124 | ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => { | |
125 | self.lower_expr_range_closed(e.span, e1, e2) | |
126 | } | |
127 | ExprKind::Range(ref e1, ref e2, lims) => { | |
128 | self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), lims) | |
129 | } | |
130 | ExprKind::Path(ref qself, ref path) => { | |
131 | let qpath = self.lower_qpath( | |
132 | e.id, | |
133 | qself, | |
134 | path, | |
135 | ParamMode::Optional, | |
136 | ImplTraitContext::disallowed(), | |
137 | ); | |
138 | hir::ExprKind::Path(qpath) | |
139 | } | |
140 | ExprKind::Break(opt_label, ref opt_expr) => { | |
141 | hir::ExprKind::Break( | |
142 | self.lower_jump_destination(e.id, opt_label), | |
143 | opt_expr.as_ref().map(|x| P(self.lower_expr(x))), | |
144 | ) | |
145 | } | |
146 | ExprKind::Continue(opt_label) => { | |
147 | hir::ExprKind::Continue(self.lower_jump_destination(e.id, opt_label)) | |
148 | } | |
149 | ExprKind::Ret(ref e) => hir::ExprKind::Ret(e.as_ref().map(|x| P(self.lower_expr(x)))), | |
150 | ExprKind::InlineAsm(ref asm) => self.lower_expr_asm(asm), | |
151 | ExprKind::Struct(ref path, ref fields, ref maybe_expr) => hir::ExprKind::Struct( | |
152 | P(self.lower_qpath( | |
153 | e.id, | |
154 | &None, | |
155 | path, | |
156 | ParamMode::Optional, | |
157 | ImplTraitContext::disallowed(), | |
158 | )), | |
159 | fields.iter().map(|x| self.lower_field(x)).collect(), | |
160 | maybe_expr.as_ref().map(|x| P(self.lower_expr(x))), | |
161 | ), | |
162 | ExprKind::Paren(ref ex) => { | |
163 | let mut ex = self.lower_expr(ex); | |
164 | // Include parens in span, but only if it is a super-span. | |
165 | if e.span.contains(ex.span) { | |
166 | ex.span = e.span; | |
167 | } | |
168 | // Merge attributes into the inner expression. | |
169 | let mut attrs = e.attrs.clone(); | |
170 | attrs.extend::<Vec<_>>(ex.attrs.into()); | |
171 | ex.attrs = attrs; | |
172 | return ex; | |
173 | } | |
174 | ||
175 | ExprKind::Yield(ref opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), | |
176 | ||
177 | ExprKind::Err => hir::ExprKind::Err, | |
178 | ||
179 | // Desugar `ExprForLoop` | |
180 | // from: `[opt_ident]: for <pat> in <head> <body>` | |
181 | ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => { | |
182 | return self.lower_expr_for(e, pat, head, body, opt_label); | |
183 | } | |
184 | ExprKind::Try(ref sub_expr) => self.lower_expr_try(e.span, sub_expr), | |
185 | ExprKind::Mac(_) => panic!("Shouldn't exist here"), | |
186 | }; | |
187 | ||
188 | hir::Expr { | |
189 | hir_id: self.lower_node_id(e.id), | |
190 | node: kind, | |
191 | span: e.span, | |
192 | attrs: e.attrs.clone(), | |
193 | } | |
194 | } | |
195 | ||
196 | fn lower_unop(&mut self, u: UnOp) -> hir::UnOp { | |
197 | match u { | |
198 | UnOp::Deref => hir::UnDeref, | |
199 | UnOp::Not => hir::UnNot, | |
200 | UnOp::Neg => hir::UnNeg, | |
201 | } | |
202 | } | |
203 | ||
204 | fn lower_binop(&mut self, b: BinOp) -> hir::BinOp { | |
205 | Spanned { | |
206 | node: match b.node { | |
207 | BinOpKind::Add => hir::BinOpKind::Add, | |
208 | BinOpKind::Sub => hir::BinOpKind::Sub, | |
209 | BinOpKind::Mul => hir::BinOpKind::Mul, | |
210 | BinOpKind::Div => hir::BinOpKind::Div, | |
211 | BinOpKind::Rem => hir::BinOpKind::Rem, | |
212 | BinOpKind::And => hir::BinOpKind::And, | |
213 | BinOpKind::Or => hir::BinOpKind::Or, | |
214 | BinOpKind::BitXor => hir::BinOpKind::BitXor, | |
215 | BinOpKind::BitAnd => hir::BinOpKind::BitAnd, | |
216 | BinOpKind::BitOr => hir::BinOpKind::BitOr, | |
217 | BinOpKind::Shl => hir::BinOpKind::Shl, | |
218 | BinOpKind::Shr => hir::BinOpKind::Shr, | |
219 | BinOpKind::Eq => hir::BinOpKind::Eq, | |
220 | BinOpKind::Lt => hir::BinOpKind::Lt, | |
221 | BinOpKind::Le => hir::BinOpKind::Le, | |
222 | BinOpKind::Ne => hir::BinOpKind::Ne, | |
223 | BinOpKind::Ge => hir::BinOpKind::Ge, | |
224 | BinOpKind::Gt => hir::BinOpKind::Gt, | |
225 | }, | |
226 | span: b.span, | |
227 | } | |
228 | } | |
229 | ||
230 | /// Emit an error and lower `ast::ExprKind::Let(pats, scrutinee)` into: | |
231 | /// ```rust | |
232 | /// match scrutinee { pats => true, _ => false } | |
233 | /// ``` | |
234 | fn lower_expr_let( | |
235 | &mut self, | |
236 | span: Span, | |
237 | pats: &[AstP<Pat>], | |
238 | scrutinee: &Expr | |
239 | ) -> hir::ExprKind { | |
240 | // If we got here, the `let` expression is not allowed. | |
241 | self.sess | |
242 | .struct_span_err(span, "`let` expressions are not supported here") | |
243 | .note("only supported directly in conditions of `if`- and `while`-expressions") | |
244 | .note("as well as when nested within `&&` and parenthesis in those conditions") | |
245 | .emit(); | |
246 | ||
247 | // For better recovery, we emit: | |
248 | // ``` | |
249 | // match scrutinee { pats => true, _ => false } | |
250 | // ``` | |
251 | // While this doesn't fully match the user's intent, it has key advantages: | |
252 | // 1. We can avoid using `abort_if_errors`. | |
253 | // 2. We can typeck both `pats` and `scrutinee`. | |
254 | // 3. `pats` is allowed to be refutable. | |
255 | // 4. The return type of the block is `bool` which seems like what the user wanted. | |
256 | let scrutinee = self.lower_expr(scrutinee); | |
257 | let then_arm = { | |
258 | let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); | |
259 | let expr = self.expr_bool(span, true); | |
260 | self.arm(pats, P(expr)) | |
261 | }; | |
262 | let else_arm = { | |
263 | let pats = hir_vec![self.pat_wild(span)]; | |
264 | let expr = self.expr_bool(span, false); | |
265 | self.arm(pats, P(expr)) | |
266 | }; | |
267 | hir::ExprKind::Match( | |
268 | P(scrutinee), | |
269 | vec![then_arm, else_arm].into(), | |
270 | hir::MatchSource::Normal, | |
271 | ) | |
272 | } | |
273 | ||
274 | fn lower_expr_if( | |
275 | &mut self, | |
276 | span: Span, | |
277 | cond: &Expr, | |
278 | then: &Block, | |
279 | else_opt: Option<&Expr>, | |
280 | ) -> hir::ExprKind { | |
281 | // FIXME(#53667): handle lowering of && and parens. | |
282 | ||
283 | // `_ => else_block` where `else_block` is `{}` if there's `None`: | |
284 | let else_pat = self.pat_wild(span); | |
285 | let (else_expr, contains_else_clause) = match else_opt { | |
286 | None => (self.expr_block_empty(span), false), | |
287 | Some(els) => (self.lower_expr(els), true), | |
288 | }; | |
289 | let else_arm = self.arm(hir_vec![else_pat], P(else_expr)); | |
290 | ||
291 | // Handle then + scrutinee: | |
292 | let then_blk = self.lower_block(then, false); | |
293 | let then_expr = self.expr_block(then_blk, ThinVec::new()); | |
294 | let (then_pats, scrutinee, desugar) = match cond.node { | |
295 | // `<pat> => <then>`: | |
296 | ExprKind::Let(ref pats, ref scrutinee) => { | |
297 | let scrutinee = self.lower_expr(scrutinee); | |
298 | let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); | |
299 | let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause }; | |
300 | (pats, scrutinee, desugar) | |
301 | } | |
302 | // `true => <then>`: | |
303 | _ => { | |
304 | // Lower condition: | |
305 | let cond = self.lower_expr(cond); | |
306 | let span_block = self.mark_span_with_reason( | |
307 | DesugaringKind::CondTemporary, | |
308 | cond.span, | |
309 | None | |
310 | ); | |
311 | // Wrap in a construct equivalent to `{ let _t = $cond; _t }` | |
312 | // to preserve drop semantics since `if cond { ... }` does not | |
313 | // let temporaries live outside of `cond`. | |
314 | let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new()); | |
315 | ||
316 | let desugar = hir::MatchSource::IfDesugar { contains_else_clause }; | |
317 | let pats = hir_vec![self.pat_bool(span, true)]; | |
318 | (pats, cond, desugar) | |
319 | } | |
320 | }; | |
321 | let then_arm = self.arm(then_pats, P(then_expr)); | |
322 | ||
323 | hir::ExprKind::Match(P(scrutinee), vec![then_arm, else_arm].into(), desugar) | |
324 | } | |
325 | ||
326 | fn lower_expr_while_in_loop_scope( | |
327 | &mut self, | |
328 | span: Span, | |
329 | cond: &Expr, | |
330 | body: &Block, | |
331 | opt_label: Option<Label> | |
332 | ) -> hir::ExprKind { | |
333 | // FIXME(#53667): handle lowering of && and parens. | |
334 | ||
335 | // Note that the block AND the condition are evaluated in the loop scope. | |
336 | // This is done to allow `break` from inside the condition of the loop. | |
337 | ||
338 | // `_ => break`: | |
339 | let else_arm = { | |
340 | let else_pat = self.pat_wild(span); | |
341 | let else_expr = self.expr_break(span, ThinVec::new()); | |
342 | self.arm(hir_vec![else_pat], else_expr) | |
343 | }; | |
344 | ||
345 | // Handle then + scrutinee: | |
346 | let then_blk = self.lower_block(body, false); | |
347 | let then_expr = self.expr_block(then_blk, ThinVec::new()); | |
348 | let (then_pats, scrutinee, desugar, source) = match cond.node { | |
349 | ExprKind::Let(ref pats, ref scrutinee) => { | |
350 | // to: | |
351 | // | |
352 | // [opt_ident]: loop { | |
353 | // match <sub_expr> { | |
354 | // <pat> => <body>, | |
355 | // _ => break | |
356 | // } | |
357 | // } | |
358 | let scrutinee = self.with_loop_condition_scope(|t| t.lower_expr(scrutinee)); | |
359 | let pats = pats.iter().map(|pat| self.lower_pat(pat)).collect(); | |
360 | let desugar = hir::MatchSource::WhileLetDesugar; | |
361 | (pats, scrutinee, desugar, hir::LoopSource::WhileLet) | |
362 | } | |
363 | _ => { | |
364 | // We desugar: `'label: while $cond $body` into: | |
365 | // | |
366 | // ``` | |
367 | // 'label: loop { | |
368 | // match DropTemps($cond) { | |
369 | // true => $body, | |
370 | // _ => break, | |
371 | // } | |
372 | // } | |
373 | // ``` | |
374 | ||
375 | // Lower condition: | |
376 | let cond = self.with_loop_condition_scope(|this| this.lower_expr(cond)); | |
377 | let span_block = self.mark_span_with_reason( | |
378 | DesugaringKind::CondTemporary, | |
379 | cond.span, | |
380 | None, | |
381 | ); | |
382 | // Wrap in a construct equivalent to `{ let _t = $cond; _t }` | |
383 | // to preserve drop semantics since `while cond { ... }` does not | |
384 | // let temporaries live outside of `cond`. | |
385 | let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new()); | |
386 | ||
387 | let desugar = hir::MatchSource::WhileDesugar; | |
388 | // `true => <then>`: | |
389 | let pats = hir_vec![self.pat_bool(span, true)]; | |
390 | (pats, cond, desugar, hir::LoopSource::While) | |
391 | } | |
392 | }; | |
393 | let then_arm = self.arm(then_pats, P(then_expr)); | |
394 | ||
395 | // `match <scrutinee> { ... }` | |
396 | let match_expr = self.expr_match( | |
397 | scrutinee.span, | |
398 | P(scrutinee), | |
399 | hir_vec![then_arm, else_arm], | |
400 | desugar, | |
401 | ); | |
402 | ||
403 | // `[opt_ident]: loop { ... }` | |
404 | hir::ExprKind::Loop( | |
405 | P(self.block_expr(P(match_expr))), | |
406 | self.lower_label(opt_label), | |
407 | source | |
408 | ) | |
409 | } | |
410 | ||
411 | fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind { | |
412 | self.with_catch_scope(body.id, |this| { | |
413 | let unstable_span = this.mark_span_with_reason( | |
414 | DesugaringKind::TryBlock, | |
415 | body.span, | |
416 | this.allow_try_trait.clone(), | |
417 | ); | |
418 | let mut block = this.lower_block(body, true).into_inner(); | |
419 | let tail = block.expr.take().map_or_else( | |
420 | || this.expr_unit(this.sess.source_map().end_point(unstable_span)), | |
421 | |x: P<hir::Expr>| x.into_inner(), | |
422 | ); | |
423 | block.expr = Some(this.wrap_in_try_constructor(sym::from_ok, tail, unstable_span)); | |
424 | hir::ExprKind::Block(P(block), None) | |
425 | }) | |
426 | } | |
427 | ||
428 | fn wrap_in_try_constructor( | |
429 | &mut self, | |
430 | method: Symbol, | |
431 | e: hir::Expr, | |
432 | unstable_span: Span, | |
433 | ) -> P<hir::Expr> { | |
434 | let path = &[sym::ops, sym::Try, method]; | |
435 | let from_err = P(self.expr_std_path(unstable_span, path, None, ThinVec::new())); | |
436 | P(self.expr_call(e.span, from_err, hir_vec![e])) | |
437 | } | |
438 | ||
439 | fn lower_arm(&mut self, arm: &Arm) -> hir::Arm { | |
440 | hir::Arm { | |
441 | hir_id: self.next_id(), | |
442 | attrs: self.lower_attrs(&arm.attrs), | |
443 | pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(), | |
444 | guard: match arm.guard { | |
445 | Some(ref x) => Some(hir::Guard::If(P(self.lower_expr(x)))), | |
446 | _ => None, | |
447 | }, | |
448 | body: P(self.lower_expr(&arm.body)), | |
449 | span: arm.span, | |
450 | } | |
451 | } | |
452 | ||
453 | pub(super) fn make_async_expr( | |
454 | &mut self, | |
455 | capture_clause: CaptureBy, | |
456 | closure_node_id: NodeId, | |
457 | ret_ty: Option<AstP<Ty>>, | |
458 | span: Span, | |
459 | body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr, | |
460 | ) -> hir::ExprKind { | |
461 | let capture_clause = self.lower_capture_clause(capture_clause); | |
462 | let output = match ret_ty { | |
463 | Some(ty) => FunctionRetTy::Ty(ty), | |
464 | None => FunctionRetTy::Default(span), | |
465 | }; | |
466 | let ast_decl = FnDecl { | |
467 | inputs: vec![], | |
468 | output, | |
469 | c_variadic: false | |
470 | }; | |
471 | let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None); | |
472 | let body_id = self.lower_fn_body(&ast_decl, |this| { | |
473 | this.generator_kind = Some(hir::GeneratorKind::Async); | |
474 | body(this) | |
475 | }); | |
476 | ||
477 | // `static || -> <ret_ty> { body }`: | |
478 | let generator_node = hir::ExprKind::Closure( | |
479 | capture_clause, | |
480 | decl, | |
481 | body_id, | |
482 | span, | |
483 | Some(hir::GeneratorMovability::Static) | |
484 | ); | |
485 | let generator = hir::Expr { | |
486 | hir_id: self.lower_node_id(closure_node_id), | |
487 | node: generator_node, | |
488 | span, | |
489 | attrs: ThinVec::new(), | |
490 | }; | |
491 | ||
492 | // `future::from_generator`: | |
493 | let unstable_span = self.mark_span_with_reason( | |
494 | DesugaringKind::Async, | |
495 | span, | |
496 | self.allow_gen_future.clone(), | |
497 | ); | |
498 | let gen_future = self.expr_std_path( | |
499 | unstable_span, | |
500 | &[sym::future, sym::from_generator], | |
501 | None, | |
502 | ThinVec::new() | |
503 | ); | |
504 | ||
505 | // `future::from_generator(generator)`: | |
506 | hir::ExprKind::Call(P(gen_future), hir_vec![generator]) | |
507 | } | |
508 | ||
509 | /// Desugar `<expr>.await` into: | |
510 | /// ```rust | |
511 | /// { | |
512 | /// let mut pinned = <expr>; | |
513 | /// loop { | |
514 | /// match ::std::future::poll_with_tls_context(unsafe { | |
515 | /// ::std::pin::Pin::new_unchecked(&mut pinned) | |
516 | /// }) { | |
517 | /// ::std::task::Poll::Ready(result) => break result, | |
518 | /// ::std::task::Poll::Pending => {}, | |
519 | /// } | |
520 | /// yield (); | |
521 | /// } | |
522 | /// } | |
523 | /// ``` | |
524 | fn lower_expr_await(&mut self, await_span: Span, expr: &Expr) -> hir::ExprKind { | |
525 | match self.generator_kind { | |
526 | Some(hir::GeneratorKind::Async) => {}, | |
527 | Some(hir::GeneratorKind::Gen) | | |
528 | None => { | |
529 | let mut err = struct_span_err!( | |
530 | self.sess, | |
531 | await_span, | |
532 | E0728, | |
533 | "`await` is only allowed inside `async` functions and blocks" | |
534 | ); | |
535 | err.span_label(await_span, "only allowed inside `async` functions and blocks"); | |
536 | if let Some(item_sp) = self.current_item { | |
537 | err.span_label(item_sp, "this is not `async`"); | |
538 | } | |
539 | err.emit(); | |
540 | } | |
541 | } | |
542 | let span = self.mark_span_with_reason( | |
543 | DesugaringKind::Await, | |
544 | await_span, | |
545 | None, | |
546 | ); | |
547 | let gen_future_span = self.mark_span_with_reason( | |
548 | DesugaringKind::Await, | |
549 | await_span, | |
550 | self.allow_gen_future.clone(), | |
551 | ); | |
552 | ||
553 | // let mut pinned = <expr>; | |
554 | let expr = P(self.lower_expr(expr)); | |
555 | let pinned_ident = Ident::with_empty_ctxt(sym::pinned); | |
556 | let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode( | |
557 | span, | |
558 | pinned_ident, | |
559 | hir::BindingAnnotation::Mutable, | |
560 | ); | |
561 | let pinned_let = self.stmt_let_pat( | |
562 | ThinVec::new(), | |
563 | span, | |
564 | Some(expr), | |
565 | pinned_pat, | |
566 | hir::LocalSource::AwaitDesugar, | |
567 | ); | |
568 | ||
569 | // ::std::future::poll_with_tls_context(unsafe { | |
570 | // ::std::pin::Pin::new_unchecked(&mut pinned) | |
571 | // })` | |
572 | let poll_expr = { | |
573 | let pinned = P(self.expr_ident(span, pinned_ident, pinned_pat_hid)); | |
574 | let ref_mut_pinned = self.expr_mut_addr_of(span, pinned); | |
575 | let pin_ty_id = self.next_id(); | |
576 | let new_unchecked_expr_kind = self.expr_call_std_assoc_fn( | |
577 | pin_ty_id, | |
578 | span, | |
579 | &[sym::pin, sym::Pin], | |
580 | "new_unchecked", | |
581 | hir_vec![ref_mut_pinned], | |
582 | ); | |
583 | let new_unchecked = P(self.expr(span, new_unchecked_expr_kind, ThinVec::new())); | |
584 | let unsafe_expr = self.expr_unsafe(new_unchecked); | |
585 | P(self.expr_call_std_path( | |
586 | gen_future_span, | |
587 | &[sym::future, sym::poll_with_tls_context], | |
588 | hir_vec![unsafe_expr], | |
589 | )) | |
590 | }; | |
591 | ||
592 | // `::std::task::Poll::Ready(result) => break result` | |
593 | let loop_node_id = self.sess.next_node_id(); | |
594 | let loop_hir_id = self.lower_node_id(loop_node_id); | |
595 | let ready_arm = { | |
596 | let x_ident = Ident::with_empty_ctxt(sym::result); | |
597 | let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident); | |
598 | let x_expr = P(self.expr_ident(span, x_ident, x_pat_hid)); | |
599 | let ready_pat = self.pat_std_enum( | |
600 | span, | |
601 | &[sym::task, sym::Poll, sym::Ready], | |
602 | hir_vec![x_pat], | |
603 | ); | |
604 | let break_x = self.with_loop_scope(loop_node_id, |this| { | |
605 | let expr_break = hir::ExprKind::Break( | |
606 | this.lower_loop_destination(None), | |
607 | Some(x_expr), | |
608 | ); | |
609 | P(this.expr(await_span, expr_break, ThinVec::new())) | |
610 | }); | |
611 | self.arm(hir_vec![ready_pat], break_x) | |
612 | }; | |
613 | ||
614 | // `::std::task::Poll::Pending => {}` | |
615 | let pending_arm = { | |
616 | let pending_pat = self.pat_std_enum( | |
617 | span, | |
618 | &[sym::task, sym::Poll, sym::Pending], | |
619 | hir_vec![], | |
620 | ); | |
621 | let empty_block = P(self.expr_block_empty(span)); | |
622 | self.arm(hir_vec![pending_pat], empty_block) | |
623 | }; | |
624 | ||
625 | let match_stmt = { | |
626 | let match_expr = self.expr_match( | |
627 | span, | |
628 | poll_expr, | |
629 | hir_vec![ready_arm, pending_arm], | |
630 | hir::MatchSource::AwaitDesugar, | |
631 | ); | |
632 | self.stmt_expr(span, match_expr) | |
633 | }; | |
634 | ||
635 | let yield_stmt = { | |
636 | let unit = self.expr_unit(span); | |
637 | let yield_expr = self.expr( | |
638 | span, | |
639 | hir::ExprKind::Yield(P(unit), hir::YieldSource::Await), | |
640 | ThinVec::new(), | |
641 | ); | |
642 | self.stmt_expr(span, yield_expr) | |
643 | }; | |
644 | ||
645 | let loop_block = P(self.block_all( | |
646 | span, | |
647 | hir_vec![match_stmt, yield_stmt], | |
648 | None, | |
649 | )); | |
650 | ||
651 | let loop_expr = P(hir::Expr { | |
652 | hir_id: loop_hir_id, | |
653 | node: hir::ExprKind::Loop( | |
654 | loop_block, | |
655 | None, | |
656 | hir::LoopSource::Loop, | |
657 | ), | |
658 | span, | |
659 | attrs: ThinVec::new(), | |
660 | }); | |
661 | ||
662 | hir::ExprKind::Block( | |
663 | P(self.block_all(span, hir_vec![pinned_let], Some(loop_expr))), | |
664 | None, | |
665 | ) | |
666 | } | |
667 | ||
668 | fn lower_expr_closure( | |
669 | &mut self, | |
670 | capture_clause: CaptureBy, | |
671 | movability: Movability, | |
672 | decl: &FnDecl, | |
673 | body: &Expr, | |
674 | fn_decl_span: Span, | |
675 | ) -> hir::ExprKind { | |
676 | // Lower outside new scope to preserve `is_in_loop_condition`. | |
677 | let fn_decl = self.lower_fn_decl(decl, None, false, None); | |
678 | ||
679 | self.with_new_scopes(|this| { | |
680 | this.current_item = Some(fn_decl_span); | |
681 | let mut generator_kind = None; | |
682 | let body_id = this.lower_fn_body(decl, |this| { | |
683 | let e = this.lower_expr(body); | |
684 | generator_kind = this.generator_kind; | |
685 | e | |
686 | }); | |
687 | let generator_option = this.generator_movability_for_fn( | |
688 | &decl, | |
689 | fn_decl_span, | |
690 | generator_kind, | |
691 | movability, | |
692 | ); | |
693 | hir::ExprKind::Closure( | |
694 | this.lower_capture_clause(capture_clause), | |
695 | fn_decl, | |
696 | body_id, | |
697 | fn_decl_span, | |
698 | generator_option, | |
699 | ) | |
700 | }) | |
701 | } | |
702 | ||
703 | fn lower_capture_clause(&mut self, c: CaptureBy) -> hir::CaptureClause { | |
704 | match c { | |
705 | CaptureBy::Value => hir::CaptureByValue, | |
706 | CaptureBy::Ref => hir::CaptureByRef, | |
707 | } | |
708 | } | |
709 | ||
710 | fn generator_movability_for_fn( | |
711 | &mut self, | |
712 | decl: &FnDecl, | |
713 | fn_decl_span: Span, | |
714 | generator_kind: Option<hir::GeneratorKind>, | |
715 | movability: Movability, | |
716 | ) -> Option<hir::GeneratorMovability> { | |
717 | match generator_kind { | |
718 | Some(hir::GeneratorKind::Gen) => { | |
719 | if !decl.inputs.is_empty() { | |
720 | span_err!( | |
721 | self.sess, | |
722 | fn_decl_span, | |
723 | E0628, | |
724 | "generators cannot have explicit arguments" | |
725 | ); | |
726 | self.sess.abort_if_errors(); | |
727 | } | |
728 | Some(match movability { | |
729 | Movability::Movable => hir::GeneratorMovability::Movable, | |
730 | Movability::Static => hir::GeneratorMovability::Static, | |
731 | }) | |
732 | }, | |
733 | Some(hir::GeneratorKind::Async) => { | |
734 | bug!("non-`async` closure body turned `async` during lowering"); | |
735 | }, | |
736 | None => { | |
737 | if movability == Movability::Static { | |
738 | span_err!( | |
739 | self.sess, | |
740 | fn_decl_span, | |
741 | E0697, | |
742 | "closures cannot be static" | |
743 | ); | |
744 | } | |
745 | None | |
746 | }, | |
747 | } | |
748 | } | |
749 | ||
750 | fn lower_expr_async_closure( | |
751 | &mut self, | |
752 | capture_clause: CaptureBy, | |
753 | closure_id: NodeId, | |
754 | decl: &FnDecl, | |
755 | body: &Expr, | |
756 | fn_decl_span: Span, | |
757 | ) -> hir::ExprKind { | |
758 | let outer_decl = FnDecl { | |
759 | inputs: decl.inputs.clone(), | |
760 | output: FunctionRetTy::Default(fn_decl_span), | |
761 | c_variadic: false, | |
762 | }; | |
763 | // We need to lower the declaration outside the new scope, because we | |
764 | // have to conserve the state of being inside a loop condition for the | |
765 | // closure argument types. | |
766 | let fn_decl = self.lower_fn_decl(&outer_decl, None, false, None); | |
767 | ||
768 | self.with_new_scopes(|this| { | |
769 | // FIXME(cramertj): allow `async` non-`move` closures with arguments. | |
770 | if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() { | |
771 | struct_span_err!( | |
772 | this.sess, | |
773 | fn_decl_span, | |
774 | E0708, | |
775 | "`async` non-`move` closures with arguments are not currently supported", | |
776 | ) | |
777 | .help( | |
778 | "consider using `let` statements to manually capture \ | |
779 | variables by reference before entering an `async move` closure" | |
780 | ) | |
781 | .emit(); | |
782 | } | |
783 | ||
784 | // Transform `async |x: u8| -> X { ... }` into | |
785 | // `|x: u8| future_from_generator(|| -> X { ... })`. | |
786 | let body_id = this.lower_fn_body(&outer_decl, |this| { | |
787 | let async_ret_ty = if let FunctionRetTy::Ty(ty) = &decl.output { | |
788 | Some(ty.clone()) | |
789 | } else { | |
790 | None | |
791 | }; | |
792 | let async_body = this.make_async_expr( | |
793 | capture_clause, closure_id, async_ret_ty, body.span, | |
794 | |this| { | |
795 | this.with_new_scopes(|this| this.lower_expr(body)) | |
796 | } | |
797 | ); | |
798 | this.expr(fn_decl_span, async_body, ThinVec::new()) | |
799 | }); | |
800 | hir::ExprKind::Closure( | |
801 | this.lower_capture_clause(capture_clause), | |
802 | fn_decl, | |
803 | body_id, | |
804 | fn_decl_span, | |
805 | None, | |
806 | ) | |
807 | }) | |
808 | } | |
809 | ||
810 | /// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`. | |
811 | fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind { | |
812 | let id = self.next_id(); | |
813 | let e1 = self.lower_expr(e1); | |
814 | let e2 = self.lower_expr(e2); | |
815 | self.expr_call_std_assoc_fn( | |
816 | id, | |
817 | span, | |
818 | &[sym::ops, sym::RangeInclusive], | |
819 | "new", | |
820 | hir_vec![e1, e2], | |
821 | ) | |
822 | } | |
823 | ||
824 | fn lower_expr_range( | |
825 | &mut self, | |
826 | span: Span, | |
827 | e1: Option<&Expr>, | |
828 | e2: Option<&Expr>, | |
829 | lims: RangeLimits, | |
830 | ) -> hir::ExprKind { | |
831 | use syntax::ast::RangeLimits::*; | |
832 | ||
833 | let path = match (e1, e2, lims) { | |
834 | (None, None, HalfOpen) => sym::RangeFull, | |
835 | (Some(..), None, HalfOpen) => sym::RangeFrom, | |
836 | (None, Some(..), HalfOpen) => sym::RangeTo, | |
837 | (Some(..), Some(..), HalfOpen) => sym::Range, | |
838 | (None, Some(..), Closed) => sym::RangeToInclusive, | |
839 | (Some(..), Some(..), Closed) => unreachable!(), | |
840 | (_, None, Closed) => self.diagnostic() | |
841 | .span_fatal(span, "inclusive range with no end") | |
842 | .raise(), | |
843 | }; | |
844 | ||
845 | let fields = e1.iter() | |
846 | .map(|e| ("start", e)) | |
847 | .chain(e2.iter().map(|e| ("end", e))) | |
848 | .map(|(s, e)| { | |
849 | let expr = P(self.lower_expr(&e)); | |
850 | let ident = Ident::new(Symbol::intern(s), e.span); | |
851 | self.field(ident, expr, e.span) | |
852 | }) | |
853 | .collect::<P<[hir::Field]>>(); | |
854 | ||
855 | let is_unit = fields.is_empty(); | |
856 | let struct_path = [sym::ops, path]; | |
857 | let struct_path = self.std_path(span, &struct_path, None, is_unit); | |
858 | let struct_path = hir::QPath::Resolved(None, P(struct_path)); | |
859 | ||
860 | if is_unit { | |
861 | hir::ExprKind::Path(struct_path) | |
862 | } else { | |
863 | hir::ExprKind::Struct(P(struct_path), fields, None) | |
864 | } | |
865 | } | |
866 | ||
867 | fn lower_label(&mut self, label: Option<Label>) -> Option<hir::Label> { | |
868 | label.map(|label| hir::Label { | |
869 | ident: label.ident, | |
870 | }) | |
871 | } | |
872 | ||
873 | fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination { | |
874 | let target_id = match destination { | |
875 | Some((id, _)) => { | |
876 | if let Some(loop_id) = self.resolver.get_label_res(id) { | |
877 | Ok(self.lower_node_id(loop_id)) | |
878 | } else { | |
879 | Err(hir::LoopIdError::UnresolvedLabel) | |
880 | } | |
881 | } | |
882 | None => { | |
883 | self.loop_scopes | |
884 | .last() | |
885 | .cloned() | |
886 | .map(|id| Ok(self.lower_node_id(id))) | |
887 | .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)) | |
888 | .into() | |
889 | } | |
890 | }; | |
891 | hir::Destination { | |
892 | label: self.lower_label(destination.map(|(_, label)| label)), | |
893 | target_id, | |
894 | } | |
895 | } | |
896 | ||
897 | fn lower_jump_destination(&mut self, id: NodeId, opt_label: Option<Label>) -> hir::Destination { | |
898 | if self.is_in_loop_condition && opt_label.is_none() { | |
899 | hir::Destination { | |
900 | label: None, | |
901 | target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(), | |
902 | } | |
903 | } else { | |
904 | self.lower_loop_destination(opt_label.map(|label| (id, label))) | |
905 | } | |
906 | } | |
907 | ||
908 | fn with_catch_scope<T, F>(&mut self, catch_id: NodeId, f: F) -> T | |
909 | where | |
910 | F: FnOnce(&mut LoweringContext<'_>) -> T, | |
911 | { | |
912 | let len = self.catch_scopes.len(); | |
913 | self.catch_scopes.push(catch_id); | |
914 | ||
915 | let result = f(self); | |
916 | assert_eq!( | |
917 | len + 1, | |
918 | self.catch_scopes.len(), | |
919 | "catch scopes should be added and removed in stack order" | |
920 | ); | |
921 | ||
922 | self.catch_scopes.pop().unwrap(); | |
923 | ||
924 | result | |
925 | } | |
926 | ||
927 | fn with_loop_scope<T, F>(&mut self, loop_id: NodeId, f: F) -> T | |
928 | where | |
929 | F: FnOnce(&mut LoweringContext<'_>) -> T, | |
930 | { | |
931 | // We're no longer in the base loop's condition; we're in another loop. | |
932 | let was_in_loop_condition = self.is_in_loop_condition; | |
933 | self.is_in_loop_condition = false; | |
934 | ||
935 | let len = self.loop_scopes.len(); | |
936 | self.loop_scopes.push(loop_id); | |
937 | ||
938 | let result = f(self); | |
939 | assert_eq!( | |
940 | len + 1, | |
941 | self.loop_scopes.len(), | |
942 | "loop scopes should be added and removed in stack order" | |
943 | ); | |
944 | ||
945 | self.loop_scopes.pop().unwrap(); | |
946 | ||
947 | self.is_in_loop_condition = was_in_loop_condition; | |
948 | ||
949 | result | |
950 | } | |
951 | ||
952 | fn with_loop_condition_scope<T, F>(&mut self, f: F) -> T | |
953 | where | |
954 | F: FnOnce(&mut LoweringContext<'_>) -> T, | |
955 | { | |
956 | let was_in_loop_condition = self.is_in_loop_condition; | |
957 | self.is_in_loop_condition = true; | |
958 | ||
959 | let result = f(self); | |
960 | ||
961 | self.is_in_loop_condition = was_in_loop_condition; | |
962 | ||
963 | result | |
964 | } | |
965 | ||
966 | fn lower_expr_asm(&mut self, asm: &InlineAsm) -> hir::ExprKind { | |
967 | let hir_asm = hir::InlineAsm { | |
968 | inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(), | |
969 | outputs: asm.outputs | |
970 | .iter() | |
971 | .map(|out| hir::InlineAsmOutput { | |
972 | constraint: out.constraint.clone(), | |
973 | is_rw: out.is_rw, | |
974 | is_indirect: out.is_indirect, | |
975 | span: out.expr.span, | |
976 | }) | |
977 | .collect(), | |
978 | asm: asm.asm.clone(), | |
979 | asm_str_style: asm.asm_str_style, | |
980 | clobbers: asm.clobbers.clone().into(), | |
981 | volatile: asm.volatile, | |
982 | alignstack: asm.alignstack, | |
983 | dialect: asm.dialect, | |
984 | ctxt: asm.ctxt, | |
985 | }; | |
986 | ||
987 | let outputs = asm.outputs | |
988 | .iter() | |
989 | .map(|out| self.lower_expr(&out.expr)) | |
990 | .collect(); | |
991 | ||
992 | let inputs = asm.inputs | |
993 | .iter() | |
994 | .map(|&(_, ref input)| self.lower_expr(input)) | |
995 | .collect(); | |
996 | ||
997 | hir::ExprKind::InlineAsm(P(hir_asm), outputs, inputs) | |
998 | } | |
999 | ||
1000 | fn lower_field(&mut self, f: &Field) -> hir::Field { | |
1001 | hir::Field { | |
1002 | hir_id: self.next_id(), | |
1003 | ident: f.ident, | |
1004 | expr: P(self.lower_expr(&f.expr)), | |
1005 | span: f.span, | |
1006 | is_shorthand: f.is_shorthand, | |
1007 | } | |
1008 | } | |
1009 | ||
1010 | fn lower_expr_yield(&mut self, span: Span, opt_expr: Option<&Expr>) -> hir::ExprKind { | |
1011 | match self.generator_kind { | |
1012 | Some(hir::GeneratorKind::Gen) => {}, | |
1013 | Some(hir::GeneratorKind::Async) => { | |
1014 | span_err!( | |
1015 | self.sess, | |
1016 | span, | |
1017 | E0727, | |
1018 | "`async` generators are not yet supported", | |
1019 | ); | |
1020 | self.sess.abort_if_errors(); | |
1021 | }, | |
1022 | None => self.generator_kind = Some(hir::GeneratorKind::Gen), | |
1023 | } | |
1024 | ||
1025 | let expr = opt_expr | |
1026 | .as_ref() | |
1027 | .map(|x| self.lower_expr(x)) | |
1028 | .unwrap_or_else(|| self.expr_unit(span)); | |
1029 | ||
1030 | hir::ExprKind::Yield(P(expr), hir::YieldSource::Yield) | |
1031 | } | |
1032 | ||
1033 | /// Desugar `ExprForLoop` from: `[opt_ident]: for <pat> in <head> <body>` into: | |
1034 | /// ```rust | |
1035 | /// { | |
1036 | /// let result = match ::std::iter::IntoIterator::into_iter(<head>) { | |
1037 | /// mut iter => { | |
1038 | /// [opt_ident]: loop { | |
1039 | /// let mut __next; | |
1040 | /// match ::std::iter::Iterator::next(&mut iter) { | |
1041 | /// ::std::option::Option::Some(val) => __next = val, | |
1042 | /// ::std::option::Option::None => break | |
1043 | /// }; | |
1044 | /// let <pat> = __next; | |
1045 | /// StmtKind::Expr(<body>); | |
1046 | /// } | |
1047 | /// } | |
1048 | /// }; | |
1049 | /// result | |
1050 | /// } | |
1051 | /// ``` | |
1052 | fn lower_expr_for( | |
1053 | &mut self, | |
1054 | e: &Expr, | |
1055 | pat: &Pat, | |
1056 | head: &Expr, | |
1057 | body: &Block, | |
1058 | opt_label: Option<Label>, | |
1059 | ) -> hir::Expr { | |
1060 | // expand <head> | |
1061 | let mut head = self.lower_expr(head); | |
1062 | let head_sp = head.span; | |
1063 | let desugared_span = self.mark_span_with_reason( | |
1064 | DesugaringKind::ForLoop, | |
1065 | head_sp, | |
1066 | None, | |
1067 | ); | |
1068 | head.span = desugared_span; | |
1069 | ||
1070 | let iter = Ident::with_empty_ctxt(sym::iter); | |
1071 | ||
1072 | let next_ident = Ident::with_empty_ctxt(sym::__next); | |
1073 | let (next_pat, next_pat_hid) = self.pat_ident_binding_mode( | |
1074 | desugared_span, | |
1075 | next_ident, | |
1076 | hir::BindingAnnotation::Mutable, | |
1077 | ); | |
1078 | ||
1079 | // `::std::option::Option::Some(val) => __next = val` | |
1080 | let pat_arm = { | |
1081 | let val_ident = Ident::with_empty_ctxt(sym::val); | |
1082 | let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident); | |
1083 | let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid)); | |
1084 | let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid)); | |
1085 | let assign = P(self.expr( | |
1086 | pat.span, | |
1087 | hir::ExprKind::Assign(next_expr, val_expr), | |
1088 | ThinVec::new(), | |
1089 | )); | |
1090 | let some_pat = self.pat_some(pat.span, val_pat); | |
1091 | self.arm(hir_vec![some_pat], assign) | |
1092 | }; | |
1093 | ||
1094 | // `::std::option::Option::None => break` | |
1095 | let break_arm = { | |
1096 | let break_expr = | |
1097 | self.with_loop_scope(e.id, |this| this.expr_break(e.span, ThinVec::new())); | |
1098 | let pat = self.pat_none(e.span); | |
1099 | self.arm(hir_vec![pat], break_expr) | |
1100 | }; | |
1101 | ||
1102 | // `mut iter` | |
1103 | let (iter_pat, iter_pat_nid) = self.pat_ident_binding_mode( | |
1104 | desugared_span, | |
1105 | iter, | |
1106 | hir::BindingAnnotation::Mutable | |
1107 | ); | |
1108 | ||
1109 | // `match ::std::iter::Iterator::next(&mut iter) { ... }` | |
1110 | let match_expr = { | |
1111 | let iter = P(self.expr_ident(head_sp, iter, iter_pat_nid)); | |
1112 | let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter); | |
1113 | let next_path = &[sym::iter, sym::Iterator, sym::next]; | |
1114 | let next_expr = P(self.expr_call_std_path( | |
1115 | head_sp, | |
1116 | next_path, | |
1117 | hir_vec![ref_mut_iter], | |
1118 | )); | |
1119 | let arms = hir_vec![pat_arm, break_arm]; | |
1120 | ||
1121 | self.expr_match(head_sp, next_expr, arms, hir::MatchSource::ForLoopDesugar) | |
1122 | }; | |
1123 | let match_stmt = self.stmt_expr(head_sp, match_expr); | |
1124 | ||
1125 | let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid)); | |
1126 | ||
1127 | // `let mut __next` | |
1128 | let next_let = self.stmt_let_pat( | |
1129 | ThinVec::new(), | |
1130 | desugared_span, | |
1131 | None, | |
1132 | next_pat, | |
1133 | hir::LocalSource::ForLoopDesugar, | |
1134 | ); | |
1135 | ||
1136 | // `let <pat> = __next` | |
1137 | let pat = self.lower_pat(pat); | |
1138 | let pat_let = self.stmt_let_pat( | |
1139 | ThinVec::new(), | |
1140 | head_sp, | |
1141 | Some(next_expr), | |
1142 | pat, | |
1143 | hir::LocalSource::ForLoopDesugar, | |
1144 | ); | |
1145 | ||
1146 | let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false)); | |
1147 | let body_expr = self.expr_block(body_block, ThinVec::new()); | |
1148 | let body_stmt = self.stmt_expr(body.span, body_expr); | |
1149 | ||
1150 | let loop_block = P(self.block_all( | |
1151 | e.span, | |
1152 | hir_vec![next_let, match_stmt, pat_let, body_stmt], | |
1153 | None, | |
1154 | )); | |
1155 | ||
1156 | // `[opt_ident]: loop { ... }` | |
1157 | let loop_expr = hir::ExprKind::Loop( | |
1158 | loop_block, | |
1159 | self.lower_label(opt_label), | |
1160 | hir::LoopSource::ForLoop, | |
1161 | ); | |
1162 | let loop_expr = P(hir::Expr { | |
1163 | hir_id: self.lower_node_id(e.id), | |
1164 | node: loop_expr, | |
1165 | span: e.span, | |
1166 | attrs: ThinVec::new(), | |
1167 | }); | |
1168 | ||
1169 | // `mut iter => { ... }` | |
1170 | let iter_arm = self.arm(hir_vec![iter_pat], loop_expr); | |
1171 | ||
1172 | // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }` | |
1173 | let into_iter_expr = { | |
1174 | let into_iter_path = | |
1175 | &[sym::iter, sym::IntoIterator, sym::into_iter]; | |
1176 | P(self.expr_call_std_path( | |
1177 | head_sp, | |
1178 | into_iter_path, | |
1179 | hir_vec![head], | |
1180 | )) | |
1181 | }; | |
1182 | ||
1183 | let match_expr = P(self.expr_match( | |
1184 | head_sp, | |
1185 | into_iter_expr, | |
1186 | hir_vec![iter_arm], | |
1187 | hir::MatchSource::ForLoopDesugar, | |
1188 | )); | |
1189 | ||
1190 | // This is effectively `{ let _result = ...; _result }`. | |
1191 | // The construct was introduced in #21984 and is necessary to make sure that | |
1192 | // temporaries in the `head` expression are dropped and do not leak to the | |
1193 | // surrounding scope of the `match` since the `match` is not a terminating scope. | |
1194 | // | |
1195 | // Also, add the attributes to the outer returned expr node. | |
1196 | self.expr_drop_temps(head_sp, match_expr, e.attrs.clone()) | |
1197 | } | |
1198 | ||
1199 | /// Desugar `ExprKind::Try` from: `<expr>?` into: | |
1200 | /// ```rust | |
1201 | /// match Try::into_result(<expr>) { | |
1202 | /// Ok(val) => #[allow(unreachable_code)] val, | |
1203 | /// Err(err) => #[allow(unreachable_code)] | |
1204 | /// // If there is an enclosing `try {...}`: | |
1205 | /// break 'catch_target Try::from_error(From::from(err)), | |
1206 | /// // Otherwise: | |
1207 | /// return Try::from_error(From::from(err)), | |
1208 | /// } | |
1209 | /// ``` | |
1210 | fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind { | |
1211 | let unstable_span = self.mark_span_with_reason( | |
1212 | DesugaringKind::QuestionMark, | |
1213 | span, | |
1214 | self.allow_try_trait.clone(), | |
1215 | ); | |
1216 | let try_span = self.sess.source_map().end_point(span); | |
1217 | let try_span = self.mark_span_with_reason( | |
1218 | DesugaringKind::QuestionMark, | |
1219 | try_span, | |
1220 | self.allow_try_trait.clone(), | |
1221 | ); | |
1222 | ||
1223 | // `Try::into_result(<expr>)` | |
1224 | let scrutinee = { | |
1225 | // expand <expr> | |
1226 | let sub_expr = self.lower_expr(sub_expr); | |
1227 | ||
1228 | let path = &[sym::ops, sym::Try, sym::into_result]; | |
1229 | P(self.expr_call_std_path(unstable_span, path, hir_vec![sub_expr])) | |
1230 | }; | |
1231 | ||
1232 | // `#[allow(unreachable_code)]` | |
1233 | let attr = { | |
1234 | // `allow(unreachable_code)` | |
1235 | let allow = { | |
1236 | let allow_ident = Ident::new(sym::allow, span); | |
1237 | let uc_ident = Ident::new(sym::unreachable_code, span); | |
1238 | let uc_nested = attr::mk_nested_word_item(uc_ident); | |
1239 | attr::mk_list_item(allow_ident, vec![uc_nested]) | |
1240 | }; | |
1241 | attr::mk_attr_outer(allow) | |
1242 | }; | |
1243 | let attrs = vec![attr]; | |
1244 | ||
1245 | // `Ok(val) => #[allow(unreachable_code)] val,` | |
1246 | let ok_arm = { | |
1247 | let val_ident = Ident::with_empty_ctxt(sym::val); | |
1248 | let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident); | |
1249 | let val_expr = P(self.expr_ident_with_attrs( | |
1250 | span, | |
1251 | val_ident, | |
1252 | val_pat_nid, | |
1253 | ThinVec::from(attrs.clone()), | |
1254 | )); | |
1255 | let ok_pat = self.pat_ok(span, val_pat); | |
1256 | ||
1257 | self.arm(hir_vec![ok_pat], val_expr) | |
1258 | }; | |
1259 | ||
1260 | // `Err(err) => #[allow(unreachable_code)] | |
1261 | // return Try::from_error(From::from(err)),` | |
1262 | let err_arm = { | |
1263 | let err_ident = Ident::with_empty_ctxt(sym::err); | |
1264 | let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident); | |
1265 | let from_expr = { | |
1266 | let from_path = &[sym::convert, sym::From, sym::from]; | |
1267 | let err_expr = self.expr_ident(try_span, err_ident, err_local_nid); | |
1268 | self.expr_call_std_path(try_span, from_path, hir_vec![err_expr]) | |
1269 | }; | |
1270 | let from_err_expr = | |
1271 | self.wrap_in_try_constructor(sym::from_error, from_expr, unstable_span); | |
1272 | let thin_attrs = ThinVec::from(attrs); | |
1273 | let catch_scope = self.catch_scopes.last().map(|x| *x); | |
1274 | let ret_expr = if let Some(catch_node) = catch_scope { | |
1275 | let target_id = Ok(self.lower_node_id(catch_node)); | |
1276 | P(self.expr( | |
1277 | try_span, | |
1278 | hir::ExprKind::Break( | |
1279 | hir::Destination { | |
1280 | label: None, | |
1281 | target_id, | |
1282 | }, | |
1283 | Some(from_err_expr), | |
1284 | ), | |
1285 | thin_attrs, | |
1286 | )) | |
1287 | } else { | |
1288 | P(self.expr(try_span, hir::ExprKind::Ret(Some(from_err_expr)), thin_attrs)) | |
1289 | }; | |
1290 | ||
1291 | let err_pat = self.pat_err(try_span, err_local); | |
1292 | self.arm(hir_vec![err_pat], ret_expr) | |
1293 | }; | |
1294 | ||
1295 | hir::ExprKind::Match( | |
1296 | scrutinee, | |
1297 | hir_vec![err_arm, ok_arm], | |
1298 | hir::MatchSource::TryDesugar, | |
1299 | ) | |
1300 | } | |
1301 | ||
1302 | // ========================================================================= | |
1303 | // Helper methods for building HIR. | |
1304 | // ========================================================================= | |
1305 | ||
1306 | /// Constructs a `true` or `false` literal expression. | |
1307 | pub(super) fn expr_bool(&mut self, span: Span, val: bool) -> hir::Expr { | |
1308 | let lit = Spanned { span, node: LitKind::Bool(val) }; | |
1309 | self.expr(span, hir::ExprKind::Lit(lit), ThinVec::new()) | |
1310 | } | |
1311 | ||
1312 | /// Wrap the given `expr` in a terminating scope using `hir::ExprKind::DropTemps`. | |
1313 | /// | |
1314 | /// In terms of drop order, it has the same effect as wrapping `expr` in | |
1315 | /// `{ let _t = $expr; _t }` but should provide better compile-time performance. | |
1316 | /// | |
1317 | /// The drop order can be important in e.g. `if expr { .. }`. | |
1318 | fn expr_drop_temps( | |
1319 | &mut self, | |
1320 | span: Span, | |
1321 | expr: P<hir::Expr>, | |
1322 | attrs: ThinVec<Attribute> | |
1323 | ) -> hir::Expr { | |
1324 | self.expr(span, hir::ExprKind::DropTemps(expr), attrs) | |
1325 | } | |
1326 | ||
1327 | fn expr_match( | |
1328 | &mut self, | |
1329 | span: Span, | |
1330 | arg: P<hir::Expr>, | |
1331 | arms: hir::HirVec<hir::Arm>, | |
1332 | source: hir::MatchSource, | |
1333 | ) -> hir::Expr { | |
1334 | self.expr(span, hir::ExprKind::Match(arg, arms, source), ThinVec::new()) | |
1335 | } | |
1336 | ||
1337 | fn expr_break(&mut self, span: Span, attrs: ThinVec<Attribute>) -> P<hir::Expr> { | |
1338 | let expr_break = hir::ExprKind::Break(self.lower_loop_destination(None), None); | |
1339 | P(self.expr(span, expr_break, attrs)) | |
1340 | } | |
1341 | ||
1342 | fn expr_mut_addr_of(&mut self, span: Span, e: P<hir::Expr>) -> hir::Expr { | |
1343 | self.expr(span, hir::ExprKind::AddrOf(hir::MutMutable, e), ThinVec::new()) | |
1344 | } | |
1345 | ||
1346 | fn expr_unit(&mut self, sp: Span) -> hir::Expr { | |
1347 | self.expr_tuple(sp, hir_vec![]) | |
1348 | } | |
1349 | ||
1350 | fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<hir::Expr>) -> hir::Expr { | |
1351 | self.expr(sp, hir::ExprKind::Tup(exprs), ThinVec::new()) | |
1352 | } | |
1353 | ||
1354 | fn expr_call( | |
1355 | &mut self, | |
1356 | span: Span, | |
1357 | e: P<hir::Expr>, | |
1358 | args: hir::HirVec<hir::Expr>, | |
1359 | ) -> hir::Expr { | |
1360 | self.expr(span, hir::ExprKind::Call(e, args), ThinVec::new()) | |
1361 | } | |
1362 | ||
1363 | // Note: associated functions must use `expr_call_std_path`. | |
1364 | fn expr_call_std_path( | |
1365 | &mut self, | |
1366 | span: Span, | |
1367 | path_components: &[Symbol], | |
1368 | args: hir::HirVec<hir::Expr>, | |
1369 | ) -> hir::Expr { | |
1370 | let path = P(self.expr_std_path(span, path_components, None, ThinVec::new())); | |
1371 | self.expr_call(span, path, args) | |
1372 | } | |
1373 | ||
1374 | // Create an expression calling an associated function of an std type. | |
1375 | // | |
1376 | // Associated functions cannot be resolved through the normal `std_path` function, | |
1377 | // as they are resolved differently and so cannot use `expr_call_std_path`. | |
1378 | // | |
1379 | // This function accepts the path component (`ty_path_components`) separately from | |
1380 | // the name of the associated function (`assoc_fn_name`) in order to facilitate | |
1381 | // separate resolution of the type and creation of a path referring to its associated | |
1382 | // function. | |
1383 | fn expr_call_std_assoc_fn( | |
1384 | &mut self, | |
1385 | ty_path_id: hir::HirId, | |
1386 | span: Span, | |
1387 | ty_path_components: &[Symbol], | |
1388 | assoc_fn_name: &str, | |
1389 | args: hir::HirVec<hir::Expr>, | |
1390 | ) -> hir::ExprKind { | |
1391 | let ty_path = P(self.std_path(span, ty_path_components, None, false)); | |
1392 | let ty = P(self.ty_path(ty_path_id, span, hir::QPath::Resolved(None, ty_path))); | |
1393 | let fn_seg = P(hir::PathSegment::from_ident(Ident::from_str(assoc_fn_name))); | |
1394 | let fn_path = hir::QPath::TypeRelative(ty, fn_seg); | |
1395 | let fn_expr = P(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new())); | |
1396 | hir::ExprKind::Call(fn_expr, args) | |
1397 | } | |
1398 | ||
1399 | fn expr_std_path( | |
1400 | &mut self, | |
1401 | span: Span, | |
1402 | components: &[Symbol], | |
1403 | params: Option<P<hir::GenericArgs>>, | |
1404 | attrs: ThinVec<Attribute>, | |
1405 | ) -> hir::Expr { | |
1406 | let path = self.std_path(span, components, params, true); | |
1407 | self.expr( | |
1408 | span, | |
1409 | hir::ExprKind::Path(hir::QPath::Resolved(None, P(path))), | |
1410 | attrs, | |
1411 | ) | |
1412 | } | |
1413 | ||
1414 | pub(super) fn expr_ident(&mut self, sp: Span, ident: Ident, binding: hir::HirId) -> hir::Expr { | |
1415 | self.expr_ident_with_attrs(sp, ident, binding, ThinVec::new()) | |
1416 | } | |
1417 | ||
1418 | fn expr_ident_with_attrs( | |
1419 | &mut self, | |
1420 | span: Span, | |
1421 | ident: Ident, | |
1422 | binding: hir::HirId, | |
1423 | attrs: ThinVec<Attribute>, | |
1424 | ) -> hir::Expr { | |
1425 | let expr_path = hir::ExprKind::Path(hir::QPath::Resolved( | |
1426 | None, | |
1427 | P(hir::Path { | |
1428 | span, | |
1429 | res: Res::Local(binding), | |
1430 | segments: hir_vec![hir::PathSegment::from_ident(ident)], | |
1431 | }), | |
1432 | )); | |
1433 | ||
1434 | self.expr(span, expr_path, attrs) | |
1435 | } | |
1436 | ||
1437 | fn expr_unsafe(&mut self, expr: P<hir::Expr>) -> hir::Expr { | |
1438 | let hir_id = self.next_id(); | |
1439 | let span = expr.span; | |
1440 | self.expr( | |
1441 | span, | |
1442 | hir::ExprKind::Block(P(hir::Block { | |
1443 | stmts: hir_vec![], | |
1444 | expr: Some(expr), | |
1445 | hir_id, | |
1446 | rules: hir::UnsafeBlock(hir::CompilerGenerated), | |
1447 | span, | |
1448 | targeted_by_break: false, | |
1449 | }), None), | |
1450 | ThinVec::new(), | |
1451 | ) | |
1452 | } | |
1453 | ||
1454 | fn expr_block_empty(&mut self, span: Span) -> hir::Expr { | |
1455 | let blk = self.block_all(span, hir_vec![], None); | |
1456 | self.expr_block(P(blk), ThinVec::new()) | |
1457 | } | |
1458 | ||
1459 | pub(super) fn expr_block(&mut self, b: P<hir::Block>, attrs: ThinVec<Attribute>) -> hir::Expr { | |
1460 | self.expr(b.span, hir::ExprKind::Block(b, None), attrs) | |
1461 | } | |
1462 | ||
1463 | pub(super) fn expr( | |
1464 | &mut self, | |
1465 | span: Span, | |
1466 | node: hir::ExprKind, | |
1467 | attrs: ThinVec<Attribute> | |
1468 | ) -> hir::Expr { | |
1469 | hir::Expr { | |
1470 | hir_id: self.next_id(), | |
1471 | node, | |
1472 | span, | |
1473 | attrs, | |
1474 | } | |
1475 | } | |
1476 | ||
1477 | fn field(&mut self, ident: Ident, expr: P<hir::Expr>, span: Span) -> hir::Field { | |
1478 | hir::Field { | |
1479 | hir_id: self.next_id(), | |
1480 | ident, | |
1481 | span, | |
1482 | expr, | |
1483 | is_shorthand: false, | |
1484 | } | |
1485 | } | |
1486 | ||
1487 | fn arm(&mut self, pats: hir::HirVec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm { | |
1488 | hir::Arm { | |
1489 | hir_id: self.next_id(), | |
1490 | attrs: hir_vec![], | |
1491 | pats, | |
1492 | guard: None, | |
1493 | span: expr.span, | |
1494 | body: expr, | |
1495 | } | |
1496 | } | |
1497 | } |