]> git.lizzy.rs Git - rust.git/blob - crates/hir_def/src/body/lower.rs
Merge #8586
[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,
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     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
27     db::DefDatabase,
28     diagnostics::{InactiveCode, MacroError, UnresolvedMacroCall, UnresolvedProcMacro},
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 use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
42
43 pub struct LowerCtx {
44     hygiene: Hygiene,
45     file_id: Option<HirFileId>,
46     source_ast_id_map: Option<Arc<AstIdMap>>,
47 }
48
49 impl LowerCtx {
50     pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self {
51         LowerCtx {
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(hygiene: &Hygiene) -> Self {
59         LowerCtx { 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 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(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 = e.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
412                 let record_lit = if let Some(nfl) = e.record_expr_field_list() {
413                     let fields = nfl
414                         .fields()
415                         .filter_map(|field| {
416                             self.check_cfg(&field)?;
417
418                             let name = field.field_name()?.as_name();
419
420                             let expr = match field.expr() {
421                                 Some(e) => self.collect_expr(e),
422                                 None => self.missing_expr(),
423                             };
424                             let src = self.expander.to_source(AstPtr::new(&field));
425                             self.source_map.field_map.insert(src.clone(), expr);
426                             self.source_map.field_map_back.insert(expr, src);
427                             Some(RecordLitField { name, expr })
428                         })
429                         .collect();
430                     let spread = nfl.spread().map(|s| self.collect_expr(s));
431                     Expr::RecordLit { path, fields, spread }
432                 } else {
433                     Expr::RecordLit { path, fields: Vec::new(), spread: None }
434                 };
435
436                 self.alloc_expr(record_lit, syntax_ptr)
437             }
438             ast::Expr::FieldExpr(e) => {
439                 let expr = self.collect_expr_opt(e.expr());
440                 let name = match e.field_access() {
441                     Some(kind) => kind.as_name(),
442                     _ => Name::missing(),
443                 };
444                 self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
445             }
446             ast::Expr::AwaitExpr(e) => {
447                 let expr = self.collect_expr_opt(e.expr());
448                 self.alloc_expr(Expr::Await { expr }, syntax_ptr)
449             }
450             ast::Expr::TryExpr(e) => {
451                 let expr = self.collect_expr_opt(e.expr());
452                 self.alloc_expr(Expr::Try { expr }, syntax_ptr)
453             }
454             ast::Expr::CastExpr(e) => {
455                 let expr = self.collect_expr_opt(e.expr());
456                 let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
457                 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
458             }
459             ast::Expr::RefExpr(e) => {
460                 let expr = self.collect_expr_opt(e.expr());
461                 let raw_tok = e.raw_token().is_some();
462                 let mutability = if raw_tok {
463                     if e.mut_token().is_some() {
464                         Mutability::Mut
465                     } else if e.const_token().is_some() {
466                         Mutability::Shared
467                     } else {
468                         unreachable!("parser only remaps to raw_token() if matching mutability token follows")
469                     }
470                 } else {
471                     Mutability::from_mutable(e.mut_token().is_some())
472                 };
473                 let rawness = Rawness::from_raw(raw_tok);
474                 self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)
475             }
476             ast::Expr::PrefixExpr(e) => {
477                 let expr = self.collect_expr_opt(e.expr());
478                 if let Some(op) = e.op_kind() {
479                     self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
480                 } else {
481                     self.alloc_expr(Expr::Missing, syntax_ptr)
482                 }
483             }
484             ast::Expr::ClosureExpr(e) => {
485                 let mut args = Vec::new();
486                 let mut arg_types = Vec::new();
487                 if let Some(pl) = e.param_list() {
488                     for param in pl.params() {
489                         let pat = self.collect_pat_opt(param.pat());
490                         let type_ref =
491                             param.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
492                         args.push(pat);
493                         arg_types.push(type_ref);
494                     }
495                 }
496                 let ret_type = e
497                     .ret_type()
498                     .and_then(|r| r.ty())
499                     .map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
500                 let body = self.collect_expr_opt(e.body());
501                 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
502             }
503             ast::Expr::BinExpr(e) => {
504                 let lhs = self.collect_expr_opt(e.lhs());
505                 let rhs = self.collect_expr_opt(e.rhs());
506                 let op = e.op_kind().map(BinaryOp::from);
507                 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
508             }
509             ast::Expr::TupleExpr(e) => {
510                 let exprs = e.fields().map(|expr| self.collect_expr(expr)).collect();
511                 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr)
512             }
513             ast::Expr::BoxExpr(e) => {
514                 let expr = self.collect_expr_opt(e.expr());
515                 self.alloc_expr(Expr::Box { expr }, syntax_ptr)
516             }
517
518             ast::Expr::ArrayExpr(e) => {
519                 let kind = e.kind();
520
521                 match kind {
522                     ArrayExprKind::ElementList(e) => {
523                         let exprs = e.map(|expr| self.collect_expr(expr)).collect();
524                         self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr)
525                     }
526                     ArrayExprKind::Repeat { initializer, repeat } => {
527                         let initializer = self.collect_expr_opt(initializer);
528                         let repeat = self.collect_expr_opt(repeat);
529                         self.alloc_expr(
530                             Expr::Array(Array::Repeat { initializer, repeat }),
531                             syntax_ptr,
532                         )
533                     }
534                 }
535             }
536
537             ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr),
538             ast::Expr::IndexExpr(e) => {
539                 let base = self.collect_expr_opt(e.base());
540                 let index = self.collect_expr_opt(e.index());
541                 self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
542             }
543             ast::Expr::RangeExpr(e) => {
544                 let lhs = e.start().map(|lhs| self.collect_expr(lhs));
545                 let rhs = e.end().map(|rhs| self.collect_expr(rhs));
546                 match e.op_kind() {
547                     Some(range_type) => {
548                         self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)
549                     }
550                     None => self.alloc_expr(Expr::Missing, syntax_ptr),
551                 }
552             }
553             ast::Expr::MacroCall(e) => {
554                 let macro_ptr = AstPtr::new(&e);
555                 let mut ids = vec![];
556                 self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
557                     ids.push(match expansion {
558                         Some(it) => this.collect_expr(it),
559                         None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
560                     })
561                 });
562                 ids[0]
563             }
564             ast::Expr::MacroStmts(e) => {
565                 e.statements().for_each(|s| self.collect_stmt(s));
566                 let tail = e
567                     .expr()
568                     .map(|e| self.collect_expr(e))
569                     .unwrap_or_else(|| self.alloc_expr(Expr::Missing, syntax_ptr.clone()));
570
571                 self.alloc_expr(Expr::MacroStmts { tail }, syntax_ptr)
572             }
573         })
574     }
575
576     fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
577         &mut self,
578         e: ast::MacroCall,
579         syntax_ptr: AstPtr<ast::MacroCall>,
580         is_error_recoverable: bool,
581         mut collector: F,
582     ) {
583         // File containing the macro call. Expansion errors will be attached here.
584         let outer_file = self.expander.current_file_id;
585
586         let macro_call = self.expander.to_source(AstPtr::new(&e));
587         let res = self.expander.enter_expand(self.db, e);
588
589         let res = match res {
590             Ok(res) => res,
591             Err(UnresolvedMacro { path }) => {
592                 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall(
593                     UnresolvedMacroCall {
594                         file: outer_file,
595                         node: syntax_ptr.cast().unwrap(),
596                         path,
597                     },
598                 ));
599                 collector(self, None);
600                 return;
601             }
602         };
603
604         match &res.err {
605             Some(ExpandError::UnresolvedProcMacro) => {
606                 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro(
607                     UnresolvedProcMacro {
608                         file: outer_file,
609                         node: syntax_ptr.into(),
610                         precise_location: None,
611                         macro_name: None,
612                     },
613                 ));
614             }
615             Some(err) => {
616                 self.source_map.diagnostics.push(BodyDiagnostic::MacroError(MacroError {
617                     file: outer_file,
618                     node: syntax_ptr.into(),
619                     message: err.to_string(),
620                 }));
621             }
622             None => {}
623         }
624
625         match res.value {
626             Some((mark, expansion)) => {
627                 // FIXME: Statements are too complicated to recover from error for now.
628                 // It is because we don't have any hygiene for local variable expansion right now.
629                 if !is_error_recoverable && res.err.is_some() {
630                     self.expander.exit(self.db, mark);
631                     collector(self, None);
632                 } else {
633                     self.source_map.expansions.insert(macro_call, self.expander.current_file_id);
634
635                     let id = collector(self, Some(expansion));
636                     self.expander.exit(self.db, mark);
637                     id
638                 }
639             }
640             None => collector(self, None),
641         }
642     }
643
644     fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
645         if let Some(expr) = expr {
646             self.collect_expr(expr)
647         } else {
648             self.missing_expr()
649         }
650     }
651
652     fn collect_stmt(&mut self, s: ast::Stmt) {
653         match s {
654             ast::Stmt::LetStmt(stmt) => {
655                 if self.check_cfg(&stmt).is_none() {
656                     return;
657                 }
658                 let pat = self.collect_pat_opt(stmt.pat());
659                 let type_ref =
660                     stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
661                 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
662                 self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer });
663             }
664             ast::Stmt::ExprStmt(stmt) => {
665                 if self.check_cfg(&stmt).is_none() {
666                     return;
667                 }
668
669                 // Note that macro could be expended to multiple statements
670                 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
671                     let macro_ptr = AstPtr::new(&m);
672                     let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
673
674                     self.collect_macro_call(
675                         m,
676                         macro_ptr,
677                         false,
678                         |this, expansion| match expansion {
679                             Some(expansion) => {
680                                 let statements: ast::MacroStmts = expansion;
681
682                                 statements.statements().for_each(|stmt| this.collect_stmt(stmt));
683                                 if let Some(expr) = statements.expr() {
684                                     let expr = this.collect_expr(expr);
685                                     this.statements_in_scope.push(Statement::Expr(expr));
686                                 }
687                             }
688                             None => {
689                                 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
690                                 this.statements_in_scope.push(Statement::Expr(expr));
691                             }
692                         },
693                     );
694                 } else {
695                     let expr = self.collect_expr_opt(stmt.expr());
696                     self.statements_in_scope.push(Statement::Expr(expr));
697                 }
698             }
699             ast::Stmt::Item(item) => {
700                 if self.check_cfg(&item).is_none() {
701                     return;
702                 }
703             }
704         }
705     }
706
707     fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
708         let ast_id = self.expander.ast_id(&block);
709         let block_loc =
710             BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) };
711         let block_id = self.db.intern_block(block_loc);
712
713         let (module, def_map) = match self.db.block_def_map(block_id) {
714             Some(def_map) => {
715                 self.body.block_scopes.push(block_id);
716                 (def_map.root(), def_map)
717             }
718             None => (self.expander.module, self.expander.def_map.clone()),
719         };
720         let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
721         let prev_local_module = mem::replace(&mut self.expander.module, module);
722         let prev_statements = std::mem::take(&mut self.statements_in_scope);
723
724         block.statements().for_each(|s| self.collect_stmt(s));
725
726         let tail = block.tail_expr().map(|e| self.collect_expr(e));
727         let statements = std::mem::replace(&mut self.statements_in_scope, prev_statements);
728         let syntax_node_ptr = AstPtr::new(&block.into());
729         let expr_id = self.alloc_expr(
730             Expr::Block { id: block_id, statements, tail, label: None },
731             syntax_node_ptr,
732         );
733
734         self.expander.def_map = prev_def_map;
735         self.expander.module = prev_local_module;
736         expr_id
737     }
738
739     fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
740         if let Some(block) = expr {
741             self.collect_block(block)
742         } else {
743             self.missing_expr()
744         }
745     }
746
747     fn collect_label(&mut self, ast_label: ast::Label) -> LabelId {
748         let label = Label {
749             name: ast_label.lifetime().as_ref().map_or_else(Name::missing, Name::new_lifetime),
750         };
751         self.alloc_label(label, AstPtr::new(&ast_label))
752     }
753
754     fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
755         let pattern = match &pat {
756             ast::Pat::IdentPat(bp) => {
757                 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
758                 let annotation =
759                     BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
760                 let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
761                 if annotation == BindingAnnotation::Unannotated && subpat.is_none() {
762                     // This could also be a single-segment path pattern. To
763                     // decide that, we need to try resolving the name.
764                     let (resolved, _) = self.expander.def_map.resolve_path(
765                         self.db,
766                         self.expander.module,
767                         &name.clone().into(),
768                         BuiltinShadowMode::Other,
769                     );
770                     match resolved.take_values() {
771                         Some(ModuleDefId::ConstId(_)) => Pat::Path(name.into()),
772                         Some(ModuleDefId::EnumVariantId(_)) => {
773                             // this is only really valid for unit variants, but
774                             // shadowing other enum variants with a pattern is
775                             // an error anyway
776                             Pat::Path(name.into())
777                         }
778                         Some(ModuleDefId::AdtId(AdtId::StructId(s)))
779                             if self.db.struct_data(s).variant_data.kind() != StructKind::Record =>
780                         {
781                             // Funnily enough, record structs *can* be shadowed
782                             // by pattern bindings (but unit or tuple structs
783                             // can't).
784                             Pat::Path(name.into())
785                         }
786                         // shadowing statics is an error as well, so we just ignore that case here
787                         _ => Pat::Bind { name, mode: annotation, subpat },
788                     }
789                 } else {
790                     Pat::Bind { name, mode: annotation, subpat }
791                 }
792             }
793             ast::Pat::TupleStructPat(p) => {
794                 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
795                 let (args, ellipsis) = self.collect_tuple_pat(p.fields());
796                 Pat::TupleStruct { path, args, ellipsis }
797             }
798             ast::Pat::RefPat(p) => {
799                 let pat = self.collect_pat_opt(p.pat());
800                 let mutability = Mutability::from_mutable(p.mut_token().is_some());
801                 Pat::Ref { pat, mutability }
802             }
803             ast::Pat::PathPat(p) => {
804                 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
805                 path.map(Pat::Path).unwrap_or(Pat::Missing)
806             }
807             ast::Pat::OrPat(p) => {
808                 let pats = p.pats().map(|p| self.collect_pat(p)).collect();
809                 Pat::Or(pats)
810             }
811             ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()),
812             ast::Pat::TuplePat(p) => {
813                 let (args, ellipsis) = self.collect_tuple_pat(p.fields());
814                 Pat::Tuple { args, ellipsis }
815             }
816             ast::Pat::WildcardPat(_) => Pat::Wild,
817             ast::Pat::RecordPat(p) => {
818                 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
819                 let args: Vec<_> = p
820                     .record_pat_field_list()
821                     .expect("every struct should have a field list")
822                     .fields()
823                     .filter_map(|f| {
824                         let ast_pat = f.pat()?;
825                         let pat = self.collect_pat(ast_pat);
826                         let name = f.field_name()?.as_name();
827                         Some(RecordFieldPat { name, pat })
828                     })
829                     .collect();
830
831                 let ellipsis = p
832                     .record_pat_field_list()
833                     .expect("every struct should have a field list")
834                     .dotdot_token()
835                     .is_some();
836
837                 Pat::Record { path, args, ellipsis }
838             }
839             ast::Pat::SlicePat(p) => {
840                 let SlicePatComponents { prefix, slice, suffix } = p.components();
841
842                 // FIXME properly handle `RestPat`
843                 Pat::Slice {
844                     prefix: prefix.into_iter().map(|p| self.collect_pat(p)).collect(),
845                     slice: slice.map(|p| self.collect_pat(p)),
846                     suffix: suffix.into_iter().map(|p| self.collect_pat(p)).collect(),
847                 }
848             }
849             ast::Pat::LiteralPat(lit) => {
850                 if let Some(ast_lit) = lit.literal() {
851                     let expr = Expr::Literal(ast_lit.kind().into());
852                     let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
853                     let expr_id = self.alloc_expr(expr, expr_ptr);
854                     Pat::Lit(expr_id)
855                 } else {
856                     Pat::Missing
857                 }
858             }
859             ast::Pat::RestPat(_) => {
860                 // `RestPat` requires special handling and should not be mapped
861                 // to a Pat. Here we are using `Pat::Missing` as a fallback for
862                 // when `RestPat` is mapped to `Pat`, which can easily happen
863                 // when the source code being analyzed has a malformed pattern
864                 // which includes `..` in a place where it isn't valid.
865
866                 Pat::Missing
867             }
868             ast::Pat::BoxPat(boxpat) => {
869                 let inner = self.collect_pat_opt(boxpat.pat());
870                 Pat::Box { inner }
871             }
872             ast::Pat::ConstBlockPat(const_block_pat) => {
873                 if let Some(expr) = const_block_pat.block_expr() {
874                     let expr_id = self.collect_block(expr);
875                     Pat::ConstBlock(expr_id)
876                 } else {
877                     Pat::Missing
878                 }
879             }
880             ast::Pat::MacroPat(mac) => match mac.macro_call() {
881                 Some(call) => {
882                     let macro_ptr = AstPtr::new(&call);
883                     let mut pat = None;
884                     self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
885                         pat = Some(this.collect_pat_opt(expanded_pat));
886                     });
887
888                     match pat {
889                         Some(pat) => return pat,
890                         None => Pat::Missing,
891                     }
892                 }
893                 None => Pat::Missing,
894             },
895             // FIXME: implement
896             ast::Pat::RangePat(_) => Pat::Missing,
897         };
898         let ptr = AstPtr::new(&pat);
899         self.alloc_pat(pattern, Either::Left(ptr))
900     }
901
902     fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
903         if let Some(pat) = pat {
904             self.collect_pat(pat)
905         } else {
906             self.missing_pat()
907         }
908     }
909
910     fn collect_tuple_pat(&mut self, args: AstChildren<ast::Pat>) -> (Vec<PatId>, Option<usize>) {
911         // Find the location of the `..`, if there is one. Note that we do not
912         // consider the possibility of there being multiple `..` here.
913         let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::RestPat(_)));
914         // We want to skip the `..` pattern here, since we account for it above.
915         let args = args
916             .filter(|p| !matches!(p, ast::Pat::RestPat(_)))
917             .map(|p| self.collect_pat(p))
918             .collect();
919
920         (args, ellipsis)
921     }
922
923     /// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when
924     /// not.
925     fn check_cfg(&mut self, owner: &dyn ast::AttrsOwner) -> Option<()> {
926         match self.expander.parse_attrs(self.db, owner).cfg() {
927             Some(cfg) => {
928                 if self.expander.cfg_options().check(&cfg) != Some(false) {
929                     return Some(());
930                 }
931
932                 self.source_map.diagnostics.push(BodyDiagnostic::InactiveCode(InactiveCode {
933                     file: self.expander.current_file_id,
934                     node: SyntaxNodePtr::new(owner.syntax()),
935                     cfg,
936                     opts: self.expander.cfg_options().clone(),
937                 }));
938
939                 None
940             }
941             None => Some(()),
942         }
943     }
944 }
945
946 impl From<ast::BinOp> for BinaryOp {
947     fn from(ast_op: ast::BinOp) -> Self {
948         match ast_op {
949             ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or),
950             ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And),
951             ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
952             ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }),
953             ast::BinOp::LesserEqualTest => {
954                 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false })
955             }
956             ast::BinOp::GreaterEqualTest => {
957                 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false })
958             }
959             ast::BinOp::LesserTest => {
960                 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true })
961             }
962             ast::BinOp::GreaterTest => {
963                 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true })
964             }
965             ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add),
966             ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul),
967             ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub),
968             ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div),
969             ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem),
970             ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl),
971             ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr),
972             ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor),
973             ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr),
974             ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd),
975             ast::BinOp::Assignment => BinaryOp::Assignment { op: None },
976             ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) },
977             ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) },
978             ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) },
979             ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) },
980             ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) },
981             ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) },
982             ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) },
983             ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) },
984             ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) },
985             ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) },
986         }
987     }
988 }
989
990 impl From<ast::LiteralKind> for Literal {
991     fn from(ast_lit_kind: ast::LiteralKind) -> Self {
992         match ast_lit_kind {
993             LiteralKind::IntNumber(lit) => {
994                 if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
995                     return Literal::Float(Default::default(), builtin);
996                 } else if let builtin @ Some(_) =
997                     lit.suffix().and_then(|it| BuiltinInt::from_suffix(&it))
998                 {
999                     Literal::Int(Default::default(), builtin)
1000                 } else {
1001                     let builtin = lit.suffix().and_then(|it| BuiltinUint::from_suffix(&it));
1002                     Literal::Uint(Default::default(), builtin)
1003                 }
1004             }
1005             LiteralKind::FloatNumber(lit) => {
1006                 let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it));
1007                 Literal::Float(Default::default(), ty)
1008             }
1009             LiteralKind::ByteString(_) => Literal::ByteString(Default::default()),
1010             LiteralKind::String(_) => Literal::String(Default::default()),
1011             LiteralKind::Byte => Literal::Uint(Default::default(), Some(BuiltinUint::U8)),
1012             LiteralKind::Bool(val) => Literal::Bool(val),
1013             LiteralKind::Char => Literal::Char(Default::default()),
1014         }
1015     }
1016 }