• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
2 //! representation.
3 
4 use std::mem;
5 
6 use base_db::CrateId;
7 use either::Either;
8 use hir_expand::{
9     ast_id_map::AstIdMap,
10     name::{name, AsName, Name},
11     AstId, ExpandError, InFile,
12 };
13 use intern::Interned;
14 use profile::Count;
15 use rustc_hash::FxHashMap;
16 use smallvec::SmallVec;
17 use syntax::{
18     ast::{
19         self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasLoopBody, HasName,
20         SlicePatComponents,
21     },
22     AstNode, AstPtr, SyntaxNodePtr,
23 };
24 use triomphe::Arc;
25 
26 use crate::{
27     body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, LabelPtr, PatPtr},
28     data::adt::StructKind,
29     db::DefDatabase,
30     expander::Expander,
31     hir::{
32         dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy,
33         ClosureKind, Expr, ExprId, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability,
34         Pat, PatId, RecordFieldPat, RecordLitField, Statement,
35     },
36     item_scope::BuiltinShadowMode,
37     lang_item::LangItem,
38     lower::LowerCtx,
39     nameres::{DefMap, MacroSubNs},
40     path::{GenericArgs, Path},
41     type_ref::{Mutability, Rawness, TypeRef},
42     AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, ModuleDefId, UnresolvedMacro,
43 };
44 
lower( db: &dyn DefDatabase, owner: DefWithBodyId, expander: Expander, params: Option<(ast::ParamList, impl Iterator<Item = bool>)>, body: Option<ast::Expr>, krate: CrateId, is_async_fn: bool, ) -> (Body, BodySourceMap)45 pub(super) fn lower(
46     db: &dyn DefDatabase,
47     owner: DefWithBodyId,
48     expander: Expander,
49     params: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
50     body: Option<ast::Expr>,
51     krate: CrateId,
52     is_async_fn: bool,
53 ) -> (Body, BodySourceMap) {
54     ExprCollector {
55         db,
56         owner,
57         krate,
58         def_map: expander.module.def_map(db),
59         source_map: BodySourceMap::default(),
60         ast_id_map: db.ast_id_map(expander.current_file_id),
61         body: Body {
62             exprs: Default::default(),
63             pats: Default::default(),
64             bindings: Default::default(),
65             binding_owners: Default::default(),
66             labels: Default::default(),
67             params: Vec::new(),
68             body_expr: dummy_expr_id(),
69             block_scopes: Vec::new(),
70             _c: Count::new(),
71         },
72         expander,
73         current_try_block_label: None,
74         is_lowering_assignee_expr: false,
75         is_lowering_generator: false,
76         label_ribs: Vec::new(),
77         current_binding_owner: None,
78     }
79     .collect(params, body, is_async_fn)
80 }
81 
82 struct ExprCollector<'a> {
83     db: &'a dyn DefDatabase,
84     expander: Expander,
85     owner: DefWithBodyId,
86     def_map: Arc<DefMap>,
87     ast_id_map: Arc<AstIdMap>,
88     krate: CrateId,
89     body: Body,
90     source_map: BodySourceMap,
91 
92     is_lowering_assignee_expr: bool,
93     is_lowering_generator: bool,
94 
95     current_try_block_label: Option<LabelId>,
96     // points to the expression that a try expression will target (replaces current_try_block_label)
97     // catch_scope: Option<ExprId>,
98     // points to the expression that an unlabeled control flow will target
99     // loop_scope: Option<ExprId>,
100     // needed to diagnose non label control flow in while conditions
101     // is_in_loop_condition: bool,
102 
103     // resolution
104     label_ribs: Vec<LabelRib>,
105     current_binding_owner: Option<ExprId>,
106 }
107 
108 #[derive(Clone, Debug)]
109 struct LabelRib {
110     kind: RibKind,
111     // Once we handle macro hygiene this will need to be a map
112     label: Option<(Name, LabelId)>,
113 }
114 
115 impl LabelRib {
new(kind: RibKind) -> Self116     fn new(kind: RibKind) -> Self {
117         LabelRib { kind, label: None }
118     }
new_normal(label: (Name, LabelId)) -> Self119     fn new_normal(label: (Name, LabelId)) -> Self {
120         LabelRib { kind: RibKind::Normal, label: Some(label) }
121     }
122 }
123 
124 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
125 enum RibKind {
126     Normal,
127     Closure,
128     Constant,
129 }
130 
131 impl RibKind {
132     /// This rib forbids referring to labels defined in upwards ribs.
is_label_barrier(self) -> bool133     fn is_label_barrier(self) -> bool {
134         match self {
135             RibKind::Normal => false,
136             RibKind::Closure | RibKind::Constant => true,
137         }
138     }
139 }
140 
141 #[derive(Debug, Default)]
142 struct BindingList {
143     map: FxHashMap<Name, BindingId>,
144     is_used: FxHashMap<BindingId, bool>,
145     reject_new: bool,
146 }
147 
148 impl BindingList {
find( &mut self, ec: &mut ExprCollector<'_>, name: Name, mode: BindingAnnotation, ) -> BindingId149     fn find(
150         &mut self,
151         ec: &mut ExprCollector<'_>,
152         name: Name,
153         mode: BindingAnnotation,
154     ) -> BindingId {
155         let id = *self.map.entry(name).or_insert_with_key(|n| ec.alloc_binding(n.clone(), mode));
156         if ec.body.bindings[id].mode != mode {
157             ec.body.bindings[id].problems = Some(BindingProblems::BoundInconsistently);
158         }
159         self.check_is_used(ec, id);
160         id
161     }
162 
check_is_used(&mut self, ec: &mut ExprCollector<'_>, id: BindingId)163     fn check_is_used(&mut self, ec: &mut ExprCollector<'_>, id: BindingId) {
164         match self.is_used.get(&id) {
165             None => {
166                 if self.reject_new {
167                     ec.body.bindings[id].problems = Some(BindingProblems::NotBoundAcrossAll);
168                 }
169             }
170             Some(true) => {
171                 ec.body.bindings[id].problems = Some(BindingProblems::BoundMoreThanOnce);
172             }
173             Some(false) => {}
174         }
175         self.is_used.insert(id, true);
176     }
177 }
178 
179 impl ExprCollector<'_> {
collect( mut self, param_list: Option<(ast::ParamList, impl Iterator<Item = bool>)>, body: Option<ast::Expr>, is_async_fn: bool, ) -> (Body, BodySourceMap)180     fn collect(
181         mut self,
182         param_list: Option<(ast::ParamList, impl Iterator<Item = bool>)>,
183         body: Option<ast::Expr>,
184         is_async_fn: bool,
185     ) -> (Body, BodySourceMap) {
186         if let Some((param_list, mut attr_enabled)) = param_list {
187             if let Some(self_param) =
188                 param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
189             {
190                 let ptr = AstPtr::new(&self_param);
191                 let binding_id: la_arena::Idx<Binding> = self.alloc_binding(
192                     name![self],
193                     BindingAnnotation::new(
194                         self_param.mut_token().is_some() && self_param.amp_token().is_none(),
195                         false,
196                     ),
197                 );
198                 let param_pat =
199                     self.alloc_pat(Pat::Bind { id: binding_id, subpat: None }, Either::Right(ptr));
200                 self.add_definition_to_binding(binding_id, param_pat);
201                 self.body.params.push(param_pat);
202             }
203 
204             for (param, _) in param_list.params().zip(attr_enabled).filter(|(_, enabled)| *enabled)
205             {
206                 let param_pat = self.collect_pat_top(param.pat());
207                 self.body.params.push(param_pat);
208             }
209         };
210         self.body.body_expr = self.with_label_rib(RibKind::Closure, |this| {
211             if is_async_fn {
212                 match body {
213                     Some(e) => {
214                         let expr = this.collect_expr(e);
215                         this.alloc_expr_desugared(Expr::Async {
216                             id: None,
217                             statements: Box::new([]),
218                             tail: Some(expr),
219                         })
220                     }
221                     None => this.missing_expr(),
222                 }
223             } else {
224                 this.collect_expr_opt(body)
225             }
226         });
227 
228         (self.body, self.source_map)
229     }
230 
ctx(&self) -> LowerCtx<'_>231     fn ctx(&self) -> LowerCtx<'_> {
232         self.expander.ctx(self.db)
233     }
234 
collect_expr(&mut self, expr: ast::Expr) -> ExprId235     fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
236         self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr())
237     }
238 
239     /// Returns `None` if and only if the expression is `#[cfg]`d out.
maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId>240     fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
241         let syntax_ptr = AstPtr::new(&expr);
242         self.check_cfg(&expr)?;
243 
244         // FIXME: Move some of these arms out into separate methods for clarity
245         Some(match expr {
246             ast::Expr::IfExpr(e) => {
247                 let then_branch = self.collect_block_opt(e.then_branch());
248 
249                 let else_branch = e.else_branch().map(|b| match b {
250                     ast::ElseBranch::Block(it) => self.collect_block(it),
251                     ast::ElseBranch::IfExpr(elif) => {
252                         let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
253                         self.collect_expr(expr)
254                     }
255                 });
256 
257                 let condition = self.collect_expr_opt(e.condition());
258 
259                 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
260             }
261             ast::Expr::LetExpr(e) => {
262                 let pat = self.collect_pat_top(e.pat());
263                 let expr = self.collect_expr_opt(e.expr());
264                 self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr)
265             }
266             ast::Expr::BlockExpr(e) => match e.modifier() {
267                 Some(ast::BlockModifier::Try(_)) => self.desugar_try_block(e),
268                 Some(ast::BlockModifier::Unsafe(_)) => {
269                     self.collect_block_(e, |id, statements, tail| Expr::Unsafe {
270                         id,
271                         statements,
272                         tail,
273                     })
274                 }
275                 Some(ast::BlockModifier::Label(label)) => {
276                     let label = self.collect_label(label);
277                     self.with_labeled_rib(label, |this| {
278                         this.collect_block_(e, |id, statements, tail| Expr::Block {
279                             id,
280                             statements,
281                             tail,
282                             label: Some(label),
283                         })
284                     })
285                 }
286                 Some(ast::BlockModifier::Async(_)) => {
287                     self.with_label_rib(RibKind::Closure, |this| {
288                         this.collect_block_(e, |id, statements, tail| Expr::Async {
289                             id,
290                             statements,
291                             tail,
292                         })
293                     })
294                 }
295                 Some(ast::BlockModifier::Const(_)) => {
296                     self.with_label_rib(RibKind::Constant, |this| {
297                         let (result_expr_id, prev_binding_owner) =
298                             this.initialize_binding_owner(syntax_ptr);
299                         let inner_expr = this.collect_block(e);
300                         let x = this.db.intern_anonymous_const(ConstBlockLoc {
301                             parent: this.owner,
302                             root: inner_expr,
303                         });
304                         this.body.exprs[result_expr_id] = Expr::Const(x);
305                         this.current_binding_owner = prev_binding_owner;
306                         result_expr_id
307                     })
308                 }
309                 None => self.collect_block(e),
310             },
311             ast::Expr::LoopExpr(e) => {
312                 let label = e.label().map(|label| self.collect_label(label));
313                 let body = self.collect_labelled_block_opt(label, e.loop_body());
314                 self.alloc_expr(Expr::Loop { body, label }, syntax_ptr)
315             }
316             ast::Expr::WhileExpr(e) => {
317                 let label = e.label().map(|label| self.collect_label(label));
318                 let body = self.collect_labelled_block_opt(label, e.loop_body());
319                 let condition = self.collect_expr_opt(e.condition());
320 
321                 self.alloc_expr(Expr::While { condition, body, label }, syntax_ptr)
322             }
323             ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e),
324             ast::Expr::CallExpr(e) => {
325                 let is_rustc_box = {
326                     let attrs = e.attrs();
327                     attrs.filter_map(|x| x.as_simple_atom()).any(|x| x == "rustc_box")
328                 };
329                 if is_rustc_box {
330                     let expr = self.collect_expr_opt(e.arg_list().and_then(|x| x.args().next()));
331                     self.alloc_expr(Expr::Box { expr }, syntax_ptr)
332                 } else {
333                     let callee = self.collect_expr_opt(e.expr());
334                     let args = if let Some(arg_list) = e.arg_list() {
335                         arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
336                     } else {
337                         Box::default()
338                     };
339                     self.alloc_expr(
340                         Expr::Call {
341                             callee,
342                             args,
343                             is_assignee_expr: self.is_lowering_assignee_expr,
344                         },
345                         syntax_ptr,
346                     )
347                 }
348             }
349             ast::Expr::MethodCallExpr(e) => {
350                 let receiver = self.collect_expr_opt(e.receiver());
351                 let args = if let Some(arg_list) = e.arg_list() {
352                     arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
353                 } else {
354                     Box::default()
355                 };
356                 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
357                 let generic_args = e
358                     .generic_arg_list()
359                     .and_then(|it| GenericArgs::from_ast(&self.ctx(), it))
360                     .map(Box::new);
361                 self.alloc_expr(
362                     Expr::MethodCall { receiver, method_name, args, generic_args },
363                     syntax_ptr,
364                 )
365             }
366             ast::Expr::MatchExpr(e) => {
367                 let expr = self.collect_expr_opt(e.expr());
368                 let arms = if let Some(match_arm_list) = e.match_arm_list() {
369                     match_arm_list
370                         .arms()
371                         .filter_map(|arm| {
372                             self.check_cfg(&arm).map(|()| MatchArm {
373                                 pat: self.collect_pat_top(arm.pat()),
374                                 expr: self.collect_expr_opt(arm.expr()),
375                                 guard: arm
376                                     .guard()
377                                     .map(|guard| self.collect_expr_opt(guard.condition())),
378                             })
379                         })
380                         .collect()
381                 } else {
382                     Box::default()
383                 };
384                 self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
385             }
386             ast::Expr::PathExpr(e) => {
387                 let path = e
388                     .path()
389                     .and_then(|path| self.expander.parse_path(self.db, path))
390                     .map(Expr::Path)
391                     .unwrap_or(Expr::Missing);
392                 self.alloc_expr(path, syntax_ptr)
393             }
394             ast::Expr::ContinueExpr(e) => {
395                 let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {
396                     self.source_map.diagnostics.push(e);
397                     None
398                 });
399                 self.alloc_expr(Expr::Continue { label }, syntax_ptr)
400             }
401             ast::Expr::BreakExpr(e) => {
402                 let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {
403                     self.source_map.diagnostics.push(e);
404                     None
405                 });
406                 let expr = e.expr().map(|e| self.collect_expr(e));
407                 self.alloc_expr(Expr::Break { expr, label }, syntax_ptr)
408             }
409             ast::Expr::ParenExpr(e) => {
410                 let inner = self.collect_expr_opt(e.expr());
411                 // make the paren expr point to the inner expression as well
412                 let src = self.expander.to_source(syntax_ptr);
413                 self.source_map.expr_map.insert(src, inner);
414                 inner
415             }
416             ast::Expr::ReturnExpr(e) => {
417                 let expr = e.expr().map(|e| self.collect_expr(e));
418                 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
419             }
420             ast::Expr::YieldExpr(e) => {
421                 self.is_lowering_generator = true;
422                 let expr = e.expr().map(|e| self.collect_expr(e));
423                 self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
424             }
425             ast::Expr::YeetExpr(e) => {
426                 let expr = e.expr().map(|e| self.collect_expr(e));
427                 self.alloc_expr(Expr::Yeet { expr }, syntax_ptr)
428             }
429             ast::Expr::RecordExpr(e) => {
430                 let path =
431                     e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
432                 let is_assignee_expr = self.is_lowering_assignee_expr;
433                 let record_lit = if let Some(nfl) = e.record_expr_field_list() {
434                     let fields = nfl
435                         .fields()
436                         .filter_map(|field| {
437                             self.check_cfg(&field)?;
438 
439                             let name = field.field_name()?.as_name();
440 
441                             let expr = match field.expr() {
442                                 Some(e) => self.collect_expr(e),
443                                 None => self.missing_expr(),
444                             };
445                             let src = self.expander.to_source(AstPtr::new(&field));
446                             self.source_map.field_map.insert(src.clone(), expr);
447                             self.source_map.field_map_back.insert(expr, src);
448                             Some(RecordLitField { name, expr })
449                         })
450                         .collect();
451                     let spread = nfl.spread().map(|s| self.collect_expr(s));
452                     let ellipsis = nfl.dotdot_token().is_some();
453                     Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr }
454                 } else {
455                     Expr::RecordLit {
456                         path,
457                         fields: Box::default(),
458                         spread: None,
459                         ellipsis: false,
460                         is_assignee_expr,
461                     }
462                 };
463 
464                 self.alloc_expr(record_lit, syntax_ptr)
465             }
466             ast::Expr::FieldExpr(e) => {
467                 let expr = self.collect_expr_opt(e.expr());
468                 let name = match e.field_access() {
469                     Some(kind) => kind.as_name(),
470                     _ => Name::missing(),
471                 };
472                 self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
473             }
474             ast::Expr::AwaitExpr(e) => {
475                 let expr = self.collect_expr_opt(e.expr());
476                 self.alloc_expr(Expr::Await { expr }, syntax_ptr)
477             }
478             ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e),
479             ast::Expr::CastExpr(e) => {
480                 let expr = self.collect_expr_opt(e.expr());
481                 let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
482                 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
483             }
484             ast::Expr::RefExpr(e) => {
485                 let expr = self.collect_expr_opt(e.expr());
486                 let raw_tok = e.raw_token().is_some();
487                 let mutability = if raw_tok {
488                     if e.mut_token().is_some() {
489                         Mutability::Mut
490                     } else if e.const_token().is_some() {
491                         Mutability::Shared
492                     } else {
493                         unreachable!("parser only remaps to raw_token() if matching mutability token follows")
494                     }
495                 } else {
496                     Mutability::from_mutable(e.mut_token().is_some())
497                 };
498                 let rawness = Rawness::from_raw(raw_tok);
499                 self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)
500             }
501             ast::Expr::PrefixExpr(e) => {
502                 let expr = self.collect_expr_opt(e.expr());
503                 match e.op_kind() {
504                     Some(op) => self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr),
505                     None => self.alloc_expr(Expr::Missing, syntax_ptr),
506                 }
507             }
508             ast::Expr::ClosureExpr(e) => self.with_label_rib(RibKind::Closure, |this| {
509                 let (result_expr_id, prev_binding_owner) =
510                     this.initialize_binding_owner(syntax_ptr);
511                 let mut args = Vec::new();
512                 let mut arg_types = Vec::new();
513                 if let Some(pl) = e.param_list() {
514                     for param in pl.params() {
515                         let pat = this.collect_pat_top(param.pat());
516                         let type_ref =
517                             param.ty().map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
518                         args.push(pat);
519                         arg_types.push(type_ref);
520                     }
521                 }
522                 let ret_type = e
523                     .ret_type()
524                     .and_then(|r| r.ty())
525                     .map(|it| Interned::new(TypeRef::from_ast(&this.ctx(), it)));
526 
527                 let prev_is_lowering_generator = mem::take(&mut this.is_lowering_generator);
528                 let prev_try_block_label = this.current_try_block_label.take();
529 
530                 let body = this.collect_expr_opt(e.body());
531 
532                 let closure_kind = if this.is_lowering_generator {
533                     let movability = if e.static_token().is_some() {
534                         Movability::Static
535                     } else {
536                         Movability::Movable
537                     };
538                     ClosureKind::Generator(movability)
539                 } else if e.async_token().is_some() {
540                     ClosureKind::Async
541                 } else {
542                     ClosureKind::Closure
543                 };
544                 let capture_by =
545                     if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };
546                 this.is_lowering_generator = prev_is_lowering_generator;
547                 this.current_binding_owner = prev_binding_owner;
548                 this.current_try_block_label = prev_try_block_label;
549                 this.body.exprs[result_expr_id] = Expr::Closure {
550                     args: args.into(),
551                     arg_types: arg_types.into(),
552                     ret_type,
553                     body,
554                     closure_kind,
555                     capture_by,
556                 };
557                 result_expr_id
558             }),
559             ast::Expr::BinExpr(e) => {
560                 let op = e.op_kind();
561                 if let Some(ast::BinaryOp::Assignment { op: None }) = op {
562                     self.is_lowering_assignee_expr = true;
563                 }
564                 let lhs = self.collect_expr_opt(e.lhs());
565                 self.is_lowering_assignee_expr = false;
566                 let rhs = self.collect_expr_opt(e.rhs());
567                 self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
568             }
569             ast::Expr::TupleExpr(e) => {
570                 let mut exprs: Vec<_> = e.fields().map(|expr| self.collect_expr(expr)).collect();
571                 // if there is a leading comma, the user is most likely to type out a leading expression
572                 // so we insert a missing expression at the beginning for IDE features
573                 if comma_follows_token(e.l_paren_token()) {
574                     exprs.insert(0, self.missing_expr());
575                 }
576 
577                 self.alloc_expr(
578                     Expr::Tuple {
579                         exprs: exprs.into_boxed_slice(),
580                         is_assignee_expr: self.is_lowering_assignee_expr,
581                     },
582                     syntax_ptr,
583                 )
584             }
585             ast::Expr::BoxExpr(e) => {
586                 let expr = self.collect_expr_opt(e.expr());
587                 self.alloc_expr(Expr::Box { expr }, syntax_ptr)
588             }
589 
590             ast::Expr::ArrayExpr(e) => {
591                 let kind = e.kind();
592 
593                 match kind {
594                     ArrayExprKind::ElementList(e) => {
595                         let elements = e.map(|expr| self.collect_expr(expr)).collect();
596                         self.alloc_expr(
597                             Expr::Array(Array::ElementList {
598                                 elements,
599                                 is_assignee_expr: self.is_lowering_assignee_expr,
600                             }),
601                             syntax_ptr,
602                         )
603                     }
604                     ArrayExprKind::Repeat { initializer, repeat } => {
605                         let initializer = self.collect_expr_opt(initializer);
606                         let repeat = self.with_label_rib(RibKind::Constant, |this| {
607                             if let Some(repeat) = repeat {
608                                 let syntax_ptr = AstPtr::new(&repeat);
609                                 this.collect_as_a_binding_owner_bad(
610                                     |this| this.collect_expr(repeat),
611                                     syntax_ptr,
612                                 )
613                             } else {
614                                 this.missing_expr()
615                             }
616                         });
617                         self.alloc_expr(
618                             Expr::Array(Array::Repeat { initializer, repeat }),
619                             syntax_ptr,
620                         )
621                     }
622                 }
623             }
624 
625             ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr),
626             ast::Expr::IndexExpr(e) => {
627                 let base = self.collect_expr_opt(e.base());
628                 let index = self.collect_expr_opt(e.index());
629                 self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
630             }
631             ast::Expr::RangeExpr(e) => {
632                 let lhs = e.start().map(|lhs| self.collect_expr(lhs));
633                 let rhs = e.end().map(|rhs| self.collect_expr(rhs));
634                 match e.op_kind() {
635                     Some(range_type) => {
636                         self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)
637                     }
638                     None => self.alloc_expr(Expr::Missing, syntax_ptr),
639                 }
640             }
641             ast::Expr::MacroExpr(e) => {
642                 let e = e.macro_call()?;
643                 let macro_ptr = AstPtr::new(&e);
644                 let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
645                     expansion.map(|it| this.collect_expr(it))
646                 });
647                 match id {
648                     Some(id) => {
649                         // Make the macro-call point to its expanded expression so we can query
650                         // semantics on syntax pointers to the macro
651                         let src = self.expander.to_source(syntax_ptr);
652                         self.source_map.expr_map.insert(src, id);
653                         id
654                     }
655                     None => self.alloc_expr(Expr::Missing, syntax_ptr),
656                 }
657             }
658             ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
659         })
660     }
661 
initialize_binding_owner( &mut self, syntax_ptr: AstPtr<ast::Expr>, ) -> (ExprId, Option<ExprId>)662     fn initialize_binding_owner(
663         &mut self,
664         syntax_ptr: AstPtr<ast::Expr>,
665     ) -> (ExprId, Option<ExprId>) {
666         let result_expr_id = self.alloc_expr(Expr::Missing, syntax_ptr);
667         let prev_binding_owner = self.current_binding_owner.take();
668         self.current_binding_owner = Some(result_expr_id);
669         (result_expr_id, prev_binding_owner)
670     }
671 
672     /// FIXME: This function is bad. It will produce a dangling `Missing` expr which wastes memory. Currently
673     /// it is used only for const blocks and repeat expressions, which are also hacky and ideally should have
674     /// their own body. Don't add more usage for this function so that we can remove this function after
675     /// separating those bodies.
collect_as_a_binding_owner_bad( &mut self, job: impl FnOnce(&mut ExprCollector<'_>) -> ExprId, syntax_ptr: AstPtr<ast::Expr>, ) -> ExprId676     fn collect_as_a_binding_owner_bad(
677         &mut self,
678         job: impl FnOnce(&mut ExprCollector<'_>) -> ExprId,
679         syntax_ptr: AstPtr<ast::Expr>,
680     ) -> ExprId {
681         let (id, prev_owner) = self.initialize_binding_owner(syntax_ptr);
682         let tmp = job(self);
683         self.body.exprs[id] = mem::replace(&mut self.body.exprs[tmp], Expr::Missing);
684         self.current_binding_owner = prev_owner;
685         id
686     }
687 
688     /// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`,
689     /// `try { <stmts>; }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(()) }`
690     /// and save the `<new_label>` to use it as a break target for desugaring of the `?` operator.
desugar_try_block(&mut self, e: BlockExpr) -> ExprId691     fn desugar_try_block(&mut self, e: BlockExpr) -> ExprId {
692         let Some(try_from_output) = LangItem::TryTraitFromOutput.path(self.db, self.krate) else {
693             return self.collect_block(e);
694         };
695         let label = self.alloc_label_desugared(Label { name: Name::generate_new_name() });
696         let old_label = self.current_try_block_label.replace(label);
697 
698         let (btail, expr_id) = self.with_labeled_rib(label, |this| {
699             let mut btail = None;
700             let block = this.collect_block_(e, |id, statements, tail| {
701                 btail = tail;
702                 Expr::Block { id, statements, tail, label: Some(label) }
703             });
704             (btail, block)
705         });
706 
707         let callee = self.alloc_expr_desugared(Expr::Path(try_from_output));
708         let next_tail = match btail {
709             Some(tail) => self.alloc_expr_desugared(Expr::Call {
710                 callee,
711                 args: Box::new([tail]),
712                 is_assignee_expr: false,
713             }),
714             None => {
715                 let unit = self.alloc_expr_desugared(Expr::Tuple {
716                     exprs: Box::new([]),
717                     is_assignee_expr: false,
718                 });
719                 self.alloc_expr_desugared(Expr::Call {
720                     callee,
721                     args: Box::new([unit]),
722                     is_assignee_expr: false,
723                 })
724             }
725         };
726         let Expr::Block { tail, .. } = &mut self.body.exprs[expr_id] else {
727             unreachable!("block was lowered to non-block");
728         };
729         *tail = Some(next_tail);
730         self.current_try_block_label = old_label;
731         expr_id
732     }
733 
734     /// Desugar `ast::ForExpr` from: `[opt_ident]: for <pat> in <head> <body>` into:
735     /// ```ignore (pseudo-rust)
736     /// match IntoIterator::into_iter(<head>) {
737     ///     mut iter => {
738     ///         [opt_ident]: loop {
739     ///             match Iterator::next(&mut iter) {
740     ///                 None => break,
741     ///                 Some(<pat>) => <body>,
742     ///             };
743     ///         }
744     ///     }
745     /// }
746     /// ```
collect_for_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::ForExpr) -> ExprId747     fn collect_for_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::ForExpr) -> ExprId {
748         let Some((into_iter_fn, iter_next_fn, option_some, option_none)) = (|| {
749             Some((
750                 LangItem::IntoIterIntoIter.path(self.db, self.krate)?,
751                 LangItem::IteratorNext.path(self.db, self.krate)?,
752                 LangItem::OptionSome.path(self.db, self.krate)?,
753                 LangItem::OptionNone.path(self.db, self.krate)?,
754             ))
755         })() else {
756             // Some of the needed lang items are missing, so we can't desugar
757             return self.alloc_expr(Expr::Missing, syntax_ptr);
758         };
759         let head = self.collect_expr_opt(e.iterable());
760         let into_iter_fn_expr = self.alloc_expr(Expr::Path(into_iter_fn), syntax_ptr.clone());
761         let iterator = self.alloc_expr(
762             Expr::Call {
763                 callee: into_iter_fn_expr,
764                 args: Box::new([head]),
765                 is_assignee_expr: false,
766             },
767             syntax_ptr.clone(),
768         );
769         let none_arm = MatchArm {
770             pat: self.alloc_pat_desugared(Pat::Path(Box::new(option_none))),
771             guard: None,
772             expr: self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr.clone()),
773         };
774         let some_pat = Pat::TupleStruct {
775             path: Some(Box::new(option_some)),
776             args: Box::new([self.collect_pat_top(e.pat())]),
777             ellipsis: None,
778         };
779         let label = e.label().map(|label| self.collect_label(label));
780         let some_arm = MatchArm {
781             pat: self.alloc_pat_desugared(some_pat),
782             guard: None,
783             expr: self.with_opt_labeled_rib(label, |this| {
784                 this.collect_expr_opt(e.loop_body().map(|x| x.into()))
785             }),
786         };
787         let iter_name = Name::generate_new_name();
788         let iter_expr =
789             self.alloc_expr(Expr::Path(Path::from(iter_name.clone())), syntax_ptr.clone());
790         let iter_expr_mut = self.alloc_expr(
791             Expr::Ref { expr: iter_expr, rawness: Rawness::Ref, mutability: Mutability::Mut },
792             syntax_ptr.clone(),
793         );
794         let iter_next_fn_expr = self.alloc_expr(Expr::Path(iter_next_fn), syntax_ptr.clone());
795         let iter_next_expr = self.alloc_expr(
796             Expr::Call {
797                 callee: iter_next_fn_expr,
798                 args: Box::new([iter_expr_mut]),
799                 is_assignee_expr: false,
800             },
801             syntax_ptr.clone(),
802         );
803         let loop_inner = self.alloc_expr(
804             Expr::Match { expr: iter_next_expr, arms: Box::new([none_arm, some_arm]) },
805             syntax_ptr.clone(),
806         );
807         let loop_outer =
808             self.alloc_expr(Expr::Loop { body: loop_inner, label }, syntax_ptr.clone());
809         let iter_binding = self.alloc_binding(iter_name, BindingAnnotation::Mutable);
810         let iter_pat = self.alloc_pat_desugared(Pat::Bind { id: iter_binding, subpat: None });
811         self.add_definition_to_binding(iter_binding, iter_pat);
812         self.alloc_expr(
813             Expr::Match {
814                 expr: iterator,
815                 arms: Box::new([MatchArm { pat: iter_pat, guard: None, expr: loop_outer }]),
816             },
817             syntax_ptr.clone(),
818         )
819     }
820 
821     /// Desugar `ast::TryExpr` from: `<expr>?` into:
822     /// ```ignore (pseudo-rust)
823     /// match Try::branch(<expr>) {
824     ///     ControlFlow::Continue(val) => val,
825     ///     ControlFlow::Break(residual) =>
826     ///         // If there is an enclosing `try {...}`:
827     ///         break 'catch_target Try::from_residual(residual),
828     ///         // Otherwise:
829     ///         return Try::from_residual(residual),
830     /// }
831     /// ```
collect_try_operator(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::TryExpr) -> ExprId832     fn collect_try_operator(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::TryExpr) -> ExprId {
833         let Some((try_branch, cf_continue, cf_break, try_from_residual)) = (|| {
834             Some((
835                 LangItem::TryTraitBranch.path(self.db, self.krate)?,
836                 LangItem::ControlFlowContinue.path(self.db, self.krate)?,
837                 LangItem::ControlFlowBreak.path(self.db, self.krate)?,
838                 LangItem::TryTraitFromResidual.path(self.db, self.krate)?,
839             ))
840         })() else {
841             // Some of the needed lang items are missing, so we can't desugar
842             return self.alloc_expr(Expr::Missing, syntax_ptr);
843         };
844         let operand = self.collect_expr_opt(e.expr());
845         let try_branch = self.alloc_expr(Expr::Path(try_branch), syntax_ptr.clone());
846         let expr = self.alloc_expr(
847             Expr::Call { callee: try_branch, args: Box::new([operand]), is_assignee_expr: false },
848             syntax_ptr.clone(),
849         );
850         let continue_name = Name::generate_new_name();
851         let continue_binding =
852             self.alloc_binding(continue_name.clone(), BindingAnnotation::Unannotated);
853         let continue_bpat =
854             self.alloc_pat_desugared(Pat::Bind { id: continue_binding, subpat: None });
855         self.add_definition_to_binding(continue_binding, continue_bpat);
856         let continue_arm = MatchArm {
857             pat: self.alloc_pat_desugared(Pat::TupleStruct {
858                 path: Some(Box::new(cf_continue)),
859                 args: Box::new([continue_bpat]),
860                 ellipsis: None,
861             }),
862             guard: None,
863             expr: self.alloc_expr(Expr::Path(Path::from(continue_name)), syntax_ptr.clone()),
864         };
865         let break_name = Name::generate_new_name();
866         let break_binding = self.alloc_binding(break_name.clone(), BindingAnnotation::Unannotated);
867         let break_bpat = self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None });
868         self.add_definition_to_binding(break_binding, break_bpat);
869         let break_arm = MatchArm {
870             pat: self.alloc_pat_desugared(Pat::TupleStruct {
871                 path: Some(Box::new(cf_break)),
872                 args: Box::new([break_bpat]),
873                 ellipsis: None,
874             }),
875             guard: None,
876             expr: {
877                 let x = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr.clone());
878                 let callee = self.alloc_expr(Expr::Path(try_from_residual), syntax_ptr.clone());
879                 let result = self.alloc_expr(
880                     Expr::Call { callee, args: Box::new([x]), is_assignee_expr: false },
881                     syntax_ptr.clone(),
882                 );
883                 self.alloc_expr(
884                     match self.current_try_block_label {
885                         Some(label) => Expr::Break { expr: Some(result), label: Some(label) },
886                         None => Expr::Return { expr: Some(result) },
887                     },
888                     syntax_ptr.clone(),
889                 )
890             },
891         };
892         let arms = Box::new([continue_arm, break_arm]);
893         self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
894     }
895 
collect_macro_call<F, T, U>( &mut self, mcall: ast::MacroCall, syntax_ptr: AstPtr<ast::MacroCall>, record_diagnostics: bool, collector: F, ) -> U where F: FnOnce(&mut Self, Option<T>) -> U, T: ast::AstNode,896     fn collect_macro_call<F, T, U>(
897         &mut self,
898         mcall: ast::MacroCall,
899         syntax_ptr: AstPtr<ast::MacroCall>,
900         record_diagnostics: bool,
901         collector: F,
902     ) -> U
903     where
904         F: FnOnce(&mut Self, Option<T>) -> U,
905         T: ast::AstNode,
906     {
907         // File containing the macro call. Expansion errors will be attached here.
908         let outer_file = self.expander.current_file_id;
909 
910         let macro_call_ptr = self.expander.to_source(AstPtr::new(&mcall));
911         let module = self.expander.module.local_id;
912         let res = self.expander.enter_expand(self.db, mcall, |path| {
913             self.def_map
914                 .resolve_path(
915                     self.db,
916                     module,
917                     &path,
918                     crate::item_scope::BuiltinShadowMode::Other,
919                     Some(MacroSubNs::Bang),
920                 )
921                 .0
922                 .take_macros()
923         });
924 
925         let res = match res {
926             Ok(res) => res,
927             Err(UnresolvedMacro { path }) => {
928                 if record_diagnostics {
929                     self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall {
930                         node: InFile::new(outer_file, syntax_ptr),
931                         path,
932                     });
933                 }
934                 return collector(self, None);
935             }
936         };
937 
938         if record_diagnostics {
939             match &res.err {
940                 Some(ExpandError::UnresolvedProcMacro(krate)) => {
941                     self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro {
942                         node: InFile::new(outer_file, syntax_ptr),
943                         krate: *krate,
944                     });
945                 }
946                 Some(ExpandError::RecursionOverflowPoisoned) => {
947                     // Recursion limit has been reached in the macro expansion tree, but not in
948                     // this very macro call. Don't add diagnostics to avoid duplication.
949                 }
950                 Some(err) => {
951                     self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
952                         node: InFile::new(outer_file, syntax_ptr),
953                         message: err.to_string(),
954                     });
955                 }
956                 None => {}
957             }
958         }
959 
960         match res.value {
961             Some((mark, expansion)) => {
962                 // Keep collecting even with expansion errors so we can provide completions and
963                 // other services in incomplete macro expressions.
964                 self.source_map.expansions.insert(macro_call_ptr, self.expander.current_file_id);
965                 let prev_ast_id_map = mem::replace(
966                     &mut self.ast_id_map,
967                     self.db.ast_id_map(self.expander.current_file_id),
968                 );
969 
970                 if record_diagnostics {
971                     // FIXME: Report parse errors here
972                 }
973 
974                 let id = collector(self, Some(expansion.tree()));
975                 self.ast_id_map = prev_ast_id_map;
976                 self.expander.exit(self.db, mark);
977                 id
978             }
979             None => collector(self, None),
980         }
981     }
982 
collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId983     fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
984         match expr {
985             Some(expr) => self.collect_expr(expr),
986             None => self.missing_expr(),
987         }
988     }
989 
collect_macro_as_stmt( &mut self, statements: &mut Vec<Statement>, mac: ast::MacroExpr, ) -> Option<ExprId>990     fn collect_macro_as_stmt(
991         &mut self,
992         statements: &mut Vec<Statement>,
993         mac: ast::MacroExpr,
994     ) -> Option<ExprId> {
995         let mac_call = mac.macro_call()?;
996         let syntax_ptr = AstPtr::new(&ast::Expr::from(mac));
997         let macro_ptr = AstPtr::new(&mac_call);
998         let expansion = self.collect_macro_call(
999             mac_call,
1000             macro_ptr,
1001             false,
1002             |this, expansion: Option<ast::MacroStmts>| match expansion {
1003                 Some(expansion) => {
1004                     expansion.statements().for_each(|stmt| this.collect_stmt(statements, stmt));
1005                     expansion.expr().and_then(|expr| match expr {
1006                         ast::Expr::MacroExpr(mac) => this.collect_macro_as_stmt(statements, mac),
1007                         expr => Some(this.collect_expr(expr)),
1008                     })
1009                 }
1010                 None => None,
1011             },
1012         );
1013         match expansion {
1014             Some(tail) => {
1015                 // Make the macro-call point to its expanded expression so we can query
1016                 // semantics on syntax pointers to the macro
1017                 let src = self.expander.to_source(syntax_ptr);
1018                 self.source_map.expr_map.insert(src, tail);
1019                 Some(tail)
1020             }
1021             None => None,
1022         }
1023     }
1024 
collect_stmt(&mut self, statements: &mut Vec<Statement>, s: ast::Stmt)1025     fn collect_stmt(&mut self, statements: &mut Vec<Statement>, s: ast::Stmt) {
1026         match s {
1027             ast::Stmt::LetStmt(stmt) => {
1028                 if self.check_cfg(&stmt).is_none() {
1029                     return;
1030                 }
1031                 let pat = self.collect_pat_top(stmt.pat());
1032                 let type_ref =
1033                     stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
1034                 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
1035                 let else_branch = stmt
1036                     .let_else()
1037                     .and_then(|let_else| let_else.block_expr())
1038                     .map(|block| self.collect_block(block));
1039                 statements.push(Statement::Let { pat, type_ref, initializer, else_branch });
1040             }
1041             ast::Stmt::ExprStmt(stmt) => {
1042                 let expr = stmt.expr();
1043                 match &expr {
1044                     Some(expr) if self.check_cfg(expr).is_none() => return,
1045                     _ => (),
1046                 }
1047                 let has_semi = stmt.semicolon_token().is_some();
1048                 // Note that macro could be expanded to multiple statements
1049                 if let Some(ast::Expr::MacroExpr(mac)) = expr {
1050                     if let Some(expr) = self.collect_macro_as_stmt(statements, mac) {
1051                         statements.push(Statement::Expr { expr, has_semi })
1052                     }
1053                 } else {
1054                     let expr = self.collect_expr_opt(expr);
1055                     statements.push(Statement::Expr { expr, has_semi });
1056                 }
1057             }
1058             ast::Stmt::Item(_item) => (),
1059         }
1060     }
1061 
collect_block(&mut self, block: ast::BlockExpr) -> ExprId1062     fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
1063         self.collect_block_(block, |id, statements, tail| Expr::Block {
1064             id,
1065             statements,
1066             tail,
1067             label: None,
1068         })
1069     }
1070 
collect_block_( &mut self, block: ast::BlockExpr, mk_block: impl FnOnce(Option<BlockId>, Box<[Statement]>, Option<ExprId>) -> Expr, ) -> ExprId1071     fn collect_block_(
1072         &mut self,
1073         block: ast::BlockExpr,
1074         mk_block: impl FnOnce(Option<BlockId>, Box<[Statement]>, Option<ExprId>) -> Expr,
1075     ) -> ExprId {
1076         let block_has_items = {
1077             let statement_has_item = block.statements().any(|stmt| match stmt {
1078                 ast::Stmt::Item(_) => true,
1079                 // Macro calls can be both items and expressions. The syntax library always treats
1080                 // them as expressions here, so we undo that.
1081                 ast::Stmt::ExprStmt(es) => matches!(es.expr(), Some(ast::Expr::MacroExpr(_))),
1082                 _ => false,
1083             });
1084             statement_has_item || matches!(block.tail_expr(), Some(ast::Expr::MacroExpr(_)))
1085         };
1086 
1087         let block_id = if block_has_items {
1088             let file_local_id = self.ast_id_map.ast_id(&block);
1089             let ast_id = AstId::new(self.expander.current_file_id, file_local_id);
1090             Some(self.db.intern_block(BlockLoc { ast_id, module: self.expander.module }))
1091         } else {
1092             None
1093         };
1094 
1095         let (module, def_map) =
1096             match block_id.map(|block_id| (self.db.block_def_map(block_id), block_id)) {
1097                 Some((def_map, block_id)) => {
1098                     self.body.block_scopes.push(block_id);
1099                     (def_map.module_id(DefMap::ROOT), def_map)
1100                 }
1101                 None => (self.expander.module, self.def_map.clone()),
1102             };
1103         let prev_def_map = mem::replace(&mut self.def_map, def_map);
1104         let prev_local_module = mem::replace(&mut self.expander.module, module);
1105 
1106         let mut statements = Vec::new();
1107         block.statements().for_each(|s| self.collect_stmt(&mut statements, s));
1108         let tail = block.tail_expr().and_then(|e| match e {
1109             ast::Expr::MacroExpr(mac) => self.collect_macro_as_stmt(&mut statements, mac),
1110             expr => self.maybe_collect_expr(expr),
1111         });
1112         let tail = tail.or_else(|| {
1113             let stmt = statements.pop()?;
1114             if let Statement::Expr { expr, has_semi: false } = stmt {
1115                 return Some(expr);
1116             }
1117             statements.push(stmt);
1118             None
1119         });
1120 
1121         let syntax_node_ptr = AstPtr::new(&block.into());
1122         let expr_id = self
1123             .alloc_expr(mk_block(block_id, statements.into_boxed_slice(), tail), syntax_node_ptr);
1124 
1125         self.def_map = prev_def_map;
1126         self.expander.module = prev_local_module;
1127         expr_id
1128     }
1129 
collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId1130     fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
1131         match expr {
1132             Some(block) => self.collect_block(block),
1133             None => self.missing_expr(),
1134         }
1135     }
1136 
collect_labelled_block_opt( &mut self, label: Option<LabelId>, expr: Option<ast::BlockExpr>, ) -> ExprId1137     fn collect_labelled_block_opt(
1138         &mut self,
1139         label: Option<LabelId>,
1140         expr: Option<ast::BlockExpr>,
1141     ) -> ExprId {
1142         match label {
1143             Some(label) => self.with_labeled_rib(label, |this| this.collect_block_opt(expr)),
1144             None => self.collect_block_opt(expr),
1145         }
1146     }
1147 
1148     // region: patterns
1149 
collect_pat_top(&mut self, pat: Option<ast::Pat>) -> PatId1150     fn collect_pat_top(&mut self, pat: Option<ast::Pat>) -> PatId {
1151         match pat {
1152             Some(pat) => self.collect_pat(pat, &mut BindingList::default()),
1153             None => self.missing_pat(),
1154         }
1155     }
1156 
collect_pat(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatId1157     fn collect_pat(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatId {
1158         let pattern = match &pat {
1159             ast::Pat::IdentPat(bp) => {
1160                 let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
1161 
1162                 let annotation =
1163                     BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
1164                 let subpat = bp.pat().map(|subpat| self.collect_pat(subpat, binding_list));
1165 
1166                 let is_simple_ident_pat =
1167                     annotation == BindingAnnotation::Unannotated && subpat.is_none();
1168                 let (binding, pattern) = if is_simple_ident_pat {
1169                     // This could also be a single-segment path pattern. To
1170                     // decide that, we need to try resolving the name.
1171                     let (resolved, _) = self.def_map.resolve_path(
1172                         self.db,
1173                         self.expander.module.local_id,
1174                         &name.clone().into(),
1175                         BuiltinShadowMode::Other,
1176                         None,
1177                     );
1178                     match resolved.take_values() {
1179                         Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())),
1180                         Some(ModuleDefId::EnumVariantId(_)) => {
1181                             // this is only really valid for unit variants, but
1182                             // shadowing other enum variants with a pattern is
1183                             // an error anyway
1184                             (None, Pat::Path(name.into()))
1185                         }
1186                         Some(ModuleDefId::AdtId(AdtId::StructId(s)))
1187                             if self.db.struct_data(s).variant_data.kind() != StructKind::Record =>
1188                         {
1189                             // Funnily enough, record structs *can* be shadowed
1190                             // by pattern bindings (but unit or tuple structs
1191                             // can't).
1192                             (None, Pat::Path(name.into()))
1193                         }
1194                         // shadowing statics is an error as well, so we just ignore that case here
1195                         _ => {
1196                             let id = binding_list.find(self, name, annotation);
1197                             (Some(id), Pat::Bind { id, subpat })
1198                         }
1199                     }
1200                 } else {
1201                     let id = binding_list.find(self, name, annotation);
1202                     (Some(id), Pat::Bind { id, subpat })
1203                 };
1204 
1205                 let ptr = AstPtr::new(&pat);
1206                 let pat = self.alloc_pat(pattern, Either::Left(ptr));
1207                 if let Some(binding_id) = binding {
1208                     self.add_definition_to_binding(binding_id, pat);
1209                 }
1210                 return pat;
1211             }
1212             ast::Pat::TupleStructPat(p) => {
1213                 let path =
1214                     p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
1215                 let (args, ellipsis) = self.collect_tuple_pat(
1216                     p.fields(),
1217                     comma_follows_token(p.l_paren_token()),
1218                     binding_list,
1219                 );
1220                 Pat::TupleStruct { path, args, ellipsis }
1221             }
1222             ast::Pat::RefPat(p) => {
1223                 let pat = self.collect_pat_opt(p.pat(), binding_list);
1224                 let mutability = Mutability::from_mutable(p.mut_token().is_some());
1225                 Pat::Ref { pat, mutability }
1226             }
1227             ast::Pat::PathPat(p) => {
1228                 let path =
1229                     p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
1230                 path.map(Pat::Path).unwrap_or(Pat::Missing)
1231             }
1232             ast::Pat::OrPat(p) => 'b: {
1233                 let prev_is_used = mem::take(&mut binding_list.is_used);
1234                 let prev_reject_new = mem::take(&mut binding_list.reject_new);
1235                 let mut pats = Vec::with_capacity(p.pats().count());
1236                 let mut it = p.pats();
1237                 let Some(first) = it.next() else {
1238                     break 'b Pat::Or(Box::new([]));
1239                 };
1240                 pats.push(self.collect_pat(first, binding_list));
1241                 binding_list.reject_new = true;
1242                 for rest in it {
1243                     for (_, x) in binding_list.is_used.iter_mut() {
1244                         *x = false;
1245                     }
1246                     pats.push(self.collect_pat(rest, binding_list));
1247                     for (&id, &x) in binding_list.is_used.iter() {
1248                         if !x {
1249                             self.body.bindings[id].problems =
1250                                 Some(BindingProblems::NotBoundAcrossAll);
1251                         }
1252                     }
1253                 }
1254                 binding_list.reject_new = prev_reject_new;
1255                 let current_is_used = mem::replace(&mut binding_list.is_used, prev_is_used);
1256                 for (id, _) in current_is_used.into_iter() {
1257                     binding_list.check_is_used(self, id);
1258                 }
1259                 Pat::Or(pats.into())
1260             }
1261             ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat(), binding_list),
1262             ast::Pat::TuplePat(p) => {
1263                 let (args, ellipsis) = self.collect_tuple_pat(
1264                     p.fields(),
1265                     comma_follows_token(p.l_paren_token()),
1266                     binding_list,
1267                 );
1268                 Pat::Tuple { args, ellipsis }
1269             }
1270             ast::Pat::WildcardPat(_) => Pat::Wild,
1271             ast::Pat::RecordPat(p) => {
1272                 let path =
1273                     p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new);
1274                 let args = p
1275                     .record_pat_field_list()
1276                     .expect("every struct should have a field list")
1277                     .fields()
1278                     .filter_map(|f| {
1279                         let ast_pat = f.pat()?;
1280                         let pat = self.collect_pat(ast_pat, binding_list);
1281                         let name = f.field_name()?.as_name();
1282                         Some(RecordFieldPat { name, pat })
1283                     })
1284                     .collect();
1285 
1286                 let ellipsis = p
1287                     .record_pat_field_list()
1288                     .expect("every struct should have a field list")
1289                     .rest_pat()
1290                     .is_some();
1291 
1292                 Pat::Record { path, args, ellipsis }
1293             }
1294             ast::Pat::SlicePat(p) => {
1295                 let SlicePatComponents { prefix, slice, suffix } = p.components();
1296 
1297                 // FIXME properly handle `RestPat`
1298                 Pat::Slice {
1299                     prefix: prefix.into_iter().map(|p| self.collect_pat(p, binding_list)).collect(),
1300                     slice: slice.map(|p| self.collect_pat(p, binding_list)),
1301                     suffix: suffix.into_iter().map(|p| self.collect_pat(p, binding_list)).collect(),
1302                 }
1303             }
1304             #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5676
1305             ast::Pat::LiteralPat(lit) => 'b: {
1306                 let Some((hir_lit, ast_lit)) = pat_literal_to_hir(lit) else { break 'b Pat::Missing };
1307                 let expr = Expr::Literal(hir_lit);
1308                 let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
1309                 let expr_id = self.alloc_expr(expr, expr_ptr);
1310                 Pat::Lit(expr_id)
1311             }
1312             ast::Pat::RestPat(_) => {
1313                 // `RestPat` requires special handling and should not be mapped
1314                 // to a Pat. Here we are using `Pat::Missing` as a fallback for
1315                 // when `RestPat` is mapped to `Pat`, which can easily happen
1316                 // when the source code being analyzed has a malformed pattern
1317                 // which includes `..` in a place where it isn't valid.
1318 
1319                 Pat::Missing
1320             }
1321             ast::Pat::BoxPat(boxpat) => {
1322                 let inner = self.collect_pat_opt(boxpat.pat(), binding_list);
1323                 Pat::Box { inner }
1324             }
1325             ast::Pat::ConstBlockPat(const_block_pat) => {
1326                 if let Some(block) = const_block_pat.block_expr() {
1327                     let expr_id = self.with_label_rib(RibKind::Constant, |this| {
1328                         let syntax_ptr = AstPtr::new(&block.clone().into());
1329                         this.collect_as_a_binding_owner_bad(
1330                             |this| this.collect_block(block),
1331                             syntax_ptr,
1332                         )
1333                     });
1334                     Pat::ConstBlock(expr_id)
1335                 } else {
1336                     Pat::Missing
1337                 }
1338             }
1339             ast::Pat::MacroPat(mac) => match mac.macro_call() {
1340                 Some(call) => {
1341                     let macro_ptr = AstPtr::new(&call);
1342                     let src = self.expander.to_source(Either::Left(AstPtr::new(&pat)));
1343                     let pat =
1344                         self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
1345                             this.collect_pat_opt(expanded_pat, binding_list)
1346                         });
1347                     self.source_map.pat_map.insert(src, pat);
1348                     return pat;
1349                 }
1350                 None => Pat::Missing,
1351             },
1352             // FIXME: implement in a way that also builds source map and calculates assoc resolutions in type inference.
1353             ast::Pat::RangePat(p) => {
1354                 let mut range_part_lower = |p: Option<ast::Pat>| {
1355                     p.and_then(|x| match &x {
1356                         ast::Pat::LiteralPat(x) => {
1357                             Some(Box::new(LiteralOrConst::Literal(pat_literal_to_hir(x)?.0)))
1358                         }
1359                         ast::Pat::IdentPat(p) => {
1360                             let name =
1361                                 p.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
1362                             Some(Box::new(LiteralOrConst::Const(name.into())))
1363                         }
1364                         ast::Pat::PathPat(p) => p
1365                             .path()
1366                             .and_then(|path| self.expander.parse_path(self.db, path))
1367                             .map(LiteralOrConst::Const)
1368                             .map(Box::new),
1369                         _ => None,
1370                     })
1371                 };
1372                 let start = range_part_lower(p.start());
1373                 let end = range_part_lower(p.end());
1374                 Pat::Range { start, end }
1375             }
1376         };
1377         let ptr = AstPtr::new(&pat);
1378         self.alloc_pat(pattern, Either::Left(ptr))
1379     }
1380 
collect_pat_opt(&mut self, pat: Option<ast::Pat>, binding_list: &mut BindingList) -> PatId1381     fn collect_pat_opt(&mut self, pat: Option<ast::Pat>, binding_list: &mut BindingList) -> PatId {
1382         match pat {
1383             Some(pat) => self.collect_pat(pat, binding_list),
1384             None => self.missing_pat(),
1385         }
1386     }
1387 
collect_tuple_pat( &mut self, args: AstChildren<ast::Pat>, has_leading_comma: bool, binding_list: &mut BindingList, ) -> (Box<[PatId]>, Option<usize>)1388     fn collect_tuple_pat(
1389         &mut self,
1390         args: AstChildren<ast::Pat>,
1391         has_leading_comma: bool,
1392         binding_list: &mut BindingList,
1393     ) -> (Box<[PatId]>, Option<usize>) {
1394         // Find the location of the `..`, if there is one. Note that we do not
1395         // consider the possibility of there being multiple `..` here.
1396         let ellipsis = args.clone().position(|p| matches!(p, ast::Pat::RestPat(_)));
1397         // We want to skip the `..` pattern here, since we account for it above.
1398         let mut args: Vec<_> = args
1399             .filter(|p| !matches!(p, ast::Pat::RestPat(_)))
1400             .map(|p| self.collect_pat(p, binding_list))
1401             .collect();
1402         // if there is a leading comma, the user is most likely to type out a leading pattern
1403         // so we insert a missing pattern at the beginning for IDE features
1404         if has_leading_comma {
1405             args.insert(0, self.missing_pat());
1406         }
1407 
1408         (args.into_boxed_slice(), ellipsis)
1409     }
1410 
1411     // endregion: patterns
1412 
1413     /// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when
1414     /// not.
check_cfg(&mut self, owner: &dyn ast::HasAttrs) -> Option<()>1415     fn check_cfg(&mut self, owner: &dyn ast::HasAttrs) -> Option<()> {
1416         match self.expander.parse_attrs(self.db, owner).cfg() {
1417             Some(cfg) => {
1418                 if self.expander.cfg_options().check(&cfg) != Some(false) {
1419                     return Some(());
1420                 }
1421 
1422                 self.source_map.diagnostics.push(BodyDiagnostic::InactiveCode {
1423                     node: InFile::new(
1424                         self.expander.current_file_id,
1425                         SyntaxNodePtr::new(owner.syntax()),
1426                     ),
1427                     cfg,
1428                     opts: self.expander.cfg_options().clone(),
1429                 });
1430 
1431                 None
1432             }
1433             None => Some(()),
1434         }
1435     }
1436 
add_definition_to_binding(&mut self, binding_id: BindingId, pat_id: PatId)1437     fn add_definition_to_binding(&mut self, binding_id: BindingId, pat_id: PatId) {
1438         self.body.bindings[binding_id].definitions.push(pat_id);
1439     }
1440 
1441     // region: labels
1442 
collect_label(&mut self, ast_label: ast::Label) -> LabelId1443     fn collect_label(&mut self, ast_label: ast::Label) -> LabelId {
1444         let label = Label {
1445             name: ast_label.lifetime().as_ref().map_or_else(Name::missing, Name::new_lifetime),
1446         };
1447         self.alloc_label(label, AstPtr::new(&ast_label))
1448     }
1449 
resolve_label( &self, lifetime: Option<ast::Lifetime>, ) -> Result<Option<LabelId>, BodyDiagnostic>1450     fn resolve_label(
1451         &self,
1452         lifetime: Option<ast::Lifetime>,
1453     ) -> Result<Option<LabelId>, BodyDiagnostic> {
1454         let Some(lifetime) = lifetime else {
1455             return Ok(None)
1456         };
1457         let name = Name::new_lifetime(&lifetime);
1458 
1459         for (rib_idx, rib) in self.label_ribs.iter().enumerate().rev() {
1460             if let Some((label_name, id)) = &rib.label {
1461                 if *label_name == name {
1462                     return if self.is_label_valid_from_rib(rib_idx) {
1463                         Ok(Some(*id))
1464                     } else {
1465                         Err(BodyDiagnostic::UnreachableLabel {
1466                             name,
1467                             node: InFile::new(
1468                                 self.expander.current_file_id,
1469                                 AstPtr::new(&lifetime),
1470                             ),
1471                         })
1472                     };
1473                 }
1474             }
1475         }
1476 
1477         Err(BodyDiagnostic::UndeclaredLabel {
1478             name,
1479             node: InFile::new(self.expander.current_file_id, AstPtr::new(&lifetime)),
1480         })
1481     }
1482 
is_label_valid_from_rib(&self, rib_index: usize) -> bool1483     fn is_label_valid_from_rib(&self, rib_index: usize) -> bool {
1484         !self.label_ribs[rib_index + 1..].iter().any(|rib| rib.kind.is_label_barrier())
1485     }
1486 
with_label_rib<T>(&mut self, kind: RibKind, f: impl FnOnce(&mut Self) -> T) -> T1487     fn with_label_rib<T>(&mut self, kind: RibKind, f: impl FnOnce(&mut Self) -> T) -> T {
1488         self.label_ribs.push(LabelRib::new(kind));
1489         let res = f(self);
1490         self.label_ribs.pop();
1491         res
1492     }
1493 
with_labeled_rib<T>(&mut self, label: LabelId, f: impl FnOnce(&mut Self) -> T) -> T1494     fn with_labeled_rib<T>(&mut self, label: LabelId, f: impl FnOnce(&mut Self) -> T) -> T {
1495         self.label_ribs.push(LabelRib::new_normal((self.body[label].name.clone(), label)));
1496         let res = f(self);
1497         self.label_ribs.pop();
1498         res
1499     }
1500 
with_opt_labeled_rib<T>( &mut self, label: Option<LabelId>, f: impl FnOnce(&mut Self) -> T, ) -> T1501     fn with_opt_labeled_rib<T>(
1502         &mut self,
1503         label: Option<LabelId>,
1504         f: impl FnOnce(&mut Self) -> T,
1505     ) -> T {
1506         match label {
1507             None => f(self),
1508             Some(label) => self.with_labeled_rib(label, f),
1509         }
1510     }
1511     // endregion: labels
1512 }
1513 
pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)>1514 fn pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)> {
1515     let ast_lit = lit.literal()?;
1516     let mut hir_lit: Literal = ast_lit.kind().into();
1517     if lit.minus_token().is_some() {
1518         let Some(h) = hir_lit.negate() else {
1519             return None;
1520         };
1521         hir_lit = h;
1522     }
1523     Some((hir_lit, ast_lit))
1524 }
1525 
1526 impl ExprCollector<'_> {
alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId1527     fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
1528         let src = self.expander.to_source(ptr);
1529         let id = self.body.exprs.alloc(expr);
1530         self.source_map.expr_map_back.insert(id, src.clone());
1531         self.source_map.expr_map.insert(src, id);
1532         id
1533     }
1534     // FIXME: desugared exprs don't have ptr, that's wrong and should be fixed somehow.
alloc_expr_desugared(&mut self, expr: Expr) -> ExprId1535     fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
1536         self.body.exprs.alloc(expr)
1537     }
missing_expr(&mut self) -> ExprId1538     fn missing_expr(&mut self) -> ExprId {
1539         self.alloc_expr_desugared(Expr::Missing)
1540     }
1541 
alloc_binding(&mut self, name: Name, mode: BindingAnnotation) -> BindingId1542     fn alloc_binding(&mut self, name: Name, mode: BindingAnnotation) -> BindingId {
1543         let binding = self.body.bindings.alloc(Binding {
1544             name,
1545             mode,
1546             definitions: SmallVec::new(),
1547             problems: None,
1548         });
1549         if let Some(owner) = self.current_binding_owner {
1550             self.body.binding_owners.insert(binding, owner);
1551         }
1552         binding
1553     }
1554 
alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId1555     fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
1556         let src = self.expander.to_source(ptr);
1557         let id = self.body.pats.alloc(pat);
1558         self.source_map.pat_map_back.insert(id, src.clone());
1559         self.source_map.pat_map.insert(src, id);
1560         id
1561     }
1562     // FIXME: desugared pats don't have ptr, that's wrong and should be fixed somehow.
alloc_pat_desugared(&mut self, pat: Pat) -> PatId1563     fn alloc_pat_desugared(&mut self, pat: Pat) -> PatId {
1564         self.body.pats.alloc(pat)
1565     }
missing_pat(&mut self) -> PatId1566     fn missing_pat(&mut self) -> PatId {
1567         self.body.pats.alloc(Pat::Missing)
1568     }
1569 
alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId1570     fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId {
1571         let src = self.expander.to_source(ptr);
1572         let id = self.body.labels.alloc(label);
1573         self.source_map.label_map_back.insert(id, src.clone());
1574         self.source_map.label_map.insert(src, id);
1575         id
1576     }
1577     // FIXME: desugared labels don't have ptr, that's wrong and should be fixed somehow.
alloc_label_desugared(&mut self, label: Label) -> LabelId1578     fn alloc_label_desugared(&mut self, label: Label) -> LabelId {
1579         self.body.labels.alloc(label)
1580     }
1581 }
1582 
comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool1583 fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool {
1584     (|| syntax::algo::skip_trivia_token(t?.next_token()?, syntax::Direction::Next))()
1585         .map_or(false, |it| it.kind() == syntax::T![,])
1586 }
1587