]> git.lizzy.rs Git - rust.git/blob - crates/hir_def/src/body/lower.rs
Merge #9165
[rust.git] / crates / hir_def / src / body / lower.rs
1 //! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
2 //! representation.
3
4 use std::{mem, sync::Arc};
5
6 use either::Either;
7 use hir_expand::{
8     ast_id_map::{AstIdMap, FileAstId},
9     hygiene::Hygiene,
10     name::{name, AsName, Name},
11     ExpandError, HirFileId, InFile,
12 };
13 use la_arena::Arena;
14 use profile::Count;
15 use syntax::{
16     ast::{
17         self, ArgListOwner, ArrayExprKind, AstChildren, LiteralKind, LoopBodyOwner, NameOwner,
18         SlicePatComponents,
19     },
20     AstNode, AstPtr, SyntaxNodePtr,
21 };
22
23 use crate::{
24     adt::StructKind,
25     body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
26     body::{BodyDiagnostic, ExprSource, PatSource},
27     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
28     db::DefDatabase,
29     expr::{
30         dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Label,
31         LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField,
32         Statement,
33     },
34     intern::Interned,
35     item_scope::BuiltinShadowMode,
36     path::{GenericArgs, Path},
37     type_ref::{Mutability, Rawness, TypeRef},
38     AdtId, BlockLoc, ModuleDefId, UnresolvedMacro,
39 };
40
41 pub struct LowerCtx<'a> {
42     pub db: &'a dyn DefDatabase,
43     hygiene: Hygiene,
44     file_id: Option<HirFileId>,
45     source_ast_id_map: Option<Arc<AstIdMap>>,
46 }
47
48 impl<'a> LowerCtx<'a> {
49     pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
50         LowerCtx {
51             db,
52             hygiene: Hygiene::new(db.upcast(), file_id),
53             file_id: Some(file_id),
54             source_ast_id_map: Some(db.ast_id_map(file_id)),
55         }
56     }
57
58     pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self {
59         LowerCtx { db, hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None }
60     }
61
62     pub(crate) fn hygiene(&self) -> &Hygiene {
63         &self.hygiene
64     }
65
66     pub(crate) fn file_id(&self) -> HirFileId {
67         self.file_id.unwrap()
68     }
69
70     pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> {
71         Path::from_src(ast, self)
72     }
73
74     pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> Option<FileAstId<N>> {
75         self.source_ast_id_map.as_ref().map(|ast_id_map| ast_id_map.ast_id(item))
76     }
77 }
78
79 pub(super) fn lower(
80     db: &dyn DefDatabase,
81     expander: Expander,
82     params: Option<ast::ParamList>,
83     body: Option<ast::Expr>,
84 ) -> (Body, BodySourceMap) {
85     ExprCollector {
86         db,
87         source_map: BodySourceMap::default(),
88         body: Body {
89             exprs: Arena::default(),
90             pats: Arena::default(),
91             labels: Arena::default(),
92             params: Vec::new(),
93             body_expr: dummy_expr_id(),
94             block_scopes: Vec::new(),
95             _c: Count::new(),
96         },
97         expander,
98         statements_in_scope: Vec::new(),
99     }
100     .collect(params, body)
101 }
102
103 struct ExprCollector<'a> {
104     db: &'a dyn DefDatabase,
105     expander: Expander,
106     body: Body,
107     source_map: BodySourceMap,
108     statements_in_scope: Vec<Statement>,
109 }
110
111 impl ExprCollector<'_> {
112     fn collect(
113         mut self,
114         param_list: Option<ast::ParamList>,
115         body: Option<ast::Expr>,
116     ) -> (Body, BodySourceMap) {
117         if let Some(param_list) = param_list {
118             if let Some(self_param) = param_list.self_param() {
119                 let ptr = AstPtr::new(&self_param);
120                 let param_pat = self.alloc_pat(
121                     Pat::Bind {
122                         name: name![self],
123                         mode: BindingAnnotation::new(
124                             self_param.mut_token().is_some() && self_param.amp_token().is_none(),
125                             false,
126                         ),
127                         subpat: None,
128                     },
129                     Either::Right(ptr),
130                 );
131                 self.body.params.push(param_pat);
132             }
133
134             for param in param_list.params() {
135                 let pat = match param.pat() {
136                     None => continue,
137                     Some(pat) => pat,
138                 };
139                 let param_pat = self.collect_pat(pat);
140                 self.body.params.push(param_pat);
141             }
142         };
143
144         self.body.body_expr = self.collect_expr_opt(body);
145         (self.body, self.source_map)
146     }
147
148     fn ctx(&self) -> LowerCtx<'_> {
149         LowerCtx::new(self.db, self.expander.current_file_id)
150     }
151
152     fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
153         let src = self.expander.to_source(ptr);
154         let id = self.make_expr(expr, Ok(src.clone()));
155         self.source_map.expr_map.insert(src, id);
156         id
157     }
158     // desugared exprs don't have ptr, that's wrong and should be fixed
159     // somehow.
160     fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
161         self.make_expr(expr, Err(SyntheticSyntax))
162     }
163     fn unit(&mut self) -> ExprId {
164         self.alloc_expr_desugared(Expr::Tuple { exprs: Vec::new() })
165     }
166     fn missing_expr(&mut self) -> ExprId {
167         self.alloc_expr_desugared(Expr::Missing)
168     }
169     fn make_expr(&mut self, expr: Expr, src: Result<ExprSource, SyntheticSyntax>) -> ExprId {
170         let id = self.body.exprs.alloc(expr);
171         self.source_map.expr_map_back.insert(id, src);
172         id
173     }
174
175     fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
176         let src = self.expander.to_source(ptr);
177         let id = self.make_pat(pat, Ok(src.clone()));
178         self.source_map.pat_map.insert(src, id);
179         id
180     }
181     fn missing_pat(&mut self) -> PatId {
182         self.make_pat(Pat::Missing, Err(SyntheticSyntax))
183     }
184     fn make_pat(&mut self, pat: Pat, src: Result<PatSource, SyntheticSyntax>) -> PatId {
185         let id = self.body.pats.alloc(pat);
186         self.source_map.pat_map_back.insert(id, src);
187         id
188     }
189
190     fn alloc_label(&mut self, label: Label, ptr: AstPtr<ast::Label>) -> LabelId {
191         let src = self.expander.to_source(ptr);
192         let id = self.make_label(label, src.clone());
193         self.source_map.label_map.insert(src, id);
194         id
195     }
196     fn make_label(&mut self, label: Label, src: LabelSource) -> LabelId {
197         let id = self.body.labels.alloc(label);
198         self.source_map.label_map_back.insert(id, src);
199         id
200     }
201
202     fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
203         self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr())
204     }
205
206     /// Returns `None` if and only if the expression is `#[cfg]`d out.
207     fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
208         let syntax_ptr = AstPtr::new(&expr);
209         self.check_cfg(&expr)?;
210
211         Some(match expr {
212             ast::Expr::IfExpr(e) => {
213                 let then_branch = self.collect_block_opt(e.then_branch());
214
215                 let else_branch = e.else_branch().map(|b| match b {
216                     ast::ElseBranch::Block(it) => self.collect_block(it),
217                     ast::ElseBranch::IfExpr(elif) => {
218                         let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
219                         self.collect_expr(expr)
220                     }
221                 });
222
223                 let condition = match e.condition() {
224                     None => self.missing_expr(),
225                     Some(condition) => match condition.pat() {
226                         None => self.collect_expr_opt(condition.expr()),
227                         // if let -- desugar to match
228                         Some(pat) => {
229                             let pat = self.collect_pat(pat);
230                             let match_expr = self.collect_expr_opt(condition.expr());
231                             let placeholder_pat = self.missing_pat();
232                             let arms = vec![
233                                 MatchArm { pat, expr: then_branch, guard: None },
234                                 MatchArm {
235                                     pat: placeholder_pat,
236                                     expr: else_branch.unwrap_or_else(|| self.unit()),
237                                     guard: None,
238                                 },
239                             ];
240                             return Some(
241                                 self.alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr),
242                             );
243                         }
244                     },
245                 };
246
247                 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
248             }
249             ast::Expr::EffectExpr(e) => match e.effect() {
250                 ast::Effect::Try(_) => {
251                     let body = self.collect_block_opt(e.block_expr());
252                     self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
253                 }
254                 ast::Effect::Unsafe(_) => {
255                     let body = self.collect_block_opt(e.block_expr());
256                     self.alloc_expr(Expr::Unsafe { body }, syntax_ptr)
257                 }
258                 // FIXME: we need to record these effects somewhere...
259                 ast::Effect::Label(label) => {
260                     let label = self.collect_label(label);
261                     match e.block_expr() {
262                         Some(block) => {
263                             let res = self.collect_block(block);
264                             match &mut self.body.exprs[res] {
265                                 Expr::Block { label: block_label, .. } => {
266                                     *block_label = Some(label);
267                                 }
268                                 _ => unreachable!(),
269                             }
270                             res
271                         }
272                         None => self.missing_expr(),
273                     }
274                 }
275                 // FIXME: we need to record these effects somewhere...
276                 ast::Effect::Async(_) => {
277                     let body = self.collect_block_opt(e.block_expr());
278                     self.alloc_expr(Expr::Async { body }, syntax_ptr)
279                 }
280                 ast::Effect::Const(_) => {
281                     let body = self.collect_block_opt(e.block_expr());
282                     self.alloc_expr(Expr::Const { body }, syntax_ptr)
283                 }
284             },
285             ast::Expr::BlockExpr(e) => self.collect_block(e),
286             ast::Expr::LoopExpr(e) => {
287                 let label = e.label().map(|label| self.collect_label(label));
288                 let body = self.collect_block_opt(e.loop_body());
289                 self.alloc_expr(Expr::Loop { body, label }, syntax_ptr)
290             }
291             ast::Expr::WhileExpr(e) => {
292                 let label = e.label().map(|label| self.collect_label(label));
293                 let body = self.collect_block_opt(e.loop_body());
294
295                 let condition = match e.condition() {
296                     None => self.missing_expr(),
297                     Some(condition) => match condition.pat() {
298                         None => self.collect_expr_opt(condition.expr()),
299                         // if let -- desugar to match
300                         Some(pat) => {
301                             cov_mark::hit!(infer_resolve_while_let);
302                             let pat = self.collect_pat(pat);
303                             let match_expr = self.collect_expr_opt(condition.expr());
304                             let placeholder_pat = self.missing_pat();
305                             let break_ =
306                                 self.alloc_expr_desugared(Expr::Break { expr: None, label: None });
307                             let arms = vec![
308                                 MatchArm { pat, expr: body, guard: None },
309                                 MatchArm { pat: placeholder_pat, expr: break_, guard: None },
310                             ];
311                             let match_expr =
312                                 self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
313                             return Some(
314                                 self.alloc_expr(Expr::Loop { body: match_expr, label }, syntax_ptr),
315                             );
316                         }
317                     },
318                 };
319
320                 self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr)
321             }
322             ast::Expr::ForExpr(e) => {
323                 let label = e.label().map(|label| self.collect_label(label));
324                 let iterable = self.collect_expr_opt(e.iterable());
325                 let pat = self.collect_pat_opt(e.pat());
326                 let body = self.collect_block_opt(e.loop_body());
327                 self.alloc_expr(Expr::For { iterable, pat, body, label }, syntax_ptr)
328             }
329             ast::Expr::CallExpr(e) => {
330                 let callee = self.collect_expr_opt(e.expr());
331                 let args = if let Some(arg_list) = e.arg_list() {
332                     arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
333                 } else {
334                     Vec::new()
335                 };
336                 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
337             }
338             ast::Expr::MethodCallExpr(e) => {
339                 let receiver = self.collect_expr_opt(e.receiver());
340                 let args = if let Some(arg_list) = e.arg_list() {
341                     arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
342                 } else {
343                     Vec::new()
344                 };
345                 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
346                 let generic_args = e
347                     .generic_arg_list()
348                     .and_then(|it| GenericArgs::from_ast(&self.ctx(), it))
349                     .map(Box::new);
350                 self.alloc_expr(
351                     Expr::MethodCall { receiver, method_name, args, generic_args },
352                     syntax_ptr,
353                 )
354             }
355             ast::Expr::MatchExpr(e) => {
356                 let expr = self.collect_expr_opt(e.expr());
357                 let arms = if let Some(match_arm_list) = e.match_arm_list() {
358                     match_arm_list
359                         .arms()
360                         .filter_map(|arm| {
361                             self.check_cfg(&arm).map(|()| MatchArm {
362                                 pat: self.collect_pat_opt(arm.pat()),
363                                 expr: self.collect_expr_opt(arm.expr()),
364                                 guard: arm
365                                     .guard()
366                                     .and_then(|guard| guard.expr())
367                                     .map(|e| self.collect_expr(e)),
368                             })
369                         })
370                         .collect()
371                 } else {
372                     Vec::new()
373                 };
374                 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
375             }
376             ast::Expr::PathExpr(e) => {
377                 let path = e
378                     .path()
379                     .and_then(|path| self.expander.parse_path(self.db, path))
380                     .map(Expr::Path)
381                     .unwrap_or(Expr::Missing);
382                 self.alloc_expr(path, syntax_ptr)
383             }
384             ast::Expr::ContinueExpr(e) => self.alloc_expr(
385                 Expr::Continue { label: e.lifetime().map(|l| Name::new_lifetime(&l)) },
386                 syntax_ptr,
387             ),
388             ast::Expr::BreakExpr(e) => {
389                 let expr = e.expr().map(|e| self.collect_expr(e));
390                 self.alloc_expr(
391                     Expr::Break { expr, label: e.lifetime().map(|l| Name::new_lifetime(&l)) },
392                     syntax_ptr,
393                 )
394             }
395             ast::Expr::ParenExpr(e) => {
396                 let inner = self.collect_expr_opt(e.expr());
397                 // make the paren expr point to the inner expression as well
398                 let src = self.expander.to_source(syntax_ptr);
399                 self.source_map.expr_map.insert(src, inner);
400                 inner
401             }
402             ast::Expr::ReturnExpr(e) => {
403                 let expr = e.expr().map(|e| self.collect_expr(e));
404                 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
405             }
406             ast::Expr::YieldExpr(e) => {
407                 let expr = e.expr().map(|e| self.collect_expr(e));
408                 self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
409             }
410             ast::Expr::RecordExpr(e) => {
411                 let path =
412                     e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
413                 let record_lit = if let Some(nfl) = e.record_expr_field_list() {
414                     let fields = nfl
415                         .fields()
416                         .filter_map(|field| {
417                             self.check_cfg(&field)?;
418
419                             let name = field.field_name()?.as_name();
420
421                             let expr = match field.expr() {
422                                 Some(e) => self.collect_expr(e),
423                                 None => self.missing_expr(),
424                             };
425                             let src = self.expander.to_source(AstPtr::new(&field));
426                             self.source_map.field_map.insert(src.clone(), expr);
427                             self.source_map.field_map_back.insert(expr, src);
428                             Some(RecordLitField { name, expr })
429                         })
430                         .collect();
431                     let spread = nfl.spread().map(|s| self.collect_expr(s));
432                     Expr::RecordLit { path, fields, spread }
433                 } else {
434                     Expr::RecordLit { path, fields: Vec::new(), spread: None }
435                 };
436
437                 self.alloc_expr(record_lit, syntax_ptr)
438             }
439             ast::Expr::FieldExpr(e) => {
440                 let expr = self.collect_expr_opt(e.expr());
441                 let name = match e.field_access() {
442                     Some(kind) => kind.as_name(),
443                     _ => Name::missing(),
444                 };
445                 self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
446             }
447             ast::Expr::AwaitExpr(e) => {
448                 let expr = self.collect_expr_opt(e.expr());
449                 self.alloc_expr(Expr::Await { expr }, syntax_ptr)
450             }
451             ast::Expr::TryExpr(e) => {
452                 let expr = self.collect_expr_opt(e.expr());
453                 self.alloc_expr(Expr::Try { expr }, syntax_ptr)
454             }
455             ast::Expr::CastExpr(e) => {
456                 let expr = self.collect_expr_opt(e.expr());
457                 let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
458                 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
459             }
460             ast::Expr::RefExpr(e) => {
461                 let expr = self.collect_expr_opt(e.expr());
462                 let raw_tok = e.raw_token().is_some();
463                 let mutability = if raw_tok {
464                     if e.mut_token().is_some() {
465                         Mutability::Mut
466                     } else if e.const_token().is_some() {
467                         Mutability::Shared
468                     } else {
469                         unreachable!("parser only remaps to raw_token() if matching mutability token follows")
470                     }
471                 } else {
472                     Mutability::from_mutable(e.mut_token().is_some())
473                 };
474                 let rawness = Rawness::from_raw(raw_tok);
475                 self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)
476             }
477             ast::Expr::PrefixExpr(e) => {
478                 let expr = self.collect_expr_opt(e.expr());
479                 if let Some(op) = e.op_kind() {
480                     self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
481                 } else {
482                     self.alloc_expr(Expr::Missing, syntax_ptr)
483                 }
484             }
485             ast::Expr::ClosureExpr(e) => {
486                 let mut args = Vec::new();
487                 let mut arg_types = Vec::new();
488                 if let Some(pl) = e.param_list() {
489                     for param in pl.params() {
490                         let pat = self.collect_pat_opt(param.pat());
491                         let type_ref =
492                             param.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
493                         args.push(pat);
494                         arg_types.push(type_ref);
495                     }
496                 }
497                 let ret_type = e
498                     .ret_type()
499                     .and_then(|r| r.ty())
500                     .map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
501                 let body = self.collect_expr_opt(e.body());
502                 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
503             }
504             ast::Expr::BinExpr(e) => {
505                 let lhs = self.collect_expr_opt(e.lhs());
506                 let rhs = self.collect_expr_opt(e.rhs());
507                 let op = e.op_kind().map(BinaryOp::from);
508                 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
509             }
510             ast::Expr::TupleExpr(e) => {
511                 let exprs = e.fields().map(|expr| self.collect_expr(expr)).collect();
512                 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr)
513             }
514             ast::Expr::BoxExpr(e) => {
515                 let expr = self.collect_expr_opt(e.expr());
516                 self.alloc_expr(Expr::Box { expr }, syntax_ptr)
517             }
518
519             ast::Expr::ArrayExpr(e) => {
520                 let kind = e.kind();
521
522                 match kind {
523                     ArrayExprKind::ElementList(e) => {
524                         let exprs = e.map(|expr| self.collect_expr(expr)).collect();
525                         self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr)
526                     }
527                     ArrayExprKind::Repeat { initializer, repeat } => {
528                         let initializer = self.collect_expr_opt(initializer);
529                         let repeat = self.collect_expr_opt(repeat);
530                         self.alloc_expr(
531                             Expr::Array(Array::Repeat { initializer, repeat }),
532                             syntax_ptr,
533                         )
534                     }
535                 }
536             }
537
538             ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr),
539             ast::Expr::IndexExpr(e) => {
540                 let base = self.collect_expr_opt(e.base());
541                 let index = self.collect_expr_opt(e.index());
542                 self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
543             }
544             ast::Expr::RangeExpr(e) => {
545                 let lhs = e.start().map(|lhs| self.collect_expr(lhs));
546                 let rhs = e.end().map(|rhs| self.collect_expr(rhs));
547                 match e.op_kind() {
548                     Some(range_type) => {
549                         self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)
550                     }
551                     None => self.alloc_expr(Expr::Missing, syntax_ptr),
552                 }
553             }
554             ast::Expr::MacroCall(e) => {
555                 let macro_ptr = AstPtr::new(&e);
556                 let mut ids = vec![];
557                 self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
558                     ids.push(match expansion {
559                         Some(it) => this.collect_expr(it),
560                         None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
561                     })
562                 });
563                 ids[0]
564             }
565             ast::Expr::MacroStmts(e) => {
566                 e.statements().for_each(|s| self.collect_stmt(s));
567                 let tail = e
568                     .expr()
569                     .map(|e| self.collect_expr(e))
570                     .unwrap_or_else(|| self.alloc_expr(Expr::Missing, syntax_ptr.clone()));
571
572                 self.alloc_expr(Expr::MacroStmts { tail }, syntax_ptr)
573             }
574         })
575     }
576
577     fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
578         &mut self,
579         e: ast::MacroCall,
580         syntax_ptr: AstPtr<ast::MacroCall>,
581         is_error_recoverable: bool,
582         mut collector: F,
583     ) {
584         // File containing the macro call. Expansion errors will be attached here.
585         let outer_file = self.expander.current_file_id;
586
587         let macro_call = self.expander.to_source(AstPtr::new(&e));
588         let res = self.expander.enter_expand(self.db, e);
589
590         let res = match res {
591             Ok(res) => res,
592             Err(UnresolvedMacro { path }) => {
593                 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall {
594                     node: InFile::new(outer_file, syntax_ptr),
595                     path,
596                 });
597                 collector(self, None);
598                 return;
599             }
600         };
601
602         match &res.err {
603             Some(ExpandError::UnresolvedProcMacro) => {
604                 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro {
605                     node: InFile::new(outer_file, syntax_ptr),
606                 });
607             }
608             Some(err) => {
609                 self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
610                     node: InFile::new(outer_file, syntax_ptr),
611                     message: err.to_string(),
612                 });
613             }
614             None => {}
615         }
616
617         match res.value {
618             Some((mark, expansion)) => {
619                 // FIXME: Statements are too complicated to recover from error for now.
620                 // It is because we don't have any hygiene for local variable expansion right now.
621                 if !is_error_recoverable && res.err.is_some() {
622                     self.expander.exit(self.db, mark);
623                     collector(self, None);
624                 } else {
625                     self.source_map.expansions.insert(macro_call, self.expander.current_file_id);
626
627                     let id = collector(self, Some(expansion));
628                     self.expander.exit(self.db, mark);
629                     id
630                 }
631             }
632             None => collector(self, None),
633         }
634     }
635
636     fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
637         if let Some(expr) = expr {
638             self.collect_expr(expr)
639         } else {
640             self.missing_expr()
641         }
642     }
643
644     fn collect_stmt(&mut self, s: ast::Stmt) {
645         match s {
646             ast::Stmt::LetStmt(stmt) => {
647                 if self.check_cfg(&stmt).is_none() {
648                     return;
649                 }
650                 let pat = self.collect_pat_opt(stmt.pat());
651                 let type_ref =
652                     stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
653                 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
654                 self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer });
655             }
656             ast::Stmt::ExprStmt(stmt) => {
657                 if self.check_cfg(&stmt).is_none() {
658                     return;
659                 }
660                 let has_semi = stmt.semicolon_token().is_some();
661                 // Note that macro could be expended to multiple statements
662                 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
663                     let macro_ptr = AstPtr::new(&m);
664                     let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
665
666                     self.collect_macro_call(
667                         m,
668                         macro_ptr,
669                         false,
670                         |this, expansion| match expansion {
671                             Some(expansion) => {
672                                 let statements: ast::MacroStmts = expansion;
673
674                                 statements.statements().for_each(|stmt| this.collect_stmt(stmt));
675                                 if let Some(expr) = statements.expr() {
676                                     let expr = this.collect_expr(expr);
677                                     this.statements_in_scope
678                                         .push(Statement::Expr { expr, has_semi });
679                                 }
680                             }
681                             None => {
682                                 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
683                                 this.statements_in_scope.push(Statement::Expr { expr, has_semi });
684                             }
685                         },
686                     );
687                 } else {
688                     let expr = self.collect_expr_opt(stmt.expr());
689                     self.statements_in_scope.push(Statement::Expr { expr, has_semi });
690                 }
691             }
692             ast::Stmt::Item(item) => {
693                 self.check_cfg(&item);
694             }
695         }
696     }
697
698     fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
699         let ast_id = self.expander.ast_id(&block);
700         let block_loc =
701             BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) };
702         let block_id = self.db.intern_block(block_loc);
703
704         let (module, def_map) = match self.db.block_def_map(block_id) {
705             Some(def_map) => {
706                 self.body.block_scopes.push(block_id);
707                 (def_map.root(), def_map)
708             }
709             None => (self.expander.module, self.expander.def_map.clone()),
710         };
711         let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
712         let prev_local_module = mem::replace(&mut self.expander.module, module);
713         let prev_statements = std::mem::take(&mut self.statements_in_scope);
714
715         block.statements().for_each(|s| self.collect_stmt(s));
716         block.tail_expr().and_then(|e| {
717             let expr = self.maybe_collect_expr(e)?;
718             self.statements_in_scope.push(Statement::Expr { expr, has_semi: false });
719             Some(())
720         });
721
722         let mut tail = None;
723         if let Some(Statement::Expr { expr, has_semi: false }) = self.statements_in_scope.last() {
724             tail = Some(*expr);
725             self.statements_in_scope.pop();
726         }
727         let tail = tail;
728         let statements = std::mem::replace(&mut self.statements_in_scope, prev_statements);
729         let syntax_node_ptr = AstPtr::new(&block.into());
730         let expr_id = self.alloc_expr(
731             Expr::Block { id: block_id, statements, tail, label: None },
732             syntax_node_ptr,
733         );
734
735         self.expander.def_map = prev_def_map;
736         self.expander.module = prev_local_module;
737         expr_id
738     }
739
740     fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
741         if let Some(block) = expr {
742             self.collect_block(block)
743         } else {
744             self.missing_expr()
745         }
746     }
747
748     fn collect_label(&mut self, ast_label: ast::Label) -> LabelId {
749         let label = Label {
750             name: ast_label.lifetime().as_ref().map_or_else(Name::missing, Name::new_lifetime),
751         };
752         self.alloc_label(label, AstPtr::new(&ast_label))
753     }
754
755     fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
756         let pattern = match &pat {
757             ast::Pat::IdentPat(bp) => {
758                 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
759                 let annotation =
760                     BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
761                 let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
762                 if annotation == BindingAnnotation::Unannotated && subpat.is_none() {
763                     // This could also be a single-segment path pattern. To
764                     // decide that, we need to try resolving the name.
765                     let (resolved, _) = self.expander.def_map.resolve_path(
766                         self.db,
767                         self.expander.module,
768                         &name.clone().into(),
769                         BuiltinShadowMode::Other,
770                     );
771                     match resolved.take_values() {
772                         Some(ModuleDefId::ConstId(_)) => Pat::Path(name.into()),
773                         Some(ModuleDefId::EnumVariantId(_)) => {
774                             // this is only really valid for unit variants, but
775                             // shadowing other enum variants with a pattern is
776                             // an error anyway
777                             Pat::Path(name.into())
778                         }
779                         Some(ModuleDefId::AdtId(AdtId::StructId(s)))
780                             if self.db.struct_data(s).variant_data.kind() != StructKind::Record =>
781                         {
782                             // Funnily enough, record structs *can* be shadowed
783                             // by pattern bindings (but unit or tuple structs
784                             // can't).
785                             Pat::Path(name.into())
786                         }
787                         // shadowing statics is an error as well, so we just ignore that case here
788                         _ => Pat::Bind { name, mode: annotation, subpat },
789                     }
790                 } else {
791                     Pat::Bind { name, mode: annotation, subpat }
792                 }
793             }
794             ast::Pat::TupleStructPat(p) => {
795                 let path =
796                     p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
797                 let (args, ellipsis) = self.collect_tuple_pat(p.fields());
798                 Pat::TupleStruct { path, args, ellipsis }
799             }
800             ast::Pat::RefPat(p) => {
801                 let pat = self.collect_pat_opt(p.pat());
802                 let mutability = Mutability::from_mutable(p.mut_token().is_some());
803                 Pat::Ref { pat, mutability }
804             }
805             ast::Pat::PathPat(p) => {
806                 let path =
807                     p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
808                 path.map(Pat::Path).unwrap_or(Pat::Missing)
809             }
810             ast::Pat::OrPat(p) => {
811                 let pats = p.pats().map(|p| self.collect_pat(p)).collect();
812                 Pat::Or(pats)
813             }
814             ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()),
815             ast::Pat::TuplePat(p) => {
816                 let (args, ellipsis) = self.collect_tuple_pat(p.fields());
817                 Pat::Tuple { args, ellipsis }
818             }
819             ast::Pat::WildcardPat(_) => Pat::Wild,
820             ast::Pat::RecordPat(p) => {
821                 let path =
822                     p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
823                 let args: Vec<_> = p
824                     .record_pat_field_list()
825                     .expect("every struct should have a field list")
826                     .fields()
827                     .filter_map(|f| {
828                         let ast_pat = f.pat()?;
829                         let pat = self.collect_pat(ast_pat);
830                         let name = f.field_name()?.as_name();
831                         Some(RecordFieldPat { name, pat })
832                     })
833                     .collect();
834
835                 let ellipsis = p
836                     .record_pat_field_list()
837                     .expect("every struct should have a field list")
838                     .dotdot_token()
839                     .is_some();
840
841                 Pat::Record { path, args, ellipsis }
842             }
843             ast::Pat::SlicePat(p) => {
844                 let SlicePatComponents { prefix, slice, suffix } = p.components();
845
846                 // FIXME properly handle `RestPat`
847                 Pat::Slice {
848                     prefix: prefix.into_iter().map(|p| self.collect_pat(p)).collect(),
849                     slice: slice.map(|p| self.collect_pat(p)),
850                     suffix: suffix.into_iter().map(|p| self.collect_pat(p)).collect(),
851                 }
852             }
853             ast::Pat::LiteralPat(lit) => {
854                 if let Some(ast_lit) = lit.literal() {
855                     let expr = Expr::Literal(ast_lit.kind().into());
856                     let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
857                     let expr_id = self.alloc_expr(expr, expr_ptr);
858                     Pat::Lit(expr_id)
859                 } else {
860                     Pat::Missing
861                 }
862             }
863             ast::Pat::RestPat(_) => {
864                 // `RestPat` requires special handling and should not be mapped
865                 // to a Pat. Here we are using `Pat::Missing` as a fallback for
866                 // when `RestPat` is mapped to `Pat`, which can easily happen
867                 // when the source code being analyzed has a malformed pattern
868                 // which includes `..` in a place where it isn't valid.
869
870                 Pat::Missing
871             }
872             ast::Pat::BoxPat(boxpat) => {
873                 let inner = self.collect_pat_opt(boxpat.pat());
874                 Pat::Box { inner }
875             }
876             ast::Pat::ConstBlockPat(const_block_pat) => {
877                 if let Some(expr) = const_block_pat.block_expr() {
878                     let expr_id = self.collect_block(expr);
879                     Pat::ConstBlock(expr_id)
880                 } else {
881                     Pat::Missing
882                 }
883             }
884             ast::Pat::MacroPat(mac) => match mac.macro_call() {
885                 Some(call) => {
886                     let macro_ptr = AstPtr::new(&call);
887                     let mut pat = None;
888                     self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
889                         pat = Some(this.collect_pat_opt(expanded_pat));
890                     });
891
892                     match pat {
893                         Some(pat) => return pat,
894                         None => Pat::Missing,
895                     }
896                 }
897                 None => Pat::Missing,
898             },
899             // FIXME: implement
900             ast::Pat::RangePat(_) => Pat::Missing,
901         };
902         let ptr = AstPtr::new(&pat);
903         self.alloc_pat(pattern, Either::Left(ptr))
904     }
905
906     fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
907         if let Some(pat) = pat {
908             self.collect_pat(pat)
909         } else {
910             self.missing_pat()
911         }
912     }
913
914     fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Vec<PatId>, Option<usize>) {
915         // Find the location of the `..`, if there is one. Note that we do not
916         // consider the possibility of there being multiple `..` here.
917         let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::RestPat(_)));
918         // We want to skip the `..` pattern here, since we account for it above.
919         let args = args
920             .filter(|p| !matches!(p, ast::Pat::RestPat(_)))
921             .map(|p| self.collect_pat(p))
922             .collect();
923
924         (args, ellipsis)
925     }
926
927     /// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when
928     /// not.
929     fn check_cfg(&mut self, owner: &dyn ast::AttrsOwner) -> Option<()> {
930         match self.expander.parse_attrs(self.db, owner).cfg() {
931             Some(cfg) => {
932                 if self.expander.cfg_options().check(&cfg) != Some(false) {
933                     return Some(());
934                 }
935
936                 self.source_map.diagnostics.push(BodyDiagnostic::InactiveCode {
937                     node: InFile::new(
938                         self.expander.current_file_id,
939                         SyntaxNodePtr::new(owner.syntax()),
940                     ),
941                     cfg,
942                     opts: self.expander.cfg_options().clone(),
943                 });
944
945                 None
946             }
947             None => Some(()),
948         }
949     }
950 }
951
952 impl From<ast::BinOp> for BinaryOp {
953     fn from(ast_op: ast::BinOp) -> Self {
954         match ast_op {
955             ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or),
956             ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And),
957             ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
958             ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }),
959             ast::BinOp::LesserEqualTest => {
960                 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false })
961             }
962             ast::BinOp::GreaterEqualTest => {
963                 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false })
964             }
965             ast::BinOp::LesserTest => {
966                 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true })
967             }
968             ast::BinOp::GreaterTest => {
969                 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true })
970             }
971             ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add),
972             ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul),
973             ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub),
974             ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div),
975             ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem),
976             ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl),
977             ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr),
978             ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor),
979             ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr),
980             ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd),
981             ast::BinOp::Assignment => BinaryOp::Assignment { op: None },
982             ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) },
983             ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) },
984             ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) },
985             ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) },
986             ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) },
987             ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) },
988             ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) },
989             ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) },
990             ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) },
991             ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) },
992         }
993     }
994 }
995
996 impl From<ast::LiteralKind> for Literal {
997     fn from(ast_lit_kind: ast::LiteralKind) -> Self {
998         match ast_lit_kind {
999             // FIXME: these should have actual values filled in, but unsure on perf impact
1000             LiteralKind::IntNumber(lit) => {
1001                 if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
1002                     Literal::Float(Default::default(), builtin)
1003                 } else if let builtin @ Some(_) =
1004                     lit.suffix().and_then(|it| BuiltinInt::from_suffix(it))
1005                 {
1006                     Literal::Int(lit.value().unwrap_or(0) as i128, builtin)
1007                 } else {
1008                     let builtin = lit.suffix().and_then(|it| BuiltinUint::from_suffix(it));
1009                     Literal::Uint(lit.value().unwrap_or(0), builtin)
1010                 }
1011             }
1012             LiteralKind::FloatNumber(lit) => {
1013                 let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(it));
1014                 Literal::Float(Default::default(), ty)
1015             }
1016             LiteralKind::ByteString(bs) => {
1017                 let text = bs.value().map(Vec::from).unwrap_or_else(Default::default);
1018                 Literal::ByteString(text)
1019             }
1020             LiteralKind::String(_) => Literal::String(Default::default()),
1021             LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)),
1022             LiteralKind::Bool(val) => Literal::Bool(val),
1023             LiteralKind::Char => Literal::Char(Default::default()),
1024         }
1025     }
1026 }