hir_def/
expr_store.rs

1//! Defines `ExpressionStore`: a lowered representation of functions, statics and
2//! consts.
3pub mod body;
4mod expander;
5pub mod lower;
6pub mod path;
7pub mod pretty;
8pub mod scope;
9#[cfg(test)]
10mod tests;
11
12use std::{
13    ops::{Deref, Index},
14    sync::LazyLock,
15};
16
17use cfg::{CfgExpr, CfgOptions};
18use either::Either;
19use hir_expand::{InFile, MacroCallId, mod_path::ModPath, name::Name};
20use la_arena::{Arena, ArenaMap};
21use rustc_hash::FxHashMap;
22use smallvec::SmallVec;
23use span::{Edition, SyntaxContext};
24use syntax::{AstPtr, SyntaxNodePtr, ast};
25use thin_vec::ThinVec;
26use triomphe::Arc;
27use tt::TextRange;
28
29use crate::{
30    BlockId, SyntheticSyntax,
31    db::DefDatabase,
32    expr_store::path::Path,
33    hir::{
34        Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label, LabelId, Pat,
35        PatId, RecordFieldPat, Statement,
36    },
37    nameres::{DefMap, block_def_map},
38    type_ref::{LifetimeRef, LifetimeRefId, PathId, TypeRef, TypeRefId},
39};
40
41pub use self::body::{Body, BodySourceMap};
42pub use self::lower::{
43    hir_assoc_type_binding_to_ast, hir_generic_arg_to_ast, hir_segment_to_ast_segment,
44};
45
46/// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons.
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
48pub struct HygieneId(span::SyntaxContext);
49
50impl HygieneId {
51    // The edition doesn't matter here, we only use this for comparisons and to lookup the macro.
52    pub const ROOT: Self = Self(span::SyntaxContext::root(Edition::Edition2015));
53
54    pub fn new(mut ctx: span::SyntaxContext) -> Self {
55        // See `Name` for why we're doing that.
56        ctx.remove_root_edition();
57        Self(ctx)
58    }
59
60    // FIXME: Inline this
61    pub(crate) fn lookup(self) -> SyntaxContext {
62        self.0
63    }
64
65    pub(crate) fn is_root(self) -> bool {
66        self.0.is_root()
67    }
68}
69
70pub type ExprPtr = AstPtr<ast::Expr>;
71pub type ExprSource = InFile<ExprPtr>;
72
73pub type PatPtr = AstPtr<ast::Pat>;
74pub type PatSource = InFile<PatPtr>;
75
76pub type LabelPtr = AstPtr<ast::Label>;
77pub type LabelSource = InFile<LabelPtr>;
78
79pub type FieldPtr = AstPtr<ast::RecordExprField>;
80pub type FieldSource = InFile<FieldPtr>;
81
82pub type PatFieldPtr = AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>;
83pub type PatFieldSource = InFile<PatFieldPtr>;
84
85pub type ExprOrPatPtr = AstPtr<Either<ast::Expr, ast::Pat>>;
86pub type ExprOrPatSource = InFile<ExprOrPatPtr>;
87
88pub type SelfParamPtr = AstPtr<ast::SelfParam>;
89pub type MacroCallPtr = AstPtr<ast::MacroCall>;
90
91pub type TypePtr = AstPtr<ast::Type>;
92pub type TypeSource = InFile<TypePtr>;
93
94pub type LifetimePtr = AstPtr<ast::Lifetime>;
95pub type LifetimeSource = InFile<LifetimePtr>;
96
97// We split the store into types-only and expressions, because most stores (e.g. generics)
98// don't store any expressions and this saves memory. Same thing for the source map.
99#[derive(Debug, PartialEq, Eq)]
100struct ExpressionOnlyStore {
101    exprs: Arena<Expr>,
102    pats: Arena<Pat>,
103    bindings: Arena<Binding>,
104    labels: Arena<Label>,
105    /// Id of the closure/coroutine that owns the corresponding binding. If a binding is owned by the
106    /// top level expression, it will not be listed in here.
107    binding_owners: FxHashMap<BindingId, ExprId>,
108    /// Block expressions in this store that may contain inner items.
109    block_scopes: Box<[BlockId]>,
110
111    /// A map from an variable usages to their hygiene ID.
112    ///
113    /// Expressions (and destructuing patterns) that can be recorded here are single segment path, although not all single segments path refer
114    /// to variables and have hygiene (some refer to items, we don't know at this stage).
115    ident_hygiene: FxHashMap<ExprOrPatId, HygieneId>,
116}
117
118#[derive(Debug, PartialEq, Eq)]
119pub struct ExpressionStore {
120    expr_only: Option<Box<ExpressionOnlyStore>>,
121    pub types: Arena<TypeRef>,
122    pub lifetimes: Arena<LifetimeRef>,
123}
124
125#[derive(Debug, Eq, Default)]
126struct ExpressionOnlySourceMap {
127    // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map
128    // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected).
129    expr_map: FxHashMap<ExprSource, ExprOrPatId>,
130    expr_map_back: ArenaMap<ExprId, ExprOrPatSource>,
131
132    pat_map: FxHashMap<PatSource, ExprOrPatId>,
133    pat_map_back: ArenaMap<PatId, ExprOrPatSource>,
134
135    label_map: FxHashMap<LabelSource, LabelId>,
136    label_map_back: ArenaMap<LabelId, LabelSource>,
137
138    binding_definitions:
139        ArenaMap<BindingId, SmallVec<[PatId; 2 * size_of::<usize>() / size_of::<PatId>()]>>,
140
141    /// We don't create explicit nodes for record fields (`S { record_field: 92 }`).
142    /// Instead, we use id of expression (`92`) to identify the field.
143    field_map_back: FxHashMap<ExprId, FieldSource>,
144    pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
145
146    template_map: Option<Box<FormatTemplate>>,
147
148    expansions: FxHashMap<InFile<MacroCallPtr>, MacroCallId>,
149
150    /// Diagnostics accumulated during lowering. These contain `AstPtr`s and so are stored in
151    /// the source map (since they're just as volatile).
152    //
153    // We store diagnostics on the `ExpressionOnlySourceMap` because diagnostics are rare (except
154    // maybe for cfgs, and they are also not common in type places).
155    diagnostics: ThinVec<ExpressionStoreDiagnostics>,
156}
157
158impl PartialEq for ExpressionOnlySourceMap {
159    fn eq(&self, other: &Self) -> bool {
160        // we only need to compare one of the two mappings
161        // as the other is a reverse mapping and thus will compare
162        // the same as normal mapping
163        let Self {
164            expr_map: _,
165            expr_map_back,
166            pat_map: _,
167            pat_map_back,
168            label_map: _,
169            label_map_back,
170            // If this changed, our pattern data must have changed
171            binding_definitions: _,
172            // If this changed, our expression data must have changed
173            field_map_back: _,
174            // If this changed, our pattern data must have changed
175            pat_field_map_back: _,
176            template_map,
177            expansions,
178            diagnostics,
179        } = self;
180        *expr_map_back == other.expr_map_back
181            && *pat_map_back == other.pat_map_back
182            && *label_map_back == other.label_map_back
183            && *template_map == other.template_map
184            && *expansions == other.expansions
185            && *diagnostics == other.diagnostics
186    }
187}
188
189#[derive(Debug, Eq, Default)]
190pub struct ExpressionStoreSourceMap {
191    expr_only: Option<Box<ExpressionOnlySourceMap>>,
192
193    types_map_back: ArenaMap<TypeRefId, TypeSource>,
194    types_map: FxHashMap<TypeSource, TypeRefId>,
195
196    lifetime_map_back: ArenaMap<LifetimeRefId, LifetimeSource>,
197    #[expect(
198        unused,
199        reason = "this is here for completeness, and maybe we'll need it in the future"
200    )]
201    lifetime_map: FxHashMap<LifetimeSource, LifetimeRefId>,
202}
203
204impl PartialEq for ExpressionStoreSourceMap {
205    fn eq(&self, other: &Self) -> bool {
206        // we only need to compare one of the two mappings
207        // as the other is a reverse mapping and thus will compare
208        // the same as normal mapping
209        let Self { expr_only, types_map_back, types_map: _, lifetime_map_back, lifetime_map: _ } =
210            self;
211        *expr_only == other.expr_only
212            && *types_map_back == other.types_map_back
213            && *lifetime_map_back == other.lifetime_map_back
214    }
215}
216
217/// The body of an item (function, const etc.).
218#[derive(Debug, Eq, PartialEq, Default)]
219pub struct ExpressionStoreBuilder {
220    pub exprs: Arena<Expr>,
221    pub pats: Arena<Pat>,
222    pub bindings: Arena<Binding>,
223    pub labels: Arena<Label>,
224    pub lifetimes: Arena<LifetimeRef>,
225    pub binding_owners: FxHashMap<BindingId, ExprId>,
226    pub types: Arena<TypeRef>,
227    block_scopes: Vec<BlockId>,
228    ident_hygiene: FxHashMap<ExprOrPatId, HygieneId>,
229
230    // AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map
231    // to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected).
232    expr_map: FxHashMap<ExprSource, ExprOrPatId>,
233    expr_map_back: ArenaMap<ExprId, ExprOrPatSource>,
234
235    pat_map: FxHashMap<PatSource, ExprOrPatId>,
236    pat_map_back: ArenaMap<PatId, ExprOrPatSource>,
237
238    label_map: FxHashMap<LabelSource, LabelId>,
239    label_map_back: ArenaMap<LabelId, LabelSource>,
240
241    types_map_back: ArenaMap<TypeRefId, TypeSource>,
242    types_map: FxHashMap<TypeSource, TypeRefId>,
243
244    lifetime_map_back: ArenaMap<LifetimeRefId, LifetimeSource>,
245    lifetime_map: FxHashMap<LifetimeSource, LifetimeRefId>,
246
247    binding_definitions:
248        ArenaMap<BindingId, SmallVec<[PatId; 2 * size_of::<usize>() / size_of::<PatId>()]>>,
249
250    /// We don't create explicit nodes for record fields (`S { record_field: 92 }`).
251    /// Instead, we use id of expression (`92`) to identify the field.
252    field_map_back: FxHashMap<ExprId, FieldSource>,
253    pat_field_map_back: FxHashMap<PatId, PatFieldSource>,
254
255    template_map: Option<Box<FormatTemplate>>,
256
257    expansions: FxHashMap<InFile<MacroCallPtr>, MacroCallId>,
258
259    /// Diagnostics accumulated during lowering. These contain `AstPtr`s and so are stored in
260    /// the source map (since they're just as volatile).
261    //
262    // We store diagnostics on the `ExpressionOnlySourceMap` because diagnostics are rare (except
263    // maybe for cfgs, and they are also not common in type places).
264    pub(crate) diagnostics: Vec<ExpressionStoreDiagnostics>,
265}
266
267#[derive(Default, Debug, Eq, PartialEq)]
268struct FormatTemplate {
269    /// A map from `format_args!()` expressions to their captures.
270    format_args_to_captures: FxHashMap<ExprId, (HygieneId, Vec<(syntax::TextRange, Name)>)>,
271    /// A map from `asm!()` expressions to their captures.
272    asm_to_captures: FxHashMap<ExprId, Vec<Vec<(syntax::TextRange, usize)>>>,
273    /// A map from desugared expressions of implicit captures to their source.
274    ///
275    /// The value stored for each capture is its template literal and offset inside it. The template literal
276    /// is from the `format_args[_nl]!()` macro and so needs to be mapped up once to go to the user-written
277    /// template.
278    implicit_capture_to_source: FxHashMap<ExprId, InFile<(ExprPtr, TextRange)>>,
279}
280
281#[derive(Debug, Eq, PartialEq)]
282pub enum ExpressionStoreDiagnostics {
283    InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions },
284    UnresolvedMacroCall { node: InFile<MacroCallPtr>, path: ModPath },
285    UnreachableLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name },
286    AwaitOutsideOfAsync { node: InFile<AstPtr<ast::AwaitExpr>>, location: String },
287    UndeclaredLabel { node: InFile<AstPtr<ast::Lifetime>>, name: Name },
288}
289
290impl ExpressionStoreBuilder {
291    pub fn finish(self) -> (ExpressionStore, ExpressionStoreSourceMap) {
292        let Self {
293            block_scopes,
294            mut exprs,
295            mut labels,
296            mut pats,
297            mut bindings,
298            mut binding_owners,
299            mut ident_hygiene,
300            mut types,
301            mut lifetimes,
302
303            mut expr_map,
304            mut expr_map_back,
305            mut pat_map,
306            mut pat_map_back,
307            mut label_map,
308            mut label_map_back,
309            mut types_map_back,
310            mut types_map,
311            mut lifetime_map_back,
312            mut lifetime_map,
313            mut binding_definitions,
314            mut field_map_back,
315            mut pat_field_map_back,
316            mut template_map,
317            mut expansions,
318            diagnostics,
319        } = self;
320        exprs.shrink_to_fit();
321        labels.shrink_to_fit();
322        pats.shrink_to_fit();
323        bindings.shrink_to_fit();
324        binding_owners.shrink_to_fit();
325        ident_hygiene.shrink_to_fit();
326        types.shrink_to_fit();
327        lifetimes.shrink_to_fit();
328
329        expr_map.shrink_to_fit();
330        expr_map_back.shrink_to_fit();
331        pat_map.shrink_to_fit();
332        pat_map_back.shrink_to_fit();
333        label_map.shrink_to_fit();
334        label_map_back.shrink_to_fit();
335        types_map_back.shrink_to_fit();
336        types_map.shrink_to_fit();
337        lifetime_map_back.shrink_to_fit();
338        lifetime_map.shrink_to_fit();
339        binding_definitions.shrink_to_fit();
340        field_map_back.shrink_to_fit();
341        pat_field_map_back.shrink_to_fit();
342        if let Some(template_map) = &mut template_map {
343            let FormatTemplate {
344                format_args_to_captures,
345                asm_to_captures,
346                implicit_capture_to_source,
347            } = &mut **template_map;
348            format_args_to_captures.shrink_to_fit();
349            asm_to_captures.shrink_to_fit();
350            implicit_capture_to_source.shrink_to_fit();
351        }
352        expansions.shrink_to_fit();
353
354        let has_exprs =
355            !exprs.is_empty() || !labels.is_empty() || !pats.is_empty() || !bindings.is_empty();
356
357        let store = {
358            let expr_only = if has_exprs {
359                Some(Box::new(ExpressionOnlyStore {
360                    exprs,
361                    pats,
362                    bindings,
363                    labels,
364                    binding_owners,
365                    block_scopes: block_scopes.into_boxed_slice(),
366                    ident_hygiene,
367                }))
368            } else {
369                None
370            };
371            ExpressionStore { expr_only, types, lifetimes }
372        };
373
374        let source_map = {
375            let expr_only = if has_exprs || !expansions.is_empty() || !diagnostics.is_empty() {
376                Some(Box::new(ExpressionOnlySourceMap {
377                    expr_map,
378                    expr_map_back,
379                    pat_map,
380                    pat_map_back,
381                    label_map,
382                    label_map_back,
383                    binding_definitions,
384                    field_map_back,
385                    pat_field_map_back,
386                    template_map,
387                    expansions,
388                    diagnostics: ThinVec::from_iter(diagnostics),
389                }))
390            } else {
391                None
392            };
393            ExpressionStoreSourceMap {
394                expr_only,
395                types_map_back,
396                types_map,
397                lifetime_map_back,
398                lifetime_map,
399            }
400        };
401
402        (store, source_map)
403    }
404}
405
406impl ExpressionStore {
407    pub fn empty_singleton() -> (Arc<ExpressionStore>, Arc<ExpressionStoreSourceMap>) {
408        static EMPTY: LazyLock<(Arc<ExpressionStore>, Arc<ExpressionStoreSourceMap>)> =
409            LazyLock::new(|| {
410                let (store, source_map) = ExpressionStoreBuilder::default().finish();
411                (Arc::new(store), Arc::new(source_map))
412            });
413        EMPTY.clone()
414    }
415
416    /// Returns an iterator over all block expressions in this store that define inner items.
417    pub fn blocks<'a>(
418        &'a self,
419        db: &'a dyn DefDatabase,
420    ) -> impl Iterator<Item = (BlockId, &'a DefMap)> + 'a {
421        self.expr_only
422            .as_ref()
423            .map(|it| &*it.block_scopes)
424            .unwrap_or_default()
425            .iter()
426            .map(move |&block| (block, block_def_map(db, block)))
427    }
428
429    pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
430        self.walk_pats(pat_id, &mut |pat| {
431            if let Pat::Bind { id, .. } = &self[pat] {
432                f(*id);
433            }
434        });
435    }
436
437    pub fn walk_pats_shallow(&self, pat_id: PatId, mut f: impl FnMut(PatId)) {
438        let pat = &self[pat_id];
439        match pat {
440            Pat::Range { .. }
441            | Pat::Lit(..)
442            | Pat::Path(..)
443            | Pat::ConstBlock(..)
444            | Pat::Wild
445            | Pat::Missing
446            | Pat::Expr(_) => {}
447            &Pat::Bind { subpat, .. } => {
448                if let Some(subpat) = subpat {
449                    f(subpat);
450                }
451            }
452            Pat::Or(args) | Pat::Tuple { args, .. } | Pat::TupleStruct { args, .. } => {
453                args.iter().copied().for_each(f);
454            }
455            Pat::Ref { pat, .. } => f(*pat),
456            Pat::Slice { prefix, slice, suffix } => {
457                let total_iter = prefix.iter().chain(slice.iter()).chain(suffix.iter());
458                total_iter.copied().for_each(f);
459            }
460            Pat::Record { args, .. } => {
461                args.iter().for_each(|RecordFieldPat { pat, .. }| f(*pat));
462            }
463            Pat::Box { inner } => f(*inner),
464        }
465    }
466
467    pub fn walk_pats(&self, pat_id: PatId, f: &mut impl FnMut(PatId)) {
468        f(pat_id);
469        self.walk_pats_shallow(pat_id, |p| self.walk_pats(p, f));
470    }
471
472    pub fn is_binding_upvar(&self, binding: BindingId, relative_to: ExprId) -> bool {
473        let Some(expr_only) = &self.expr_only else { return false };
474        match expr_only.binding_owners.get(&binding) {
475            Some(it) => {
476                // We assign expression ids in a way that outer closures will receive
477                // a lower id
478                it.into_raw() < relative_to.into_raw()
479            }
480            None => true,
481        }
482    }
483
484    #[inline]
485    pub fn binding_owner(&self, id: BindingId) -> Option<ExprId> {
486        self.expr_only.as_ref()?.binding_owners.get(&id).copied()
487    }
488
489    /// Walks the immediate children expressions and calls `f` for each child expression.
490    ///
491    /// Note that this does not walk const blocks.
492    pub fn walk_child_exprs(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) {
493        let expr = &self[expr_id];
494        match expr {
495            Expr::Continue { .. }
496            | Expr::Const(_)
497            | Expr::Missing
498            | Expr::Path(_)
499            | Expr::OffsetOf(_)
500            | Expr::Literal(_)
501            | Expr::Underscore => {}
502            Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
503                AsmOperand::In { expr, .. }
504                | AsmOperand::Out { expr: Some(expr), .. }
505                | AsmOperand::InOut { expr, .. }
506                | AsmOperand::Const(expr)
507                | AsmOperand::Label(expr) => f(*expr),
508                AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
509                    f(*in_expr);
510                    if let Some(out_expr) = out_expr {
511                        f(*out_expr);
512                    }
513                }
514                AsmOperand::Out { expr: None, .. } | AsmOperand::Sym(_) => (),
515            }),
516            Expr::If { condition, then_branch, else_branch } => {
517                f(*condition);
518                f(*then_branch);
519                if let &Some(else_branch) = else_branch {
520                    f(else_branch);
521                }
522            }
523            Expr::Let { expr, pat } => {
524                self.walk_exprs_in_pat(*pat, &mut f);
525                f(*expr);
526            }
527            Expr::Block { statements, tail, .. }
528            | Expr::Unsafe { statements, tail, .. }
529            | Expr::Async { statements, tail, .. } => {
530                for stmt in statements.iter() {
531                    match stmt {
532                        Statement::Let { initializer, else_branch, pat, .. } => {
533                            if let &Some(expr) = initializer {
534                                f(expr);
535                            }
536                            if let &Some(expr) = else_branch {
537                                f(expr);
538                            }
539                            self.walk_exprs_in_pat(*pat, &mut f);
540                        }
541                        Statement::Expr { expr: expression, .. } => f(*expression),
542                        Statement::Item(_) => (),
543                    }
544                }
545                if let &Some(expr) = tail {
546                    f(expr);
547                }
548            }
549            Expr::Loop { body, .. } => f(*body),
550            Expr::Call { callee, args, .. } => {
551                f(*callee);
552                args.iter().copied().for_each(f);
553            }
554            Expr::MethodCall { receiver, args, .. } => {
555                f(*receiver);
556                args.iter().copied().for_each(f);
557            }
558            Expr::Match { expr, arms } => {
559                f(*expr);
560                arms.iter().for_each(|arm| {
561                    f(arm.expr);
562                    self.walk_exprs_in_pat(arm.pat, &mut f);
563                });
564            }
565            Expr::Break { expr, .. }
566            | Expr::Return { expr }
567            | Expr::Yield { expr }
568            | Expr::Yeet { expr } => {
569                if let &Some(expr) = expr {
570                    f(expr);
571                }
572            }
573            Expr::Become { expr } => f(*expr),
574            Expr::RecordLit { fields, spread, .. } => {
575                for field in fields.iter() {
576                    f(field.expr);
577                }
578                if let &Some(expr) = spread {
579                    f(expr);
580                }
581            }
582            Expr::Closure { body, .. } => {
583                f(*body);
584            }
585            Expr::BinaryOp { lhs, rhs, .. } => {
586                f(*lhs);
587                f(*rhs);
588            }
589            Expr::Range { lhs, rhs, .. } => {
590                if let &Some(lhs) = rhs {
591                    f(lhs);
592                }
593                if let &Some(rhs) = lhs {
594                    f(rhs);
595                }
596            }
597            Expr::Index { base, index, .. } => {
598                f(*base);
599                f(*index);
600            }
601            Expr::Field { expr, .. }
602            | Expr::Await { expr }
603            | Expr::Cast { expr, .. }
604            | Expr::Ref { expr, .. }
605            | Expr::UnaryOp { expr, .. }
606            | Expr::Box { expr } => {
607                f(*expr);
608            }
609            Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
610            Expr::Array(a) => match a {
611                Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
612                Array::Repeat { initializer, repeat } => {
613                    f(*initializer);
614                    f(*repeat)
615                }
616            },
617            &Expr::Assignment { target, value } => {
618                self.walk_exprs_in_pat(target, &mut f);
619                f(value);
620            }
621        }
622    }
623
624    /// Walks the immediate children expressions and calls `f` for each child expression but does
625    /// not walk expressions within patterns.
626    ///
627    /// Note that this does not walk const blocks.
628    pub fn walk_child_exprs_without_pats(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) {
629        let expr = &self[expr_id];
630        match expr {
631            Expr::Continue { .. }
632            | Expr::Const(_)
633            | Expr::Missing
634            | Expr::Path(_)
635            | Expr::OffsetOf(_)
636            | Expr::Literal(_)
637            | Expr::Underscore => {}
638            Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
639                AsmOperand::In { expr, .. }
640                | AsmOperand::Out { expr: Some(expr), .. }
641                | AsmOperand::InOut { expr, .. }
642                | AsmOperand::Const(expr)
643                | AsmOperand::Label(expr) => f(*expr),
644                AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
645                    f(*in_expr);
646                    if let Some(out_expr) = out_expr {
647                        f(*out_expr);
648                    }
649                }
650                AsmOperand::Out { expr: None, .. } | AsmOperand::Sym(_) => (),
651            }),
652            Expr::If { condition, then_branch, else_branch } => {
653                f(*condition);
654                f(*then_branch);
655                if let &Some(else_branch) = else_branch {
656                    f(else_branch);
657                }
658            }
659            Expr::Let { expr, .. } => {
660                f(*expr);
661            }
662            Expr::Block { statements, tail, .. }
663            | Expr::Unsafe { statements, tail, .. }
664            | Expr::Async { statements, tail, .. } => {
665                for stmt in statements.iter() {
666                    match stmt {
667                        Statement::Let { initializer, else_branch, .. } => {
668                            if let &Some(expr) = initializer {
669                                f(expr);
670                            }
671                            if let &Some(expr) = else_branch {
672                                f(expr);
673                            }
674                        }
675                        Statement::Expr { expr: expression, .. } => f(*expression),
676                        Statement::Item(_) => (),
677                    }
678                }
679                if let &Some(expr) = tail {
680                    f(expr);
681                }
682            }
683            Expr::Loop { body, .. } => f(*body),
684            Expr::Call { callee, args, .. } => {
685                f(*callee);
686                args.iter().copied().for_each(f);
687            }
688            Expr::MethodCall { receiver, args, .. } => {
689                f(*receiver);
690                args.iter().copied().for_each(f);
691            }
692            Expr::Match { expr, arms } => {
693                f(*expr);
694                arms.iter().map(|arm| arm.expr).for_each(f);
695            }
696            Expr::Break { expr, .. }
697            | Expr::Return { expr }
698            | Expr::Yield { expr }
699            | Expr::Yeet { expr } => {
700                if let &Some(expr) = expr {
701                    f(expr);
702                }
703            }
704            Expr::Become { expr } => f(*expr),
705            Expr::RecordLit { fields, spread, .. } => {
706                for field in fields.iter() {
707                    f(field.expr);
708                }
709                if let &Some(expr) = spread {
710                    f(expr);
711                }
712            }
713            Expr::Closure { body, .. } => {
714                f(*body);
715            }
716            Expr::BinaryOp { lhs, rhs, .. } => {
717                f(*lhs);
718                f(*rhs);
719            }
720            Expr::Range { lhs, rhs, .. } => {
721                if let &Some(lhs) = rhs {
722                    f(lhs);
723                }
724                if let &Some(rhs) = lhs {
725                    f(rhs);
726                }
727            }
728            Expr::Index { base, index, .. } => {
729                f(*base);
730                f(*index);
731            }
732            Expr::Field { expr, .. }
733            | Expr::Await { expr }
734            | Expr::Cast { expr, .. }
735            | Expr::Ref { expr, .. }
736            | Expr::UnaryOp { expr, .. }
737            | Expr::Box { expr } => {
738                f(*expr);
739            }
740            Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
741            Expr::Array(a) => match a {
742                Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
743                Array::Repeat { initializer, repeat } => {
744                    f(*initializer);
745                    f(*repeat)
746                }
747            },
748            &Expr::Assignment { target: _, value } => f(value),
749        }
750    }
751
752    pub fn walk_exprs_in_pat(&self, pat_id: PatId, f: &mut impl FnMut(ExprId)) {
753        self.walk_pats(pat_id, &mut |pat| {
754            if let Pat::Expr(expr) | Pat::ConstBlock(expr) = self[pat] {
755                f(expr);
756            }
757        });
758    }
759
760    #[inline]
761    #[track_caller]
762    fn assert_expr_only(&self) -> &ExpressionOnlyStore {
763        self.expr_only.as_ref().expect("should have `ExpressionStore::expr_only`")
764    }
765
766    fn binding_hygiene(&self, binding: BindingId) -> HygieneId {
767        self.assert_expr_only().bindings[binding].hygiene
768    }
769
770    pub fn expr_path_hygiene(&self, expr: ExprId) -> HygieneId {
771        self.assert_expr_only().ident_hygiene.get(&expr.into()).copied().unwrap_or(HygieneId::ROOT)
772    }
773
774    pub fn pat_path_hygiene(&self, pat: PatId) -> HygieneId {
775        self.assert_expr_only().ident_hygiene.get(&pat.into()).copied().unwrap_or(HygieneId::ROOT)
776    }
777
778    pub fn expr_or_pat_path_hygiene(&self, id: ExprOrPatId) -> HygieneId {
779        match id {
780            ExprOrPatId::ExprId(id) => self.expr_path_hygiene(id),
781            ExprOrPatId::PatId(id) => self.pat_path_hygiene(id),
782        }
783    }
784
785    #[inline]
786    pub fn exprs(&self) -> impl Iterator<Item = (ExprId, &Expr)> {
787        match &self.expr_only {
788            Some(it) => it.exprs.iter(),
789            None => const { &Arena::new() }.iter(),
790        }
791    }
792
793    #[inline]
794    pub fn pats(&self) -> impl Iterator<Item = (PatId, &Pat)> {
795        match &self.expr_only {
796            Some(it) => it.pats.iter(),
797            None => const { &Arena::new() }.iter(),
798        }
799    }
800
801    #[inline]
802    pub fn bindings(&self) -> impl Iterator<Item = (BindingId, &Binding)> {
803        match &self.expr_only {
804            Some(it) => it.bindings.iter(),
805            None => const { &Arena::new() }.iter(),
806        }
807    }
808}
809
810impl Index<ExprId> for ExpressionStore {
811    type Output = Expr;
812
813    #[inline]
814    fn index(&self, expr: ExprId) -> &Expr {
815        &self.assert_expr_only().exprs[expr]
816    }
817}
818
819impl Index<PatId> for ExpressionStore {
820    type Output = Pat;
821
822    #[inline]
823    fn index(&self, pat: PatId) -> &Pat {
824        &self.assert_expr_only().pats[pat]
825    }
826}
827
828impl Index<LabelId> for ExpressionStore {
829    type Output = Label;
830
831    #[inline]
832    fn index(&self, label: LabelId) -> &Label {
833        &self.assert_expr_only().labels[label]
834    }
835}
836
837impl Index<BindingId> for ExpressionStore {
838    type Output = Binding;
839
840    #[inline]
841    fn index(&self, b: BindingId) -> &Binding {
842        &self.assert_expr_only().bindings[b]
843    }
844}
845
846impl Index<TypeRefId> for ExpressionStore {
847    type Output = TypeRef;
848
849    #[inline]
850    fn index(&self, b: TypeRefId) -> &TypeRef {
851        &self.types[b]
852    }
853}
854
855impl Index<LifetimeRefId> for ExpressionStore {
856    type Output = LifetimeRef;
857
858    #[inline]
859    fn index(&self, b: LifetimeRefId) -> &LifetimeRef {
860        &self.lifetimes[b]
861    }
862}
863
864impl Index<PathId> for ExpressionStore {
865    type Output = Path;
866
867    #[inline]
868    fn index(&self, index: PathId) -> &Self::Output {
869        let TypeRef::Path(path) = &self[index.type_ref()] else {
870            unreachable!("`PathId` always points to `TypeRef::Path`");
871        };
872        path
873    }
874}
875
876// FIXME: Change `node_` prefix to something more reasonable.
877// Perhaps `expr_syntax` and `expr_id`?
878impl ExpressionStoreSourceMap {
879    pub fn expr_or_pat_syntax(&self, id: ExprOrPatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
880        match id {
881            ExprOrPatId::ExprId(id) => self.expr_syntax(id),
882            ExprOrPatId::PatId(id) => self.pat_syntax(id),
883        }
884    }
885
886    #[inline]
887    fn expr_or_synthetic(&self) -> Result<&ExpressionOnlySourceMap, SyntheticSyntax> {
888        self.expr_only.as_deref().ok_or(SyntheticSyntax)
889    }
890
891    #[inline]
892    fn expr_only(&self) -> Option<&ExpressionOnlySourceMap> {
893        self.expr_only.as_deref()
894    }
895
896    #[inline]
897    #[track_caller]
898    fn assert_expr_only(&self) -> &ExpressionOnlySourceMap {
899        self.expr_only.as_ref().expect("should have `ExpressionStoreSourceMap::expr_only`")
900    }
901
902    pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprOrPatSource, SyntheticSyntax> {
903        self.expr_or_synthetic()?.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax)
904    }
905
906    pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprOrPatId> {
907        let src = node.map(AstPtr::new);
908        self.expr_only()?.expr_map.get(&src).cloned()
909    }
910
911    pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<MacroCallId> {
912        let src = node.map(AstPtr::new);
913        self.expr_only()?.expansions.get(&src).cloned()
914    }
915
916    pub fn macro_calls(&self) -> impl Iterator<Item = (InFile<MacroCallPtr>, MacroCallId)> + '_ {
917        self.expr_only().into_iter().flat_map(|it| it.expansions.iter().map(|(&a, &b)| (a, b)))
918    }
919
920    pub fn pat_syntax(&self, pat: PatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
921        self.expr_or_synthetic()?.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
922    }
923
924    pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<ExprOrPatId> {
925        self.expr_only()?.pat_map.get(&node.map(AstPtr::new)).cloned()
926    }
927
928    pub fn type_syntax(&self, id: TypeRefId) -> Result<TypeSource, SyntheticSyntax> {
929        self.types_map_back.get(id).cloned().ok_or(SyntheticSyntax)
930    }
931
932    pub fn node_type(&self, node: InFile<&ast::Type>) -> Option<TypeRefId> {
933        self.types_map.get(&node.map(AstPtr::new)).cloned()
934    }
935
936    pub fn label_syntax(&self, label: LabelId) -> LabelSource {
937        self.assert_expr_only().label_map_back[label]
938    }
939
940    pub fn patterns_for_binding(&self, binding: BindingId) -> &[PatId] {
941        self.assert_expr_only().binding_definitions.get(binding).map_or(&[], Deref::deref)
942    }
943
944    pub fn node_label(&self, node: InFile<&ast::Label>) -> Option<LabelId> {
945        let src = node.map(AstPtr::new);
946        self.expr_only()?.label_map.get(&src).cloned()
947    }
948
949    pub fn field_syntax(&self, expr: ExprId) -> FieldSource {
950        self.assert_expr_only().field_map_back[&expr]
951    }
952
953    pub fn pat_field_syntax(&self, pat: PatId) -> PatFieldSource {
954        self.assert_expr_only().pat_field_map_back[&pat]
955    }
956
957    pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroExpr>) -> Option<ExprOrPatId> {
958        let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::MacroExpr>).map(AstPtr::upcast);
959        self.expr_only()?.expr_map.get(&src).copied()
960    }
961
962    pub fn expansions(&self) -> impl Iterator<Item = (&InFile<MacroCallPtr>, &MacroCallId)> {
963        self.expr_only().into_iter().flat_map(|it| it.expansions.iter())
964    }
965
966    pub fn expansion(&self, node: InFile<&ast::MacroCall>) -> Option<MacroCallId> {
967        self.expr_only()?.expansions.get(&node.map(AstPtr::new)).copied()
968    }
969
970    pub fn implicit_format_args(
971        &self,
972        node: InFile<&ast::FormatArgsExpr>,
973    ) -> Option<(HygieneId, &[(syntax::TextRange, Name)])> {
974        let expr_only = self.expr_only()?;
975        let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
976        let (hygiene, names) = expr_only
977            .template_map
978            .as_ref()?
979            .format_args_to_captures
980            .get(&expr_only.expr_map.get(&src)?.as_expr()?)?;
981        Some((*hygiene, &**names))
982    }
983
984    pub fn format_args_implicit_capture(
985        &self,
986        capture_expr: ExprId,
987    ) -> Option<InFile<(ExprPtr, TextRange)>> {
988        self.expr_only()?
989            .template_map
990            .as_ref()?
991            .implicit_capture_to_source
992            .get(&capture_expr)
993            .copied()
994    }
995
996    pub fn asm_template_args(
997        &self,
998        node: InFile<&ast::AsmExpr>,
999    ) -> Option<(ExprId, &[Vec<(syntax::TextRange, usize)>])> {
1000        let expr_only = self.expr_only()?;
1001        let src = node.map(AstPtr::new).map(AstPtr::upcast::<ast::Expr>);
1002        let expr = expr_only.expr_map.get(&src)?.as_expr()?;
1003        Some(expr).zip(
1004            expr_only.template_map.as_ref()?.asm_to_captures.get(&expr).map(std::ops::Deref::deref),
1005        )
1006    }
1007
1008    /// Get a reference to the source map's diagnostics.
1009    pub fn diagnostics(&self) -> &[ExpressionStoreDiagnostics] {
1010        self.expr_only().map(|it| &*it.diagnostics).unwrap_or_default()
1011    }
1012}