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