]> git.lizzy.rs Git - rust.git/blob - crates/ra_hir_def/src/body/lower.rs
853e17bae7f6ade304692b872a495f7b146bc997
[rust.git] / crates / ra_hir_def / src / body / lower.rs
1 //! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
2 //! representation.
3
4 use either::Either;
5
6 use hir_expand::name::{name, AsName, Name};
7 use ra_arena::Arena;
8 use ra_syntax::{
9     ast::{
10         self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, ModuleItemOwner, NameOwner,
11         TypeAscriptionOwner,
12     },
13     AstNode, AstPtr,
14 };
15 use test_utils::tested_by;
16
17 use crate::{
18     body::{Body, BodySourceMap, Expander, PatPtr},
19     builtin_type::{BuiltinFloat, BuiltinInt},
20     db::DefDatabase,
21     expr::{
22         ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp,
23         MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
24     },
25     path::GenericArgs,
26     path::Path,
27     type_ref::{Mutability, TypeRef},
28     ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, StaticLoc,
29     StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
30 };
31
32 pub(super) fn lower(
33     db: &impl DefDatabase,
34     def: DefWithBodyId,
35     expander: Expander,
36     params: Option<ast::ParamList>,
37     body: Option<ast::Expr>,
38 ) -> (Body, BodySourceMap) {
39     ExprCollector {
40         db,
41         def,
42         expander,
43         source_map: BodySourceMap::default(),
44         body: Body {
45             exprs: Arena::default(),
46             pats: Arena::default(),
47             params: Vec::new(),
48             body_expr: ExprId::dummy(),
49             defs: Vec::new(),
50         },
51     }
52     .collect(params, body)
53 }
54
55 struct ExprCollector<DB> {
56     db: DB,
57     def: DefWithBodyId,
58     expander: Expander,
59
60     body: Body,
61     source_map: BodySourceMap,
62 }
63
64 impl<'a, DB> ExprCollector<&'a DB>
65 where
66     DB: DefDatabase,
67 {
68     fn collect(
69         mut self,
70         param_list: Option<ast::ParamList>,
71         body: Option<ast::Expr>,
72     ) -> (Body, BodySourceMap) {
73         if let Some(param_list) = param_list {
74             if let Some(self_param) = param_list.self_param() {
75                 let ptr = AstPtr::new(&self_param);
76                 let param_pat = self.alloc_pat(
77                     Pat::Bind {
78                         name: name![self],
79                         mode: BindingAnnotation::Unannotated,
80                         subpat: None,
81                     },
82                     Either::Right(ptr),
83                 );
84                 self.body.params.push(param_pat);
85             }
86
87             for param in param_list.params() {
88                 let pat = match param.pat() {
89                     None => continue,
90                     Some(pat) => pat,
91                 };
92                 let param_pat = self.collect_pat(pat);
93                 self.body.params.push(param_pat);
94             }
95         };
96
97         self.body.body_expr = self.collect_expr_opt(body);
98         (self.body, self.source_map)
99     }
100
101     fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
102         let ptr = Either::Left(ptr);
103         let id = self.body.exprs.alloc(expr);
104         let src = self.expander.to_source(ptr);
105         self.source_map.expr_map.insert(src, id);
106         self.source_map.expr_map_back.insert(id, src);
107         id
108     }
109     // desugared exprs don't have ptr, that's wrong and should be fixed
110     // somehow.
111     fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
112         self.body.exprs.alloc(expr)
113     }
114     fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId {
115         let ptr = Either::Right(ptr);
116         let id = self.body.exprs.alloc(expr);
117         let src = self.expander.to_source(ptr);
118         self.source_map.expr_map.insert(src, id);
119         self.source_map.expr_map_back.insert(id, src);
120         id
121     }
122     fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
123         let id = self.body.pats.alloc(pat);
124         let src = self.expander.to_source(ptr);
125         self.source_map.pat_map.insert(src, id);
126         self.source_map.pat_map_back.insert(id, src);
127         id
128     }
129
130     fn empty_block(&mut self) -> ExprId {
131         let block = Expr::Block { statements: Vec::new(), tail: None };
132         self.body.exprs.alloc(block)
133     }
134
135     fn missing_expr(&mut self) -> ExprId {
136         self.body.exprs.alloc(Expr::Missing)
137     }
138
139     fn missing_pat(&mut self) -> PatId {
140         self.body.pats.alloc(Pat::Missing)
141     }
142
143     fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
144         let syntax_ptr = AstPtr::new(&expr);
145         match expr {
146             ast::Expr::IfExpr(e) => {
147                 let then_branch = self.collect_block_opt(e.then_branch());
148
149                 let else_branch = e.else_branch().map(|b| match b {
150                     ast::ElseBranch::Block(it) => self.collect_block(it),
151                     ast::ElseBranch::IfExpr(elif) => {
152                         let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
153                         self.collect_expr(expr)
154                     }
155                 });
156
157                 let condition = match e.condition() {
158                     None => self.missing_expr(),
159                     Some(condition) => match condition.pat() {
160                         None => self.collect_expr_opt(condition.expr()),
161                         // if let -- desugar to match
162                         Some(pat) => {
163                             let pat = self.collect_pat(pat);
164                             let match_expr = self.collect_expr_opt(condition.expr());
165                             let placeholder_pat = self.missing_pat();
166                             let arms = vec![
167                                 MatchArm { pats: vec![pat], expr: then_branch, guard: None },
168                                 MatchArm {
169                                     pats: vec![placeholder_pat],
170                                     expr: else_branch.unwrap_or_else(|| self.empty_block()),
171                                     guard: None,
172                                 },
173                             ];
174                             return self
175                                 .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr);
176                         }
177                     },
178                 };
179
180                 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
181             }
182             ast::Expr::TryBlockExpr(e) => {
183                 let body = self.collect_block_opt(e.body());
184                 self.alloc_expr(Expr::TryBlock { body }, syntax_ptr)
185             }
186             ast::Expr::BlockExpr(e) => self.collect_block(e),
187             ast::Expr::LoopExpr(e) => {
188                 let body = self.collect_block_opt(e.loop_body());
189                 self.alloc_expr(Expr::Loop { body }, syntax_ptr)
190             }
191             ast::Expr::WhileExpr(e) => {
192                 let body = self.collect_block_opt(e.loop_body());
193
194                 let condition = match e.condition() {
195                     None => self.missing_expr(),
196                     Some(condition) => match condition.pat() {
197                         None => self.collect_expr_opt(condition.expr()),
198                         // if let -- desugar to match
199                         Some(pat) => {
200                             tested_by!(infer_resolve_while_let);
201                             let pat = self.collect_pat(pat);
202                             let match_expr = self.collect_expr_opt(condition.expr());
203                             let placeholder_pat = self.missing_pat();
204                             let break_ = self.alloc_expr_desugared(Expr::Break { expr: None });
205                             let arms = vec![
206                                 MatchArm { pats: vec![pat], expr: body, guard: None },
207                                 MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None },
208                             ];
209                             let match_expr =
210                                 self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
211                             return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr);
212                         }
213                     },
214                 };
215
216                 self.alloc_expr(Expr::While { condition, body }, syntax_ptr)
217             }
218             ast::Expr::ForExpr(e) => {
219                 let iterable = self.collect_expr_opt(e.iterable());
220                 let pat = self.collect_pat_opt(e.pat());
221                 let body = self.collect_block_opt(e.loop_body());
222                 self.alloc_expr(Expr::For { iterable, pat, body }, syntax_ptr)
223             }
224             ast::Expr::CallExpr(e) => {
225                 let callee = self.collect_expr_opt(e.expr());
226                 let args = if let Some(arg_list) = e.arg_list() {
227                     arg_list.args().map(|e| self.collect_expr(e)).collect()
228                 } else {
229                     Vec::new()
230                 };
231                 self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
232             }
233             ast::Expr::MethodCallExpr(e) => {
234                 let receiver = self.collect_expr_opt(e.expr());
235                 let args = if let Some(arg_list) = e.arg_list() {
236                     arg_list.args().map(|e| self.collect_expr(e)).collect()
237                 } else {
238                     Vec::new()
239                 };
240                 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
241                 let generic_args = e.type_arg_list().and_then(GenericArgs::from_ast);
242                 self.alloc_expr(
243                     Expr::MethodCall { receiver, method_name, args, generic_args },
244                     syntax_ptr,
245                 )
246             }
247             ast::Expr::MatchExpr(e) => {
248                 let expr = self.collect_expr_opt(e.expr());
249                 let arms = if let Some(match_arm_list) = e.match_arm_list() {
250                     match_arm_list
251                         .arms()
252                         .map(|arm| MatchArm {
253                             pats: arm.pats().map(|p| self.collect_pat(p)).collect(),
254                             expr: self.collect_expr_opt(arm.expr()),
255                             guard: arm
256                                 .guard()
257                                 .and_then(|guard| guard.expr())
258                                 .map(|e| self.collect_expr(e)),
259                         })
260                         .collect()
261                 } else {
262                     Vec::new()
263                 };
264                 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
265             }
266             ast::Expr::PathExpr(e) => {
267                 let path = e
268                     .path()
269                     .and_then(|path| self.expander.parse_path(path))
270                     .map(Expr::Path)
271                     .unwrap_or(Expr::Missing);
272                 self.alloc_expr(path, syntax_ptr)
273             }
274             ast::Expr::ContinueExpr(_e) => {
275                 // FIXME: labels
276                 self.alloc_expr(Expr::Continue, syntax_ptr)
277             }
278             ast::Expr::BreakExpr(e) => {
279                 let expr = e.expr().map(|e| self.collect_expr(e));
280                 self.alloc_expr(Expr::Break { expr }, syntax_ptr)
281             }
282             ast::Expr::ParenExpr(e) => {
283                 let inner = self.collect_expr_opt(e.expr());
284                 // make the paren expr point to the inner expression as well
285                 let src = self.expander.to_source(Either::Left(syntax_ptr));
286                 self.source_map.expr_map.insert(src, inner);
287                 inner
288             }
289             ast::Expr::ReturnExpr(e) => {
290                 let expr = e.expr().map(|e| self.collect_expr(e));
291                 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
292             }
293             ast::Expr::RecordLit(e) => {
294                 let path = e.path().and_then(|path| self.expander.parse_path(path));
295                 let mut field_ptrs = Vec::new();
296                 let record_lit = if let Some(nfl) = e.record_field_list() {
297                     let fields = nfl
298                         .fields()
299                         .inspect(|field| field_ptrs.push(AstPtr::new(field)))
300                         .map(|field| RecordLitField {
301                             name: field
302                                 .name_ref()
303                                 .map(|nr| nr.as_name())
304                                 .unwrap_or_else(Name::missing),
305                             expr: if let Some(e) = field.expr() {
306                                 self.collect_expr(e)
307                             } else if let Some(nr) = field.name_ref() {
308                                 // field shorthand
309                                 self.alloc_expr_field_shorthand(
310                                     Expr::Path(Path::from_name_ref(&nr)),
311                                     AstPtr::new(&field),
312                                 )
313                             } else {
314                                 self.missing_expr()
315                             },
316                         })
317                         .collect();
318                     let spread = nfl.spread().map(|s| self.collect_expr(s));
319                     Expr::RecordLit { path, fields, spread }
320                 } else {
321                     Expr::RecordLit { path, fields: Vec::new(), spread: None }
322                 };
323
324                 let res = self.alloc_expr(record_lit, syntax_ptr);
325                 for (i, ptr) in field_ptrs.into_iter().enumerate() {
326                     self.source_map.field_map.insert((res, i), ptr);
327                 }
328                 res
329             }
330             ast::Expr::FieldExpr(e) => {
331                 let expr = self.collect_expr_opt(e.expr());
332                 let name = match e.field_access() {
333                     Some(kind) => kind.as_name(),
334                     _ => Name::missing(),
335                 };
336                 self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
337             }
338             ast::Expr::AwaitExpr(e) => {
339                 let expr = self.collect_expr_opt(e.expr());
340                 self.alloc_expr(Expr::Await { expr }, syntax_ptr)
341             }
342             ast::Expr::TryExpr(e) => {
343                 let expr = self.collect_expr_opt(e.expr());
344                 self.alloc_expr(Expr::Try { expr }, syntax_ptr)
345             }
346             ast::Expr::CastExpr(e) => {
347                 let expr = self.collect_expr_opt(e.expr());
348                 let type_ref = TypeRef::from_ast_opt(e.type_ref());
349                 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
350             }
351             ast::Expr::RefExpr(e) => {
352                 let expr = self.collect_expr_opt(e.expr());
353                 let mutability = Mutability::from_mutable(e.is_mut());
354                 self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr)
355             }
356             ast::Expr::PrefixExpr(e) => {
357                 let expr = self.collect_expr_opt(e.expr());
358                 if let Some(op) = e.op_kind() {
359                     self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
360                 } else {
361                     self.alloc_expr(Expr::Missing, syntax_ptr)
362                 }
363             }
364             ast::Expr::LambdaExpr(e) => {
365                 let mut args = Vec::new();
366                 let mut arg_types = Vec::new();
367                 if let Some(pl) = e.param_list() {
368                     for param in pl.params() {
369                         let pat = self.collect_pat_opt(param.pat());
370                         let type_ref = param.ascribed_type().map(TypeRef::from_ast);
371                         args.push(pat);
372                         arg_types.push(type_ref);
373                     }
374                 }
375                 let body = self.collect_expr_opt(e.body());
376                 self.alloc_expr(Expr::Lambda { args, arg_types, body }, syntax_ptr)
377             }
378             ast::Expr::BinExpr(e) => {
379                 let lhs = self.collect_expr_opt(e.lhs());
380                 let rhs = self.collect_expr_opt(e.rhs());
381                 let op = e.op_kind().map(BinaryOp::from);
382                 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
383             }
384             ast::Expr::TupleExpr(e) => {
385                 let exprs = e.exprs().map(|expr| self.collect_expr(expr)).collect();
386                 self.alloc_expr(Expr::Tuple { exprs }, syntax_ptr)
387             }
388             ast::Expr::BoxExpr(e) => {
389                 let expr = self.collect_expr_opt(e.expr());
390                 self.alloc_expr(Expr::Box { expr }, syntax_ptr)
391             }
392
393             ast::Expr::ArrayExpr(e) => {
394                 let kind = e.kind();
395
396                 match kind {
397                     ArrayExprKind::ElementList(e) => {
398                         let exprs = e.map(|expr| self.collect_expr(expr)).collect();
399                         self.alloc_expr(Expr::Array(Array::ElementList(exprs)), syntax_ptr)
400                     }
401                     ArrayExprKind::Repeat { initializer, repeat } => {
402                         let initializer = self.collect_expr_opt(initializer);
403                         let repeat = self.collect_expr_opt(repeat);
404                         self.alloc_expr(
405                             Expr::Array(Array::Repeat { initializer, repeat }),
406                             syntax_ptr,
407                         )
408                     }
409                 }
410             }
411
412             ast::Expr::Literal(e) => {
413                 let lit = match e.kind() {
414                     LiteralKind::IntNumber { suffix } => {
415                         let known_name = suffix.and_then(|it| BuiltinInt::from_suffix(&it));
416
417                         Literal::Int(Default::default(), known_name)
418                     }
419                     LiteralKind::FloatNumber { suffix } => {
420                         let known_name = suffix.and_then(|it| BuiltinFloat::from_suffix(&it));
421
422                         Literal::Float(Default::default(), known_name)
423                     }
424                     LiteralKind::ByteString => Literal::ByteString(Default::default()),
425                     LiteralKind::String => Literal::String(Default::default()),
426                     LiteralKind::Byte => Literal::Int(Default::default(), Some(BuiltinInt::U8)),
427                     LiteralKind::Bool => Literal::Bool(Default::default()),
428                     LiteralKind::Char => Literal::Char(Default::default()),
429                 };
430                 self.alloc_expr(Expr::Literal(lit), syntax_ptr)
431             }
432             ast::Expr::IndexExpr(e) => {
433                 let base = self.collect_expr_opt(e.base());
434                 let index = self.collect_expr_opt(e.index());
435                 self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
436             }
437             ast::Expr::RangeExpr(e) => {
438                 let lhs = e.start().map(|lhs| self.collect_expr(lhs));
439                 let rhs = e.end().map(|rhs| self.collect_expr(rhs));
440                 match e.op_kind() {
441                     Some(range_type) => {
442                         self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)
443                     }
444                     None => self.alloc_expr(Expr::Missing, syntax_ptr),
445                 }
446             }
447             // FIXME expand to statements in statement position
448             ast::Expr::MacroCall(e) => match self.expander.enter_expand(self.db, e) {
449                 Some((mark, expansion)) => {
450                     let id = self.collect_expr(expansion);
451                     self.expander.exit(self.db, mark);
452                     id
453                 }
454                 None => self.alloc_expr(Expr::Missing, syntax_ptr),
455             },
456
457             // FIXME implement HIR for these:
458             ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
459         }
460     }
461
462     fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
463         if let Some(expr) = expr {
464             self.collect_expr(expr)
465         } else {
466             self.missing_expr()
467         }
468     }
469
470     fn collect_block(&mut self, expr: ast::BlockExpr) -> ExprId {
471         let syntax_node_ptr = AstPtr::new(&expr.clone().into());
472         let block = match expr.block() {
473             Some(block) => block,
474             None => return self.alloc_expr(Expr::Missing, syntax_node_ptr),
475         };
476         self.collect_block_items(&block);
477         let statements = block
478             .statements()
479             .map(|s| match s {
480                 ast::Stmt::LetStmt(stmt) => {
481                     let pat = self.collect_pat_opt(stmt.pat());
482                     let type_ref = stmt.ascribed_type().map(TypeRef::from_ast);
483                     let initializer = stmt.initializer().map(|e| self.collect_expr(e));
484                     Statement::Let { pat, type_ref, initializer }
485                 }
486                 ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())),
487             })
488             .collect();
489         let tail = block.expr().map(|e| self.collect_expr(e));
490         self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr)
491     }
492
493     fn collect_block_items(&mut self, block: &ast::Block) {
494         let container = ContainerId::DefWithBodyId(self.def);
495         for item in block.items() {
496             let def: ModuleDefId = match item {
497                 ast::ModuleItem::FnDef(def) => {
498                     let ast_id = self.expander.ast_id(&def);
499                     FunctionLoc { container: container.into(), ast_id }.intern(self.db).into()
500                 }
501                 ast::ModuleItem::TypeAliasDef(def) => {
502                     let ast_id = self.expander.ast_id(&def);
503                     TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into()
504                 }
505                 ast::ModuleItem::ConstDef(def) => {
506                     let ast_id = self.expander.ast_id(&def);
507                     ConstLoc { container: container.into(), ast_id }.intern(self.db).into()
508                 }
509                 ast::ModuleItem::StaticDef(def) => {
510                     let ast_id = self.expander.ast_id(&def);
511                     StaticLoc { container, ast_id }.intern(self.db).into()
512                 }
513                 ast::ModuleItem::StructDef(def) => {
514                     let ast_id = self.expander.ast_id(&def);
515                     StructLoc { container, ast_id }.intern(self.db).into()
516                 }
517                 ast::ModuleItem::EnumDef(def) => {
518                     let ast_id = self.expander.ast_id(&def);
519                     EnumLoc { container, ast_id }.intern(self.db).into()
520                 }
521                 ast::ModuleItem::UnionDef(def) => {
522                     let ast_id = self.expander.ast_id(&def);
523                     UnionLoc { container, ast_id }.intern(self.db).into()
524                 }
525                 ast::ModuleItem::TraitDef(def) => {
526                     let ast_id = self.expander.ast_id(&def);
527                     TraitLoc { container, ast_id }.intern(self.db).into()
528                 }
529                 ast::ModuleItem::ImplBlock(_)
530                 | ast::ModuleItem::UseItem(_)
531                 | ast::ModuleItem::ExternCrateItem(_)
532                 | ast::ModuleItem::Module(_) => continue,
533             };
534             self.body.defs.push(def)
535         }
536     }
537
538     fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
539         if let Some(block) = expr {
540             self.collect_block(block)
541         } else {
542             self.missing_expr()
543         }
544     }
545
546     fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
547         let pattern = match &pat {
548             ast::Pat::BindPat(bp) => {
549                 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
550                 let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref());
551                 let subpat = bp.pat().map(|subpat| self.collect_pat(subpat));
552                 Pat::Bind { name, mode: annotation, subpat }
553             }
554             ast::Pat::TupleStructPat(p) => {
555                 let path = p.path().and_then(|path| self.expander.parse_path(path));
556                 let args = p.args().map(|p| self.collect_pat(p)).collect();
557                 Pat::TupleStruct { path, args }
558             }
559             ast::Pat::RefPat(p) => {
560                 let pat = self.collect_pat_opt(p.pat());
561                 let mutability = Mutability::from_mutable(p.is_mut());
562                 Pat::Ref { pat, mutability }
563             }
564             ast::Pat::PathPat(p) => {
565                 let path = p.path().and_then(|path| self.expander.parse_path(path));
566                 path.map(Pat::Path).unwrap_or(Pat::Missing)
567             }
568             ast::Pat::TuplePat(p) => {
569                 let args = p.args().map(|p| self.collect_pat(p)).collect();
570                 Pat::Tuple(args)
571             }
572             ast::Pat::PlaceholderPat(_) => Pat::Wild,
573             ast::Pat::RecordPat(p) => {
574                 let path = p.path().and_then(|path| self.expander.parse_path(path));
575                 let record_field_pat_list =
576                     p.record_field_pat_list().expect("every struct should have a field list");
577                 let mut fields: Vec<_> = record_field_pat_list
578                     .bind_pats()
579                     .filter_map(|bind_pat| {
580                         let ast_pat =
581                             ast::Pat::cast(bind_pat.syntax().clone()).expect("bind pat is a pat");
582                         let pat = self.collect_pat(ast_pat);
583                         let name = bind_pat.name()?.as_name();
584                         Some(RecordFieldPat { name, pat })
585                     })
586                     .collect();
587                 let iter = record_field_pat_list.record_field_pats().filter_map(|f| {
588                     let ast_pat = f.pat()?;
589                     let pat = self.collect_pat(ast_pat);
590                     let name = f.name()?.as_name();
591                     Some(RecordFieldPat { name, pat })
592                 });
593                 fields.extend(iter);
594
595                 Pat::Record { path, args: fields }
596             }
597
598             // FIXME: implement
599             ast::Pat::DotDotPat(_) => Pat::Missing,
600             ast::Pat::BoxPat(_) => Pat::Missing,
601             ast::Pat::LiteralPat(_) => Pat::Missing,
602             ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing,
603         };
604         let ptr = AstPtr::new(&pat);
605         self.alloc_pat(pattern, Either::Left(ptr))
606     }
607
608     fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
609         if let Some(pat) = pat {
610             self.collect_pat(pat)
611         } else {
612             self.missing_pat()
613         }
614     }
615 }
616
617 impl From<ast::BinOp> for BinaryOp {
618     fn from(ast_op: ast::BinOp) -> Self {
619         match ast_op {
620             ast::BinOp::BooleanOr => BinaryOp::LogicOp(LogicOp::Or),
621             ast::BinOp::BooleanAnd => BinaryOp::LogicOp(LogicOp::And),
622             ast::BinOp::EqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: false }),
623             ast::BinOp::NegatedEqualityTest => BinaryOp::CmpOp(CmpOp::Eq { negated: true }),
624             ast::BinOp::LesserEqualTest => {
625                 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false })
626             }
627             ast::BinOp::GreaterEqualTest => {
628                 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false })
629             }
630             ast::BinOp::LesserTest => {
631                 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: true })
632             }
633             ast::BinOp::GreaterTest => {
634                 BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true })
635             }
636             ast::BinOp::Addition => BinaryOp::ArithOp(ArithOp::Add),
637             ast::BinOp::Multiplication => BinaryOp::ArithOp(ArithOp::Mul),
638             ast::BinOp::Subtraction => BinaryOp::ArithOp(ArithOp::Sub),
639             ast::BinOp::Division => BinaryOp::ArithOp(ArithOp::Div),
640             ast::BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Rem),
641             ast::BinOp::LeftShift => BinaryOp::ArithOp(ArithOp::Shl),
642             ast::BinOp::RightShift => BinaryOp::ArithOp(ArithOp::Shr),
643             ast::BinOp::BitwiseXor => BinaryOp::ArithOp(ArithOp::BitXor),
644             ast::BinOp::BitwiseOr => BinaryOp::ArithOp(ArithOp::BitOr),
645             ast::BinOp::BitwiseAnd => BinaryOp::ArithOp(ArithOp::BitAnd),
646             ast::BinOp::Assignment => BinaryOp::Assignment { op: None },
647             ast::BinOp::AddAssign => BinaryOp::Assignment { op: Some(ArithOp::Add) },
648             ast::BinOp::DivAssign => BinaryOp::Assignment { op: Some(ArithOp::Div) },
649             ast::BinOp::MulAssign => BinaryOp::Assignment { op: Some(ArithOp::Mul) },
650             ast::BinOp::RemAssign => BinaryOp::Assignment { op: Some(ArithOp::Rem) },
651             ast::BinOp::ShlAssign => BinaryOp::Assignment { op: Some(ArithOp::Shl) },
652             ast::BinOp::ShrAssign => BinaryOp::Assignment { op: Some(ArithOp::Shr) },
653             ast::BinOp::SubAssign => BinaryOp::Assignment { op: Some(ArithOp::Sub) },
654             ast::BinOp::BitOrAssign => BinaryOp::Assignment { op: Some(ArithOp::BitOr) },
655             ast::BinOp::BitAndAssign => BinaryOp::Assignment { op: Some(ArithOp::BitAnd) },
656             ast::BinOp::BitXorAssign => BinaryOp::Assignment { op: Some(ArithOp::BitXor) },
657         }
658     }
659 }