hir_def/expr_store/
lower.rs

1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
2//! representation.
3
4mod asm;
5mod format_args;
6mod generics;
7mod path;
8
9use std::{cell::OnceCell, mem};
10
11use base_db::FxIndexSet;
12use cfg::CfgOptions;
13use either::Either;
14use hir_expand::{
15    HirFileId, InFile, MacroDefId,
16    name::{AsName, Name},
17    span_map::SpanMapRef,
18};
19use intern::{Symbol, sym};
20use rustc_hash::FxHashMap;
21use stdx::never;
22use syntax::{
23    AstNode, AstPtr, SyntaxNodePtr,
24    ast::{
25        self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasGenericArgs,
26        HasGenericParams, HasLoopBody, HasName, HasTypeBounds, IsString, RangeItem,
27        SlicePatComponents,
28    },
29};
30use thin_vec::ThinVec;
31use triomphe::Arc;
32use tt::TextRange;
33
34use crate::{
35    AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, MacroId,
36    ModuleDefId, ModuleId, TraitId, TypeAliasId, UnresolvedMacro,
37    attrs::AttrFlags,
38    db::DefDatabase,
39    expr_store::{
40        Body, BodySourceMap, ExprPtr, ExpressionStore, ExpressionStoreBuilder,
41        ExpressionStoreDiagnostics, ExpressionStoreSourceMap, HygieneId, LabelPtr, LifetimePtr,
42        PatPtr, TypePtr,
43        expander::Expander,
44        lower::generics::ImplTraitLowerFn,
45        path::{AssociatedTypeBinding, GenericArg, GenericArgs, GenericArgsParentheses, Path},
46    },
47    hir::{
48        Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind,
49        Expr, ExprId, Item, Label, LabelId, Literal, MatchArm, Movability, OffsetOf, Pat, PatId,
50        RecordFieldPat, RecordLitField, Statement, generics::GenericParams,
51    },
52    item_scope::BuiltinShadowMode,
53    item_tree::FieldsShape,
54    lang_item::{LangItemTarget, LangItems},
55    nameres::{DefMap, LocalDefMap, MacroSubNs, block_def_map},
56    type_ref::{
57        ArrayType, ConstRef, FnType, LifetimeRef, LifetimeRefId, Mutability, PathId, Rawness,
58        RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, UseArgRef,
59    },
60};
61
62pub use self::path::hir_segment_to_ast_segment;
63
64pub(super) fn lower_body(
65    db: &dyn DefDatabase,
66    owner: DefWithBodyId,
67    current_file_id: HirFileId,
68    module: ModuleId,
69    parameters: Option<ast::ParamList>,
70    body: Option<ast::Expr>,
71    is_async_fn: bool,
72) -> (Body, BodySourceMap) {
73    // We cannot leave the root span map empty and let any identifier from it be treated as root,
74    // because when inside nested macros `SyntaxContextId`s from the outer macro will be interleaved
75    // with the inner macro, and that will cause confusion because they won't be the same as `ROOT`
76    // even though they should be the same. Also, when the body comes from multiple expansions, their
77    // hygiene is different.
78
79    let mut self_param = None;
80    let mut source_map_self_param = None;
81    let mut params = vec![];
82    let mut collector = ExprCollector::new(db, module, current_file_id);
83
84    let skip_body = AttrFlags::query(
85        db,
86        match owner {
87            DefWithBodyId::FunctionId(it) => it.into(),
88            DefWithBodyId::StaticId(it) => it.into(),
89            DefWithBodyId::ConstId(it) => it.into(),
90            DefWithBodyId::VariantId(it) => it.into(),
91        },
92    )
93    .contains(AttrFlags::RUST_ANALYZER_SKIP);
94    // If #[rust_analyzer::skip] annotated, only construct enough information for the signature
95    // and skip the body.
96    if skip_body {
97        if let Some(param_list) = parameters {
98            if let Some(self_param_syn) =
99                param_list.self_param().filter(|self_param| collector.check_cfg(self_param))
100            {
101                let is_mutable =
102                    self_param_syn.mut_token().is_some() && self_param_syn.amp_token().is_none();
103                let hygiene = self_param_syn
104                    .name()
105                    .map(|name| collector.hygiene_id_for(name.syntax().text_range()))
106                    .unwrap_or(HygieneId::ROOT);
107                let binding_id: la_arena::Idx<Binding> = collector.alloc_binding(
108                    Name::new_symbol_root(sym::self_),
109                    BindingAnnotation::new(is_mutable, false),
110                    hygiene,
111                );
112                self_param = Some(binding_id);
113                source_map_self_param =
114                    Some(collector.expander.in_file(AstPtr::new(&self_param_syn)));
115            }
116            let count = param_list.params().filter(|it| collector.check_cfg(it)).count();
117            params = (0..count).map(|_| collector.missing_pat()).collect();
118        };
119        let body_expr = collector.missing_expr();
120        let (store, source_map) = collector.store.finish();
121        return (
122            Body { store, params: params.into_boxed_slice(), self_param, body_expr },
123            BodySourceMap { self_param: source_map_self_param, store: source_map },
124        );
125    }
126
127    if let Some(param_list) = parameters {
128        if let Some(self_param_syn) = param_list.self_param().filter(|it| collector.check_cfg(it)) {
129            let is_mutable =
130                self_param_syn.mut_token().is_some() && self_param_syn.amp_token().is_none();
131            let hygiene = self_param_syn
132                .name()
133                .map(|name| collector.hygiene_id_for(name.syntax().text_range()))
134                .unwrap_or(HygieneId::ROOT);
135            let binding_id: la_arena::Idx<Binding> = collector.alloc_binding(
136                Name::new_symbol_root(sym::self_),
137                BindingAnnotation::new(is_mutable, false),
138                hygiene,
139            );
140            self_param = Some(binding_id);
141            source_map_self_param = Some(collector.expander.in_file(AstPtr::new(&self_param_syn)));
142        }
143
144        for param in param_list.params() {
145            if collector.check_cfg(&param) {
146                let param_pat = collector.collect_pat_top(param.pat());
147                params.push(param_pat);
148            }
149        }
150    };
151
152    let body_expr = collector.collect(
153        body,
154        if is_async_fn {
155            Awaitable::Yes
156        } else {
157            match owner {
158                DefWithBodyId::FunctionId(..) => Awaitable::No("non-async function"),
159                DefWithBodyId::StaticId(..) => Awaitable::No("static"),
160                DefWithBodyId::ConstId(..) => Awaitable::No("constant"),
161                DefWithBodyId::VariantId(..) => Awaitable::No("enum variant"),
162            }
163        },
164    );
165
166    let (store, source_map) = collector.store.finish();
167    (
168        Body { store, params: params.into_boxed_slice(), self_param, body_expr },
169        BodySourceMap { self_param: source_map_self_param, store: source_map },
170    )
171}
172
173pub(crate) fn lower_type_ref(
174    db: &dyn DefDatabase,
175    module: ModuleId,
176    type_ref: InFile<Option<ast::Type>>,
177) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId) {
178    let mut expr_collector = ExprCollector::new(db, module, type_ref.file_id);
179    let type_ref =
180        expr_collector.lower_type_ref_opt(type_ref.value, &mut ExprCollector::impl_trait_allocator);
181    let (store, source_map) = expr_collector.store.finish();
182    (store, source_map, type_ref)
183}
184
185pub(crate) fn lower_generic_params(
186    db: &dyn DefDatabase,
187    module: ModuleId,
188    def: GenericDefId,
189    file_id: HirFileId,
190    param_list: Option<ast::GenericParamList>,
191    where_clause: Option<ast::WhereClause>,
192) -> (Arc<ExpressionStore>, Arc<GenericParams>, ExpressionStoreSourceMap) {
193    let mut expr_collector = ExprCollector::new(db, module, file_id);
194    let mut collector = generics::GenericParamsCollector::new(def);
195    collector.lower(&mut expr_collector, param_list, where_clause);
196    let params = collector.finish();
197    let (store, source_map) = expr_collector.store.finish();
198    (Arc::new(store), params, source_map)
199}
200
201pub(crate) fn lower_impl(
202    db: &dyn DefDatabase,
203    module: ModuleId,
204    impl_syntax: InFile<ast::Impl>,
205    impl_id: ImplId,
206) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId, Option<TraitRef>, Arc<GenericParams>) {
207    let mut expr_collector = ExprCollector::new(db, module, impl_syntax.file_id);
208    let self_ty =
209        expr_collector.lower_type_ref_opt_disallow_impl_trait(impl_syntax.value.self_ty());
210    let trait_ = impl_syntax.value.trait_().and_then(|it| match &it {
211        ast::Type::PathType(path_type) => {
212            let path = expr_collector
213                .lower_path_type(path_type, &mut ExprCollector::impl_trait_allocator)?;
214            Some(TraitRef { path: expr_collector.alloc_path(path, AstPtr::new(&it)) })
215        }
216        _ => None,
217    });
218    let mut collector = generics::GenericParamsCollector::new(impl_id.into());
219    collector.lower(
220        &mut expr_collector,
221        impl_syntax.value.generic_param_list(),
222        impl_syntax.value.where_clause(),
223    );
224    let params = collector.finish();
225    let (store, source_map) = expr_collector.store.finish();
226    (store, source_map, self_ty, trait_, params)
227}
228
229pub(crate) fn lower_trait(
230    db: &dyn DefDatabase,
231    module: ModuleId,
232    trait_syntax: InFile<ast::Trait>,
233    trait_id: TraitId,
234) -> (ExpressionStore, ExpressionStoreSourceMap, Arc<GenericParams>) {
235    let mut expr_collector = ExprCollector::new(db, module, trait_syntax.file_id);
236    let mut collector = generics::GenericParamsCollector::with_self_param(
237        &mut expr_collector,
238        trait_id.into(),
239        trait_syntax.value.type_bound_list(),
240    );
241    collector.lower(
242        &mut expr_collector,
243        trait_syntax.value.generic_param_list(),
244        trait_syntax.value.where_clause(),
245    );
246    let params = collector.finish();
247    let (store, source_map) = expr_collector.store.finish();
248    (store, source_map, params)
249}
250
251pub(crate) fn lower_type_alias(
252    db: &dyn DefDatabase,
253    module: ModuleId,
254    alias: InFile<ast::TypeAlias>,
255    type_alias_id: TypeAliasId,
256) -> (
257    ExpressionStore,
258    ExpressionStoreSourceMap,
259    Arc<GenericParams>,
260    Box<[TypeBound]>,
261    Option<TypeRefId>,
262) {
263    let mut expr_collector = ExprCollector::new(db, module, alias.file_id);
264    let bounds = alias
265        .value
266        .type_bound_list()
267        .map(|bounds| {
268            bounds
269                .bounds()
270                .map(|bound| {
271                    expr_collector.lower_type_bound(bound, &mut ExprCollector::impl_trait_allocator)
272                })
273                .collect()
274        })
275        .unwrap_or_default();
276    let mut collector = generics::GenericParamsCollector::new(type_alias_id.into());
277    collector.lower(
278        &mut expr_collector,
279        alias.value.generic_param_list(),
280        alias.value.where_clause(),
281    );
282    let params = collector.finish();
283    let type_ref = alias
284        .value
285        .ty()
286        .map(|ty| expr_collector.lower_type_ref(ty, &mut ExprCollector::impl_trait_allocator));
287    let (store, source_map) = expr_collector.store.finish();
288    (store, source_map, params, bounds, type_ref)
289}
290
291pub(crate) fn lower_function(
292    db: &dyn DefDatabase,
293    module: ModuleId,
294    fn_: InFile<ast::Fn>,
295    function_id: FunctionId,
296) -> (
297    ExpressionStore,
298    ExpressionStoreSourceMap,
299    Arc<GenericParams>,
300    Box<[TypeRefId]>,
301    Option<TypeRefId>,
302    bool,
303    bool,
304) {
305    let mut expr_collector = ExprCollector::new(db, module, fn_.file_id);
306    let mut collector = generics::GenericParamsCollector::new(function_id.into());
307    collector.lower(&mut expr_collector, fn_.value.generic_param_list(), fn_.value.where_clause());
308    let mut params = vec![];
309    let mut has_self_param = false;
310    let mut has_variadic = false;
311    collector.collect_impl_trait(&mut expr_collector, |collector, mut impl_trait_lower_fn| {
312        if let Some(param_list) = fn_.value.param_list() {
313            if let Some(param) = param_list.self_param() {
314                let enabled = collector.check_cfg(&param);
315                if enabled {
316                    has_self_param = true;
317                    params.push(match param.ty() {
318                        Some(ty) => collector.lower_type_ref(ty, &mut impl_trait_lower_fn),
319                        None => {
320                            let self_type = collector.alloc_type_ref_desugared(TypeRef::Path(
321                                Name::new_symbol_root(sym::Self_).into(),
322                            ));
323                            let lifetime = param
324                                .lifetime()
325                                .map(|lifetime| collector.lower_lifetime_ref(lifetime));
326                            match param.kind() {
327                                ast::SelfParamKind::Owned => self_type,
328                                ast::SelfParamKind::Ref => collector.alloc_type_ref_desugared(
329                                    TypeRef::Reference(Box::new(RefType {
330                                        ty: self_type,
331                                        lifetime,
332                                        mutability: Mutability::Shared,
333                                    })),
334                                ),
335                                ast::SelfParamKind::MutRef => collector.alloc_type_ref_desugared(
336                                    TypeRef::Reference(Box::new(RefType {
337                                        ty: self_type,
338                                        lifetime,
339                                        mutability: Mutability::Mut,
340                                    })),
341                                ),
342                            }
343                        }
344                    });
345                }
346            }
347            let p = param_list
348                .params()
349                .filter(|param| collector.check_cfg(param))
350                .filter(|param| {
351                    let is_variadic = param.dotdotdot_token().is_some();
352                    has_variadic |= is_variadic;
353                    !is_variadic
354                })
355                .map(|param| param.ty())
356                // FIXME
357                .collect::<Vec<_>>();
358            for p in p {
359                params.push(collector.lower_type_ref_opt(p, &mut impl_trait_lower_fn));
360            }
361        }
362    });
363    let generics = collector.finish();
364    let return_type = fn_.value.ret_type().map(|ret_type| {
365        expr_collector.lower_type_ref_opt(ret_type.ty(), &mut ExprCollector::impl_trait_allocator)
366    });
367
368    let return_type = if fn_.value.async_token().is_some() {
369        let path = hir_expand::mod_path::path![core::future::Future];
370        let mut generic_args: Vec<_> =
371            std::iter::repeat_n(None, path.segments().len() - 1).collect();
372        let binding = AssociatedTypeBinding {
373            name: Name::new_symbol_root(sym::Output),
374            args: None,
375            type_ref: Some(
376                return_type
377                    .unwrap_or_else(|| expr_collector.alloc_type_ref_desugared(TypeRef::unit())),
378            ),
379            bounds: Box::default(),
380        };
381        generic_args
382            .push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() }));
383
384        let path = Path::from_known_path(path, generic_args);
385        let path = PathId::from_type_ref_unchecked(
386            expr_collector.alloc_type_ref_desugared(TypeRef::Path(path)),
387        );
388        let ty_bound = TypeBound::Path(path, TraitBoundModifier::None);
389        Some(
390            expr_collector
391                .alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound]))),
392        )
393    } else {
394        return_type
395    };
396    let (store, source_map) = expr_collector.store.finish();
397    (
398        store,
399        source_map,
400        generics,
401        params.into_boxed_slice(),
402        return_type,
403        has_self_param,
404        has_variadic,
405    )
406}
407
408pub struct ExprCollector<'db> {
409    db: &'db dyn DefDatabase,
410    cfg_options: &'db CfgOptions,
411    expander: Expander,
412    def_map: &'db DefMap,
413    local_def_map: &'db LocalDefMap,
414    module: ModuleId,
415    lang_items: OnceCell<&'db LangItems>,
416    pub store: ExpressionStoreBuilder,
417
418    // state stuff
419    // Prevent nested impl traits like `impl Foo<impl Bar>`.
420    outer_impl_trait: bool,
421
422    is_lowering_coroutine: bool,
423
424    /// Legacy (`macro_rules!`) macros can have multiple definitions and shadow each other,
425    /// and we need to find the current definition. So we track the number of definitions we saw.
426    current_block_legacy_macro_defs_count: FxHashMap<Name, usize>,
427
428    current_try_block_label: Option<LabelId>,
429
430    label_ribs: Vec<LabelRib>,
431    unowned_bindings: Vec<BindingId>,
432
433    awaitable_context: Option<Awaitable>,
434    krate: base_db::Crate,
435
436    name_generator_index: usize,
437}
438
439#[derive(Clone, Debug)]
440struct LabelRib {
441    kind: RibKind,
442}
443
444impl LabelRib {
445    fn new(kind: RibKind) -> Self {
446        LabelRib { kind }
447    }
448}
449
450#[derive(Clone, Debug, PartialEq, Eq)]
451enum RibKind {
452    Normal(Name, LabelId, HygieneId),
453    Closure,
454    Constant,
455    MacroDef(Box<MacroDefId>),
456}
457
458impl RibKind {
459    /// This rib forbids referring to labels defined in upwards ribs.
460    fn is_label_barrier(&self) -> bool {
461        match self {
462            RibKind::Normal(..) | RibKind::MacroDef(_) => false,
463            RibKind::Closure | RibKind::Constant => true,
464        }
465    }
466}
467
468#[derive(PartialEq, Eq, Debug, Copy, Clone)]
469enum Awaitable {
470    Yes,
471    No(&'static str),
472}
473
474#[derive(Debug, Default)]
475struct BindingList {
476    map: FxHashMap<(Name, HygieneId), BindingId>,
477    is_used: FxHashMap<BindingId, bool>,
478    reject_new: bool,
479}
480
481impl BindingList {
482    fn find(
483        &mut self,
484        ec: &mut ExprCollector<'_>,
485        name: Name,
486        hygiene: HygieneId,
487        mode: BindingAnnotation,
488    ) -> BindingId {
489        let id = *self
490            .map
491            .entry((name, hygiene))
492            .or_insert_with_key(|(name, hygiene)| ec.alloc_binding(name.clone(), mode, *hygiene));
493        if ec.store.bindings[id].mode != mode {
494            ec.store.bindings[id].problems = Some(BindingProblems::BoundInconsistently);
495        }
496        self.check_is_used(ec, id);
497        id
498    }
499
500    fn check_is_used(&mut self, ec: &mut ExprCollector<'_>, id: BindingId) {
501        match self.is_used.get(&id) {
502            None => {
503                if self.reject_new {
504                    ec.store.bindings[id].problems = Some(BindingProblems::NotBoundAcrossAll);
505                }
506            }
507            Some(true) => {
508                ec.store.bindings[id].problems = Some(BindingProblems::BoundMoreThanOnce);
509            }
510            Some(false) => {}
511        }
512        self.is_used.insert(id, true);
513    }
514}
515
516impl<'db> ExprCollector<'db> {
517    pub fn new(
518        db: &dyn DefDatabase,
519        module: ModuleId,
520        current_file_id: HirFileId,
521    ) -> ExprCollector<'_> {
522        let (def_map, local_def_map) = module.local_def_map(db);
523        let expander = Expander::new(db, current_file_id, def_map);
524        let krate = module.krate(db);
525        ExprCollector {
526            db,
527            cfg_options: krate.cfg_options(db),
528            module,
529            def_map,
530            local_def_map,
531            lang_items: OnceCell::new(),
532            store: ExpressionStoreBuilder::default(),
533            expander,
534            current_try_block_label: None,
535            is_lowering_coroutine: false,
536            label_ribs: Vec::new(),
537            unowned_bindings: Vec::new(),
538            awaitable_context: None,
539            current_block_legacy_macro_defs_count: FxHashMap::default(),
540            outer_impl_trait: false,
541            krate,
542            name_generator_index: 0,
543        }
544    }
545
546    fn generate_new_name(&mut self) -> Name {
547        let index = self.name_generator_index;
548        self.name_generator_index += 1;
549        Name::generate_new_name(index)
550    }
551
552    #[inline]
553    pub(crate) fn lang_items(&self) -> &'db LangItems {
554        self.lang_items.get_or_init(|| crate::lang_item::lang_items(self.db, self.def_map.krate()))
555    }
556
557    #[inline]
558    pub(crate) fn span_map(&self) -> SpanMapRef<'_> {
559        self.expander.span_map()
560    }
561
562    pub fn lower_lifetime_ref(&mut self, lifetime: ast::Lifetime) -> LifetimeRefId {
563        // FIXME: Keyword check?
564        let lifetime_ref = match &*lifetime.text() {
565            "" | "'" => LifetimeRef::Error,
566            "'static" => LifetimeRef::Static,
567            "'_" => LifetimeRef::Placeholder,
568            text => LifetimeRef::Named(Name::new_lifetime(text)),
569        };
570        self.alloc_lifetime_ref(lifetime_ref, AstPtr::new(&lifetime))
571    }
572
573    pub fn lower_lifetime_ref_opt(&mut self, lifetime: Option<ast::Lifetime>) -> LifetimeRefId {
574        match lifetime {
575            Some(lifetime) => self.lower_lifetime_ref(lifetime),
576            None => self.alloc_lifetime_ref_desugared(LifetimeRef::Placeholder),
577        }
578    }
579
580    /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
581    pub fn lower_type_ref(
582        &mut self,
583        node: ast::Type,
584        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
585    ) -> TypeRefId {
586        let ty = match &node {
587            ast::Type::ParenType(inner) => {
588                return self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);
589            }
590            ast::Type::TupleType(inner) => TypeRef::Tuple(ThinVec::from_iter(Vec::from_iter(
591                inner.fields().map(|it| self.lower_type_ref(it, impl_trait_lower_fn)),
592            ))),
593            ast::Type::NeverType(..) => TypeRef::Never,
594            ast::Type::PathType(inner) => inner
595                .path()
596                .and_then(|it| self.lower_path(it, impl_trait_lower_fn))
597                .map(TypeRef::Path)
598                .unwrap_or(TypeRef::Error),
599            ast::Type::PtrType(inner) => {
600                let inner_ty = self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);
601                let mutability = Mutability::from_mutable(inner.mut_token().is_some());
602                TypeRef::RawPtr(inner_ty, mutability)
603            }
604            ast::Type::ArrayType(inner) => {
605                let len = self.lower_const_arg_opt(inner.const_arg());
606                TypeRef::Array(ArrayType {
607                    ty: self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn),
608                    len,
609                })
610            }
611            ast::Type::SliceType(inner) => {
612                TypeRef::Slice(self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn))
613            }
614            ast::Type::RefType(inner) => {
615                let inner_ty = self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);
616                let lifetime = inner.lifetime().map(|lt| self.lower_lifetime_ref(lt));
617                let mutability = Mutability::from_mutable(inner.mut_token().is_some());
618                TypeRef::Reference(Box::new(RefType { ty: inner_ty, lifetime, mutability }))
619            }
620            ast::Type::InferType(_inner) => TypeRef::Placeholder,
621            ast::Type::FnPtrType(inner) => {
622                let ret_ty = inner
623                    .ret_type()
624                    .and_then(|rt| rt.ty())
625                    .map(|it| self.lower_type_ref(it, impl_trait_lower_fn))
626                    .unwrap_or_else(|| self.alloc_type_ref_desugared(TypeRef::unit()));
627                let mut is_varargs = false;
628                let mut params = if let Some(pl) = inner.param_list() {
629                    if let Some(param) = pl.params().last() {
630                        is_varargs = param.dotdotdot_token().is_some();
631                    }
632
633                    pl.params()
634                        .map(|it| {
635                            let type_ref = self.lower_type_ref_opt(it.ty(), impl_trait_lower_fn);
636                            let name = match it.pat() {
637                                Some(ast::Pat::IdentPat(it)) => Some(
638                                    it.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing),
639                                ),
640                                _ => None,
641                            };
642                            (name, type_ref)
643                        })
644                        .collect()
645                } else {
646                    Vec::with_capacity(1)
647                };
648                fn lower_abi(abi: ast::Abi) -> Symbol {
649                    match abi.abi_string() {
650                        Some(tok) => Symbol::intern(tok.text_without_quotes()),
651                        // `extern` default to be `extern "C"`.
652                        _ => sym::C,
653                    }
654                }
655
656                let abi = inner.abi().map(lower_abi);
657                params.push((None, ret_ty));
658                TypeRef::Fn(Box::new(FnType {
659                    is_varargs,
660                    is_unsafe: inner.unsafe_token().is_some(),
661                    abi,
662                    params: params.into_boxed_slice(),
663                }))
664            }
665            // for types are close enough for our purposes to the inner type for now...
666            ast::Type::ForType(inner) => {
667                return self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);
668            }
669            ast::Type::ImplTraitType(inner) => {
670                if self.outer_impl_trait {
671                    // Disallow nested impl traits
672                    TypeRef::Error
673                } else {
674                    return self.with_outer_impl_trait_scope(true, |this| {
675                        let type_bounds =
676                            this.type_bounds_from_ast(inner.type_bound_list(), impl_trait_lower_fn);
677                        impl_trait_lower_fn(this, AstPtr::new(&node), type_bounds)
678                    });
679                }
680            }
681            ast::Type::DynTraitType(inner) => TypeRef::DynTrait(
682                self.type_bounds_from_ast(inner.type_bound_list(), impl_trait_lower_fn),
683            ),
684            ast::Type::MacroType(mt) => match mt.macro_call() {
685                Some(mcall) => {
686                    let macro_ptr = AstPtr::new(&mcall);
687                    let src = self.expander.in_file(AstPtr::new(&node));
688                    let id = self.collect_macro_call(mcall, macro_ptr, true, |this, expansion| {
689                        this.lower_type_ref_opt(expansion, impl_trait_lower_fn)
690                    });
691                    self.store.types_map.insert(src, id);
692                    return id;
693                }
694                None => TypeRef::Error,
695            },
696        };
697        self.alloc_type_ref(ty, AstPtr::new(&node))
698    }
699
700    pub(crate) fn lower_type_ref_disallow_impl_trait(&mut self, node: ast::Type) -> TypeRefId {
701        self.lower_type_ref(node, &mut Self::impl_trait_error_allocator)
702    }
703
704    pub(crate) fn lower_type_ref_opt(
705        &mut self,
706        node: Option<ast::Type>,
707        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
708    ) -> TypeRefId {
709        match node {
710            Some(node) => self.lower_type_ref(node, impl_trait_lower_fn),
711            None => self.alloc_error_type(),
712        }
713    }
714
715    pub(crate) fn lower_type_ref_opt_disallow_impl_trait(
716        &mut self,
717        node: Option<ast::Type>,
718    ) -> TypeRefId {
719        self.lower_type_ref_opt(node, &mut Self::impl_trait_error_allocator)
720    }
721
722    fn alloc_type_ref(&mut self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {
723        let id = self.store.types.alloc(type_ref);
724        let ptr = self.expander.in_file(node);
725        self.store.types_map_back.insert(id, ptr);
726        self.store.types_map.insert(ptr, id);
727        id
728    }
729
730    fn alloc_lifetime_ref(
731        &mut self,
732        lifetime_ref: LifetimeRef,
733        node: LifetimePtr,
734    ) -> LifetimeRefId {
735        let id = self.store.lifetimes.alloc(lifetime_ref);
736        let ptr = self.expander.in_file(node);
737        self.store.lifetime_map_back.insert(id, ptr);
738        self.store.lifetime_map.insert(ptr, id);
739        id
740    }
741
742    fn alloc_type_ref_desugared(&mut self, type_ref: TypeRef) -> TypeRefId {
743        self.store.types.alloc(type_ref)
744    }
745
746    fn alloc_lifetime_ref_desugared(&mut self, lifetime_ref: LifetimeRef) -> LifetimeRefId {
747        self.store.lifetimes.alloc(lifetime_ref)
748    }
749
750    fn alloc_error_type(&mut self) -> TypeRefId {
751        self.store.types.alloc(TypeRef::Error)
752    }
753
754    pub fn lower_path(
755        &mut self,
756        ast: ast::Path,
757        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
758    ) -> Option<Path> {
759        super::lower::path::lower_path(self, ast, impl_trait_lower_fn)
760    }
761
762    fn with_outer_impl_trait_scope<R>(
763        &mut self,
764        impl_trait: bool,
765        f: impl FnOnce(&mut Self) -> R,
766    ) -> R {
767        let old = mem::replace(&mut self.outer_impl_trait, impl_trait);
768        let result = f(self);
769        self.outer_impl_trait = old;
770        result
771    }
772
773    pub fn impl_trait_error_allocator(
774        ec: &mut ExprCollector<'_>,
775        ptr: TypePtr,
776        _: ThinVec<TypeBound>,
777    ) -> TypeRefId {
778        ec.alloc_type_ref(TypeRef::Error, ptr)
779    }
780
781    fn impl_trait_allocator(
782        ec: &mut ExprCollector<'_>,
783        ptr: TypePtr,
784        bounds: ThinVec<TypeBound>,
785    ) -> TypeRefId {
786        ec.alloc_type_ref(TypeRef::ImplTrait(bounds), ptr)
787    }
788
789    fn alloc_path(&mut self, path: Path, node: TypePtr) -> PathId {
790        PathId::from_type_ref_unchecked(self.alloc_type_ref(TypeRef::Path(path), node))
791    }
792
793    /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
794    /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
795    pub fn lower_generic_args_from_fn_path(
796        &mut self,
797        args: Option<ast::ParenthesizedArgList>,
798        ret_type: Option<ast::RetType>,
799        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
800    ) -> Option<GenericArgs> {
801        let params = args?;
802        let mut param_types = Vec::new();
803        for param in params.type_args() {
804            let type_ref = self.lower_type_ref_opt(param.ty(), impl_trait_lower_fn);
805            param_types.push(type_ref);
806        }
807        let args = Box::new([GenericArg::Type(
808            self.alloc_type_ref_desugared(TypeRef::Tuple(ThinVec::from_iter(param_types))),
809        )]);
810        let bindings = if let Some(ret_type) = ret_type {
811            let type_ref = self.lower_type_ref_opt(ret_type.ty(), impl_trait_lower_fn);
812            Box::new([AssociatedTypeBinding {
813                name: Name::new_symbol_root(sym::Output),
814                args: None,
815                type_ref: Some(type_ref),
816                bounds: Box::default(),
817            }])
818        } else {
819            // -> ()
820            let type_ref = self.alloc_type_ref_desugared(TypeRef::unit());
821            Box::new([AssociatedTypeBinding {
822                name: Name::new_symbol_root(sym::Output),
823                args: None,
824                type_ref: Some(type_ref),
825                bounds: Box::default(),
826            }])
827        };
828        Some(GenericArgs {
829            args,
830            has_self_type: false,
831            bindings,
832            parenthesized: GenericArgsParentheses::ParenSugar,
833        })
834    }
835
836    pub(super) fn lower_generic_args(
837        &mut self,
838        node: ast::GenericArgList,
839        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
840    ) -> Option<GenericArgs> {
841        // This needs to be kept in sync with `hir_generic_arg_to_ast()`.
842        let mut args = Vec::new();
843        let mut bindings = Vec::new();
844        for generic_arg in node.generic_args() {
845            match generic_arg {
846                ast::GenericArg::TypeArg(type_arg) => {
847                    let type_ref = self.lower_type_ref_opt(type_arg.ty(), impl_trait_lower_fn);
848                    args.push(GenericArg::Type(type_ref));
849                }
850                ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
851                    // This needs to be kept in sync with `hir_assoc_type_binding_to_ast()`.
852                    if assoc_type_arg.param_list().is_some() {
853                        // We currently ignore associated return type bounds.
854                        continue;
855                    }
856                    if let Some(name_ref) = assoc_type_arg.name_ref() {
857                        // Nested impl traits like `impl Foo<Assoc = impl Bar>` are allowed
858                        self.with_outer_impl_trait_scope(false, |this| {
859                            let name = name_ref.as_name();
860                            let args = assoc_type_arg
861                                .generic_arg_list()
862                                .and_then(|args| this.lower_generic_args(args, impl_trait_lower_fn))
863                                .or_else(|| {
864                                    assoc_type_arg
865                                        .return_type_syntax()
866                                        .map(|_| GenericArgs::return_type_notation())
867                                });
868                            let type_ref = assoc_type_arg
869                                .ty()
870                                .map(|it| this.lower_type_ref(it, impl_trait_lower_fn));
871                            let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
872                                l.bounds()
873                                    .map(|it| this.lower_type_bound(it, impl_trait_lower_fn))
874                                    .collect()
875                            } else {
876                                Box::default()
877                            };
878                            bindings.push(AssociatedTypeBinding { name, args, type_ref, bounds });
879                        });
880                    }
881                }
882                ast::GenericArg::LifetimeArg(lifetime_arg) => {
883                    if let Some(lifetime) = lifetime_arg.lifetime() {
884                        let lifetime_ref = self.lower_lifetime_ref(lifetime);
885                        args.push(GenericArg::Lifetime(lifetime_ref))
886                    }
887                }
888                ast::GenericArg::ConstArg(arg) => {
889                    let arg = self.lower_const_arg(arg);
890                    args.push(GenericArg::Const(arg))
891                }
892            }
893        }
894
895        if args.is_empty() && bindings.is_empty() {
896            return None;
897        }
898        Some(GenericArgs {
899            args: args.into_boxed_slice(),
900            has_self_type: false,
901            bindings: bindings.into_boxed_slice(),
902            parenthesized: GenericArgsParentheses::No,
903        })
904    }
905
906    fn collect(&mut self, expr: Option<ast::Expr>, awaitable: Awaitable) -> ExprId {
907        self.awaitable_context.replace(awaitable);
908        self.with_label_rib(RibKind::Closure, |this| {
909            if awaitable == Awaitable::Yes {
910                match expr {
911                    Some(e) => {
912                        let syntax_ptr = AstPtr::new(&e);
913                        let expr = this.collect_expr(e);
914                        this.alloc_expr_desugared_with_ptr(
915                            Expr::Async { id: None, statements: Box::new([]), tail: Some(expr) },
916                            syntax_ptr,
917                        )
918                    }
919                    None => this.missing_expr(),
920                }
921            } else {
922                this.collect_expr_opt(expr)
923            }
924        })
925    }
926
927    fn type_bounds_from_ast(
928        &mut self,
929        type_bounds_opt: Option<ast::TypeBoundList>,
930        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
931    ) -> ThinVec<TypeBound> {
932        if let Some(type_bounds) = type_bounds_opt {
933            ThinVec::from_iter(Vec::from_iter(
934                type_bounds.bounds().map(|it| self.lower_type_bound(it, impl_trait_lower_fn)),
935            ))
936        } else {
937            ThinVec::from_iter([])
938        }
939    }
940
941    fn lower_path_type(
942        &mut self,
943        path_type: &ast::PathType,
944        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
945    ) -> Option<Path> {
946        let path = self.lower_path(path_type.path()?, impl_trait_lower_fn)?;
947        Some(path)
948    }
949
950    fn lower_type_bound(
951        &mut self,
952        node: ast::TypeBound,
953        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
954    ) -> TypeBound {
955        let Some(kind) = node.kind() else { return TypeBound::Error };
956        match kind {
957            ast::TypeBoundKind::PathType(binder, path_type) => {
958                let binder = match binder.and_then(|it| it.generic_param_list()) {
959                    Some(gpl) => gpl
960                        .lifetime_params()
961                        .flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(&lt.text())))
962                        .collect(),
963                    None => ThinVec::default(),
964                };
965                let m = match node.question_mark_token() {
966                    Some(_) => TraitBoundModifier::Maybe,
967                    None => TraitBoundModifier::None,
968                };
969                self.lower_path_type(&path_type, impl_trait_lower_fn)
970                    .map(|p| {
971                        let path = self.alloc_path(p, AstPtr::new(&path_type).upcast());
972                        if binder.is_empty() {
973                            TypeBound::Path(path, m)
974                        } else {
975                            TypeBound::ForLifetime(binder, path)
976                        }
977                    })
978                    .unwrap_or(TypeBound::Error)
979            }
980            ast::TypeBoundKind::Use(gal) => TypeBound::Use(
981                gal.use_bound_generic_args()
982                    .map(|p| match p {
983                        ast::UseBoundGenericArg::Lifetime(l) => {
984                            UseArgRef::Lifetime(self.lower_lifetime_ref(l))
985                        }
986                        ast::UseBoundGenericArg::NameRef(n) => UseArgRef::Name(n.as_name()),
987                    })
988                    .collect(),
989            ),
990            ast::TypeBoundKind::Lifetime(lifetime) => {
991                TypeBound::Lifetime(self.lower_lifetime_ref(lifetime))
992            }
993        }
994    }
995
996    fn lower_const_arg_opt(&mut self, arg: Option<ast::ConstArg>) -> ConstRef {
997        ConstRef { expr: self.collect_expr_opt(arg.and_then(|it| it.expr())) }
998    }
999
1000    fn lower_const_arg(&mut self, arg: ast::ConstArg) -> ConstRef {
1001        ConstRef { expr: self.collect_expr_opt(arg.expr()) }
1002    }
1003
1004    fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
1005        self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr())
1006    }
1007
1008    /// Returns `None` if and only if the expression is `#[cfg]`d out.
1009    fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
1010        let syntax_ptr = AstPtr::new(&expr);
1011        if !self.check_cfg(&expr) {
1012            return None;
1013        }
1014
1015        // FIXME: Move some of these arms out into separate methods for clarity
1016        Some(match expr {
1017            ast::Expr::IfExpr(e) => {
1018                let then_branch = self.collect_block_opt(e.then_branch());
1019
1020                let else_branch = e.else_branch().map(|b| match b {
1021                    ast::ElseBranch::Block(it) => self.collect_block(it),
1022                    ast::ElseBranch::IfExpr(elif) => {
1023                        let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
1024                        self.collect_expr(expr)
1025                    }
1026                });
1027
1028                let condition = self.collect_expr_opt(e.condition());
1029
1030                self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
1031            }
1032            ast::Expr::LetExpr(e) => {
1033                let pat = self.collect_pat_top(e.pat());
1034                let expr = self.collect_expr_opt(e.expr());
1035                self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr)
1036            }
1037            ast::Expr::BlockExpr(e) => match e.modifier() {
1038                Some(ast::BlockModifier::Try(_)) => self.desugar_try_block(e),
1039                Some(ast::BlockModifier::Unsafe(_)) => {
1040                    self.collect_block_(e, |id, statements, tail| Expr::Unsafe {
1041                        id,
1042                        statements,
1043                        tail,
1044                    })
1045                }
1046                Some(ast::BlockModifier::Label(label)) => {
1047                    let label_hygiene = self.hygiene_id_for(label.syntax().text_range());
1048                    let label_id = self.collect_label(label);
1049                    self.with_labeled_rib(label_id, label_hygiene, |this| {
1050                        this.collect_block_(e, |id, statements, tail| Expr::Block {
1051                            id,
1052                            statements,
1053                            tail,
1054                            label: Some(label_id),
1055                        })
1056                    })
1057                }
1058                Some(ast::BlockModifier::Async(_)) => {
1059                    self.with_label_rib(RibKind::Closure, |this| {
1060                        this.with_awaitable_block(Awaitable::Yes, |this| {
1061                            this.collect_block_(e, |id, statements, tail| Expr::Async {
1062                                id,
1063                                statements,
1064                                tail,
1065                            })
1066                        })
1067                    })
1068                }
1069                Some(ast::BlockModifier::Const(_)) => {
1070                    self.with_label_rib(RibKind::Constant, |this| {
1071                        this.with_awaitable_block(Awaitable::No("constant block"), |this| {
1072                            this.with_binding_owner(|this| {
1073                                let inner_expr = this.collect_block(e);
1074                                this.alloc_expr(Expr::Const(inner_expr), syntax_ptr)
1075                            })
1076                        })
1077                    })
1078                }
1079                // FIXME
1080                Some(ast::BlockModifier::AsyncGen(_)) => {
1081                    self.with_awaitable_block(Awaitable::Yes, |this| this.collect_block(e))
1082                }
1083                Some(ast::BlockModifier::Gen(_)) => self
1084                    .with_awaitable_block(Awaitable::No("non-async gen block"), |this| {
1085                        this.collect_block(e)
1086                    }),
1087                None => self.collect_block(e),
1088            },
1089            ast::Expr::LoopExpr(e) => {
1090                let label = e.label().map(|label| {
1091                    (self.hygiene_id_for(label.syntax().text_range()), self.collect_label(label))
1092                });
1093                let body = self.collect_labelled_block_opt(label, e.loop_body());
1094                self.alloc_expr(Expr::Loop { body, label: label.map(|it| it.1) }, syntax_ptr)
1095            }
1096            ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e),
1097            ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e),
1098            ast::Expr::CallExpr(e) => {
1099                // FIXME: Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c
1100                let is_rustc_box = {
1101                    let attrs = e.attrs();
1102                    attrs.filter_map(|it| it.as_simple_atom()).any(|it| it == "rustc_box")
1103                };
1104                if is_rustc_box {
1105                    let expr = self.collect_expr_opt(e.arg_list().and_then(|it| it.args().next()));
1106                    self.alloc_expr(Expr::Box { expr }, syntax_ptr)
1107                } else {
1108                    let callee = self.collect_expr_opt(e.expr());
1109                    let args = if let Some(arg_list) = e.arg_list() {
1110                        arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
1111                    } else {
1112                        Box::default()
1113                    };
1114                    self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
1115                }
1116            }
1117            ast::Expr::MethodCallExpr(e) => {
1118                let receiver = self.collect_expr_opt(e.receiver());
1119                let args = if let Some(arg_list) = e.arg_list() {
1120                    arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
1121                } else {
1122                    Box::default()
1123                };
1124                let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
1125                let generic_args = e
1126                    .generic_arg_list()
1127                    .and_then(|it| {
1128                        self.lower_generic_args(it, &mut Self::impl_trait_error_allocator)
1129                    })
1130                    .map(Box::new);
1131                self.alloc_expr(
1132                    Expr::MethodCall { receiver, method_name, args, generic_args },
1133                    syntax_ptr,
1134                )
1135            }
1136            ast::Expr::MatchExpr(e) => {
1137                let expr = self.collect_expr_opt(e.expr());
1138                let arms = if let Some(match_arm_list) = e.match_arm_list() {
1139                    match_arm_list
1140                        .arms()
1141                        .filter_map(|arm| {
1142                            if self.check_cfg(&arm) {
1143                                Some(MatchArm {
1144                                    pat: self.collect_pat_top(arm.pat()),
1145                                    expr: self.collect_expr_opt(arm.expr()),
1146                                    guard: arm
1147                                        .guard()
1148                                        .map(|guard| self.collect_expr_opt(guard.condition())),
1149                                })
1150                            } else {
1151                                None
1152                            }
1153                        })
1154                        .collect()
1155                } else {
1156                    Box::default()
1157                };
1158                self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
1159            }
1160            ast::Expr::PathExpr(e) => {
1161                let (path, hygiene) = self
1162                    .collect_expr_path(e)
1163                    .map(|(path, hygiene)| (Expr::Path(path), hygiene))
1164                    .unwrap_or((Expr::Missing, HygieneId::ROOT));
1165                let expr_id = self.alloc_expr(path, syntax_ptr);
1166                if !hygiene.is_root() {
1167                    self.store.ident_hygiene.insert(expr_id.into(), hygiene);
1168                }
1169                expr_id
1170            }
1171            ast::Expr::ContinueExpr(e) => {
1172                let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {
1173                    self.store.diagnostics.push(e);
1174                    None
1175                });
1176                self.alloc_expr(Expr::Continue { label }, syntax_ptr)
1177            }
1178            ast::Expr::BreakExpr(e) => {
1179                let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {
1180                    self.store.diagnostics.push(e);
1181                    None
1182                });
1183                let expr = e.expr().map(|e| self.collect_expr(e));
1184                self.alloc_expr(Expr::Break { expr, label }, syntax_ptr)
1185            }
1186            ast::Expr::ParenExpr(e) => {
1187                let inner = self.collect_expr_opt(e.expr());
1188                // make the paren expr point to the inner expression as well for IDE resolution
1189                let src = self.expander.in_file(syntax_ptr);
1190                self.store.expr_map.insert(src, inner.into());
1191                inner
1192            }
1193            ast::Expr::ReturnExpr(e) => {
1194                let expr = e.expr().map(|e| self.collect_expr(e));
1195                self.alloc_expr(Expr::Return { expr }, syntax_ptr)
1196            }
1197            ast::Expr::BecomeExpr(e) => {
1198                let expr =
1199                    e.expr().map(|e| self.collect_expr(e)).unwrap_or_else(|| self.missing_expr());
1200                self.alloc_expr(Expr::Become { expr }, syntax_ptr)
1201            }
1202            ast::Expr::YieldExpr(e) => {
1203                self.is_lowering_coroutine = true;
1204                let expr = e.expr().map(|e| self.collect_expr(e));
1205                self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
1206            }
1207            ast::Expr::YeetExpr(e) => {
1208                let expr = e.expr().map(|e| self.collect_expr(e));
1209                self.alloc_expr(Expr::Yeet { expr }, syntax_ptr)
1210            }
1211            ast::Expr::RecordExpr(e) => {
1212                let path = e
1213                    .path()
1214                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator))
1215                    .map(Box::new);
1216                let record_lit = if let Some(nfl) = e.record_expr_field_list() {
1217                    let fields = nfl
1218                        .fields()
1219                        .filter_map(|field| {
1220                            if !self.check_cfg(&field) {
1221                                return None;
1222                            }
1223
1224                            let name = field.field_name()?.as_name();
1225
1226                            let expr = match field.expr() {
1227                                Some(e) => self.collect_expr(e),
1228                                None => self.missing_expr(),
1229                            };
1230                            let src = self.expander.in_file(AstPtr::new(&field));
1231                            self.store.field_map_back.insert(expr, src);
1232                            Some(RecordLitField { name, expr })
1233                        })
1234                        .collect();
1235                    let spread = nfl.spread().map(|s| self.collect_expr(s));
1236                    Expr::RecordLit { path, fields, spread }
1237                } else {
1238                    Expr::RecordLit { path, fields: Box::default(), spread: None }
1239                };
1240
1241                self.alloc_expr(record_lit, syntax_ptr)
1242            }
1243            ast::Expr::FieldExpr(e) => {
1244                let expr = self.collect_expr_opt(e.expr());
1245                let name = match e.field_access() {
1246                    Some(kind) => kind.as_name(),
1247                    _ => Name::missing(),
1248                };
1249                self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
1250            }
1251            ast::Expr::AwaitExpr(e) => {
1252                let expr = self.collect_expr_opt(e.expr());
1253                if let Awaitable::No(location) = self.is_lowering_awaitable_block() {
1254                    self.store.diagnostics.push(ExpressionStoreDiagnostics::AwaitOutsideOfAsync {
1255                        node: self.expander.in_file(AstPtr::new(&e)),
1256                        location: location.to_string(),
1257                    });
1258                }
1259                self.alloc_expr(Expr::Await { expr }, syntax_ptr)
1260            }
1261            ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e),
1262            ast::Expr::CastExpr(e) => {
1263                let expr = self.collect_expr_opt(e.expr());
1264                let type_ref = self.lower_type_ref_opt_disallow_impl_trait(e.ty());
1265                self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
1266            }
1267            ast::Expr::RefExpr(e) => {
1268                let expr = self.collect_expr_opt(e.expr());
1269                let raw_tok = e.raw_token().is_some();
1270                let mutability = if raw_tok {
1271                    if e.mut_token().is_some() { Mutability::Mut } else { Mutability::Shared }
1272                } else {
1273                    Mutability::from_mutable(e.mut_token().is_some())
1274                };
1275                let rawness = Rawness::from_raw(raw_tok);
1276                self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)
1277            }
1278            ast::Expr::PrefixExpr(e) => {
1279                let expr = self.collect_expr_opt(e.expr());
1280                match e.op_kind() {
1281                    Some(op) => self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr),
1282                    None => self.alloc_expr(Expr::Missing, syntax_ptr),
1283                }
1284            }
1285            ast::Expr::ClosureExpr(e) => self.with_label_rib(RibKind::Closure, |this| {
1286                this.with_binding_owner(|this| {
1287                    let mut args = Vec::new();
1288                    let mut arg_types = Vec::new();
1289                    if let Some(pl) = e.param_list() {
1290                        let num_params = pl.params().count();
1291                        args.reserve_exact(num_params);
1292                        arg_types.reserve_exact(num_params);
1293                        for param in pl.params() {
1294                            let pat = this.collect_pat_top(param.pat());
1295                            let type_ref =
1296                                param.ty().map(|it| this.lower_type_ref_disallow_impl_trait(it));
1297                            args.push(pat);
1298                            arg_types.push(type_ref);
1299                        }
1300                    }
1301                    let ret_type = e
1302                        .ret_type()
1303                        .and_then(|r| r.ty())
1304                        .map(|it| this.lower_type_ref_disallow_impl_trait(it));
1305
1306                    let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);
1307                    let prev_try_block_label = this.current_try_block_label.take();
1308
1309                    let awaitable = if e.async_token().is_some() {
1310                        Awaitable::Yes
1311                    } else {
1312                        Awaitable::No("non-async closure")
1313                    };
1314                    let body = this
1315                        .with_awaitable_block(awaitable, |this| this.collect_expr_opt(e.body()));
1316
1317                    let closure_kind = if this.is_lowering_coroutine {
1318                        let movability = if e.static_token().is_some() {
1319                            Movability::Static
1320                        } else {
1321                            Movability::Movable
1322                        };
1323                        ClosureKind::Coroutine(movability)
1324                    } else if e.async_token().is_some() {
1325                        ClosureKind::Async
1326                    } else {
1327                        ClosureKind::Closure
1328                    };
1329                    let capture_by =
1330                        if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };
1331                    this.is_lowering_coroutine = prev_is_lowering_coroutine;
1332                    this.current_try_block_label = prev_try_block_label;
1333                    this.alloc_expr(
1334                        Expr::Closure {
1335                            args: args.into(),
1336                            arg_types: arg_types.into(),
1337                            ret_type,
1338                            body,
1339                            closure_kind,
1340                            capture_by,
1341                        },
1342                        syntax_ptr,
1343                    )
1344                })
1345            }),
1346            ast::Expr::BinExpr(e) => {
1347                let op = e.op_kind();
1348                if let Some(ast::BinaryOp::Assignment { op: None }) = op {
1349                    let target = self.collect_expr_as_pat_opt(e.lhs());
1350                    let value = self.collect_expr_opt(e.rhs());
1351                    self.alloc_expr(Expr::Assignment { target, value }, syntax_ptr)
1352                } else {
1353                    let lhs = self.collect_expr_opt(e.lhs());
1354                    let rhs = self.collect_expr_opt(e.rhs());
1355                    self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
1356                }
1357            }
1358            ast::Expr::TupleExpr(e) => {
1359                let mut exprs: Vec<_> = e.fields().map(|expr| self.collect_expr(expr)).collect();
1360                // if there is a leading comma, the user is most likely to type out a leading expression
1361                // so we insert a missing expression at the beginning for IDE features
1362                if comma_follows_token(e.l_paren_token()) {
1363                    exprs.insert(0, self.missing_expr());
1364                }
1365
1366                self.alloc_expr(Expr::Tuple { exprs: exprs.into_boxed_slice() }, syntax_ptr)
1367            }
1368            ast::Expr::ArrayExpr(e) => {
1369                let kind = e.kind();
1370
1371                match kind {
1372                    ArrayExprKind::ElementList(e) => {
1373                        let elements = e.map(|expr| self.collect_expr(expr)).collect();
1374                        self.alloc_expr(Expr::Array(Array::ElementList { elements }), syntax_ptr)
1375                    }
1376                    ArrayExprKind::Repeat { initializer, repeat } => {
1377                        let initializer = self.collect_expr_opt(initializer);
1378                        let repeat = self.with_label_rib(RibKind::Constant, |this| {
1379                            if let Some(repeat) = repeat {
1380                                this.with_binding_owner(|this| this.collect_expr(repeat))
1381                            } else {
1382                                this.missing_expr()
1383                            }
1384                        });
1385                        self.alloc_expr(
1386                            Expr::Array(Array::Repeat { initializer, repeat }),
1387                            syntax_ptr,
1388                        )
1389                    }
1390                }
1391            }
1392
1393            ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr),
1394            ast::Expr::IndexExpr(e) => {
1395                let base = self.collect_expr_opt(e.base());
1396                let index = self.collect_expr_opt(e.index());
1397                self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
1398            }
1399            ast::Expr::RangeExpr(e) => {
1400                let lhs = e.start().map(|lhs| self.collect_expr(lhs));
1401                let rhs = e.end().map(|rhs| self.collect_expr(rhs));
1402                match e.op_kind() {
1403                    Some(range_type) => {
1404                        self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)
1405                    }
1406                    None => self.alloc_expr(Expr::Missing, syntax_ptr),
1407                }
1408            }
1409            ast::Expr::MacroExpr(e) => {
1410                let e = e.macro_call()?;
1411                let macro_ptr = AstPtr::new(&e);
1412                let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
1413                    expansion.map(|it| this.collect_expr(it))
1414                });
1415                match id {
1416                    Some(id) => {
1417                        // Make the macro-call point to its expanded expression so we can query
1418                        // semantics on syntax pointers to the macro
1419                        let src = self.expander.in_file(syntax_ptr);
1420                        self.store.expr_map.insert(src, id.into());
1421                        id
1422                    }
1423                    None => self.alloc_expr(Expr::Missing, syntax_ptr),
1424                }
1425            }
1426            ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
1427            ast::Expr::AsmExpr(e) => self.lower_inline_asm(e, syntax_ptr),
1428            ast::Expr::OffsetOfExpr(e) => {
1429                let container = self.lower_type_ref_opt_disallow_impl_trait(e.ty());
1430                let fields = e.fields().map(|it| it.as_name()).collect();
1431                self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
1432            }
1433            ast::Expr::FormatArgsExpr(f) => self.collect_format_args(f, syntax_ptr),
1434        })
1435    }
1436
1437    fn collect_expr_path(&mut self, e: ast::PathExpr) -> Option<(Path, HygieneId)> {
1438        e.path().and_then(|path| {
1439            let path = self.lower_path(path, &mut Self::impl_trait_error_allocator)?;
1440            // Need to enable `mod_path.len() < 1` for `self`.
1441            let may_be_variable = matches!(&path, Path::BarePath(mod_path) if mod_path.len() <= 1);
1442            let hygiene = if may_be_variable {
1443                self.hygiene_id_for(e.syntax().text_range())
1444            } else {
1445                HygieneId::ROOT
1446            };
1447            Some((path, hygiene))
1448        })
1449    }
1450
1451    fn collect_expr_as_pat_opt(&mut self, expr: Option<ast::Expr>) -> PatId {
1452        match expr {
1453            Some(expr) => self.collect_expr_as_pat(expr),
1454            _ => self.missing_pat(),
1455        }
1456    }
1457
1458    fn collect_expr_as_pat(&mut self, expr: ast::Expr) -> PatId {
1459        self.maybe_collect_expr_as_pat(&expr).unwrap_or_else(|| {
1460            let src = self.expander.in_file(AstPtr::new(&expr).wrap_left());
1461            let expr = self.collect_expr(expr);
1462            // Do not use `alloc_pat_from_expr()` here, it will override the entry in `expr_map`.
1463            let id = self.store.pats.alloc(Pat::Expr(expr));
1464            self.store.pat_map_back.insert(id, src);
1465            id
1466        })
1467    }
1468
1469    fn maybe_collect_expr_as_pat(&mut self, expr: &ast::Expr) -> Option<PatId> {
1470        if !self.check_cfg(expr) {
1471            return None;
1472        }
1473        let syntax_ptr = AstPtr::new(expr);
1474
1475        let result = match expr {
1476            ast::Expr::UnderscoreExpr(_) => self.alloc_pat_from_expr(Pat::Wild, syntax_ptr),
1477            ast::Expr::ParenExpr(e) => {
1478                // We special-case `(..)` for consistency with patterns.
1479                if let Some(ast::Expr::RangeExpr(range)) = e.expr()
1480                    && range.is_range_full()
1481                {
1482                    return Some(self.alloc_pat_from_expr(
1483                        Pat::Tuple { args: Box::default(), ellipsis: Some(0) },
1484                        syntax_ptr,
1485                    ));
1486                }
1487                return e.expr().and_then(|expr| self.maybe_collect_expr_as_pat(&expr));
1488            }
1489            ast::Expr::TupleExpr(e) => {
1490                let (ellipsis, args) = collect_tuple(self, e.fields());
1491                self.alloc_pat_from_expr(Pat::Tuple { args, ellipsis }, syntax_ptr)
1492            }
1493            ast::Expr::ArrayExpr(e) => {
1494                if e.semicolon_token().is_some() {
1495                    return None;
1496                }
1497
1498                let mut elements = e.exprs();
1499                let prefix = elements
1500                    .by_ref()
1501                    .map_while(|elem| collect_possibly_rest(self, elem).left())
1502                    .collect();
1503                let suffix = elements.map(|elem| self.collect_expr_as_pat(elem)).collect();
1504                self.alloc_pat_from_expr(Pat::Slice { prefix, slice: None, suffix }, syntax_ptr)
1505            }
1506            ast::Expr::CallExpr(e) => {
1507                let path = collect_path(self, e.expr()?)?;
1508                let path = path
1509                    .path()
1510                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator))
1511                    .map(Box::new);
1512                let (ellipsis, args) = collect_tuple(self, e.arg_list()?.args());
1513                self.alloc_pat_from_expr(Pat::TupleStruct { path, args, ellipsis }, syntax_ptr)
1514            }
1515            ast::Expr::PathExpr(e) => {
1516                let (path, hygiene) = self
1517                    .collect_expr_path(e.clone())
1518                    .map(|(path, hygiene)| (Pat::Path(path), hygiene))
1519                    .unwrap_or((Pat::Missing, HygieneId::ROOT));
1520                let pat_id = self.alloc_pat_from_expr(path, syntax_ptr);
1521                if !hygiene.is_root() {
1522                    self.store.ident_hygiene.insert(pat_id.into(), hygiene);
1523                }
1524                pat_id
1525            }
1526            ast::Expr::MacroExpr(e) => {
1527                let e = e.macro_call()?;
1528                let macro_ptr = AstPtr::new(&e);
1529                let src = self.expander.in_file(AstPtr::new(expr));
1530                let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
1531                    this.collect_expr_as_pat_opt(expansion)
1532                });
1533                self.store.expr_map.insert(src, id.into());
1534                id
1535            }
1536            ast::Expr::RecordExpr(e) => {
1537                let path = e
1538                    .path()
1539                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator))
1540                    .map(Box::new);
1541                let record_field_list = e.record_expr_field_list()?;
1542                let ellipsis = record_field_list.dotdot_token().is_some();
1543                // FIXME: Report an error here if `record_field_list.spread().is_some()`.
1544                let args = record_field_list
1545                    .fields()
1546                    .filter_map(|f| {
1547                        if !self.check_cfg(&f) {
1548                            return None;
1549                        }
1550                        let field_expr = f.expr()?;
1551                        let pat = self.collect_expr_as_pat(field_expr);
1552                        let name = f.field_name()?.as_name();
1553                        let src = self.expander.in_file(AstPtr::new(&f).wrap_left());
1554                        self.store.pat_field_map_back.insert(pat, src);
1555                        Some(RecordFieldPat { name, pat })
1556                    })
1557                    .collect();
1558                self.alloc_pat_from_expr(Pat::Record { path, args, ellipsis }, syntax_ptr)
1559            }
1560            _ => return None,
1561        };
1562        return Some(result);
1563
1564        fn collect_path(this: &mut ExprCollector<'_>, expr: ast::Expr) -> Option<ast::PathExpr> {
1565            match expr {
1566                ast::Expr::PathExpr(e) => Some(e),
1567                ast::Expr::MacroExpr(mac) => {
1568                    let call = mac.macro_call()?;
1569                    {
1570                        let macro_ptr = AstPtr::new(&call);
1571                        this.collect_macro_call(call, macro_ptr, true, |this, expanded_path| {
1572                            collect_path(this, expanded_path?)
1573                        })
1574                    }
1575                }
1576                _ => None,
1577            }
1578        }
1579
1580        fn collect_possibly_rest(
1581            this: &mut ExprCollector<'_>,
1582            expr: ast::Expr,
1583        ) -> Either<PatId, ()> {
1584            match &expr {
1585                ast::Expr::RangeExpr(e) if e.is_range_full() => Either::Right(()),
1586                ast::Expr::MacroExpr(mac) => match mac.macro_call() {
1587                    Some(call) => {
1588                        let macro_ptr = AstPtr::new(&call);
1589                        let pat = this.collect_macro_call(
1590                            call,
1591                            macro_ptr,
1592                            true,
1593                            |this, expanded_expr| match expanded_expr {
1594                                Some(expanded_pat) => collect_possibly_rest(this, expanded_pat),
1595                                None => Either::Left(this.missing_pat()),
1596                            },
1597                        );
1598                        if let Either::Left(pat) = pat {
1599                            let src = this.expander.in_file(AstPtr::new(&expr).wrap_left());
1600                            this.store.pat_map_back.insert(pat, src);
1601                        }
1602                        pat
1603                    }
1604                    None => {
1605                        let ptr = AstPtr::new(&expr);
1606                        Either::Left(this.alloc_pat_from_expr(Pat::Missing, ptr))
1607                    }
1608                },
1609                _ => Either::Left(this.collect_expr_as_pat(expr)),
1610            }
1611        }
1612
1613        fn collect_tuple(
1614            this: &mut ExprCollector<'_>,
1615            fields: ast::AstChildren<ast::Expr>,
1616        ) -> (Option<u32>, Box<[la_arena::Idx<Pat>]>) {
1617            let mut ellipsis = None;
1618            let args = fields
1619                .enumerate()
1620                .filter_map(|(idx, elem)| {
1621                    match collect_possibly_rest(this, elem) {
1622                        Either::Left(pat) => Some(pat),
1623                        Either::Right(()) => {
1624                            if ellipsis.is_none() {
1625                                ellipsis = Some(idx as u32);
1626                            }
1627                            // FIXME: Report an error here otherwise.
1628                            None
1629                        }
1630                    }
1631                })
1632                .collect();
1633            (ellipsis, args)
1634        }
1635    }
1636
1637    fn with_binding_owner(&mut self, create_expr: impl FnOnce(&mut Self) -> ExprId) -> ExprId {
1638        let prev_unowned_bindings_len = self.unowned_bindings.len();
1639        let expr_id = create_expr(self);
1640        for binding in self.unowned_bindings.drain(prev_unowned_bindings_len..) {
1641            self.store.binding_owners.insert(binding, expr_id);
1642        }
1643        expr_id
1644    }
1645
1646    /// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`,
1647    /// `try { <stmts>; }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(()) }`
1648    /// and save the `<new_label>` to use it as a break target for desugaring of the `?` operator.
1649    fn desugar_try_block(&mut self, e: BlockExpr) -> ExprId {
1650        let try_from_output = self.lang_path(self.lang_items().TryTraitFromOutput);
1651        let label = self.generate_new_name();
1652        let label = self.alloc_label_desugared(Label { name: label });
1653        let old_label = self.current_try_block_label.replace(label);
1654
1655        let ptr = AstPtr::new(&e).upcast();
1656        let (btail, expr_id) = self.with_labeled_rib(label, HygieneId::ROOT, |this| {
1657            let mut btail = None;
1658            let block = this.collect_block_(e, |id, statements, tail| {
1659                btail = tail;
1660                Expr::Block { id, statements, tail, label: Some(label) }
1661            });
1662            (btail, block)
1663        });
1664
1665        let callee = self
1666            .alloc_expr_desugared_with_ptr(try_from_output.map_or(Expr::Missing, Expr::Path), ptr);
1667        let next_tail = match btail {
1668            Some(tail) => self
1669                .alloc_expr_desugared_with_ptr(Expr::Call { callee, args: Box::new([tail]) }, ptr),
1670            None => {
1671                let unit =
1672                    self.alloc_expr_desugared_with_ptr(Expr::Tuple { exprs: Box::new([]) }, ptr);
1673                self.alloc_expr_desugared_with_ptr(
1674                    Expr::Call { callee, args: Box::new([unit]) },
1675                    ptr,
1676                )
1677            }
1678        };
1679        let Expr::Block { tail, .. } = &mut self.store.exprs[expr_id] else {
1680            unreachable!("block was lowered to non-block");
1681        };
1682        *tail = Some(next_tail);
1683        self.current_try_block_label = old_label;
1684        expr_id
1685    }
1686
1687    /// Desugar `ast::WhileExpr` from: `[opt_ident]: while <cond> <body>` into:
1688    /// ```ignore (pseudo-rust)
1689    /// [opt_ident]: loop {
1690    ///   if <cond> {
1691    ///     <body>
1692    ///   }
1693    ///   else {
1694    ///     break;
1695    ///   }
1696    /// }
1697    /// ```
1698    /// FIXME: Rustc wraps the condition in a construct equivalent to `{ let _t = <cond>; _t }`
1699    /// to preserve drop semantics. We should probably do the same in future.
1700    fn collect_while_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::WhileExpr) -> ExprId {
1701        let label = e.label().map(|label| {
1702            (self.hygiene_id_for(label.syntax().text_range()), self.collect_label(label))
1703        });
1704        let body = self.collect_labelled_block_opt(label, e.loop_body());
1705
1706        // Labels can also be used in the condition expression, like this:
1707        // ```
1708        // fn main() {
1709        //     let mut optional = Some(0);
1710        //     'my_label: while let Some(a) = match optional {
1711        //         None => break 'my_label,
1712        //         Some(val) => Some(val),
1713        //     } {
1714        //         println!("{}", a);
1715        //         optional = None;
1716        //     }
1717        // }
1718        // ```
1719        let condition = match label {
1720            Some((label_hygiene, label)) => self.with_labeled_rib(label, label_hygiene, |this| {
1721                this.collect_expr_opt(e.condition())
1722            }),
1723            None => self.collect_expr_opt(e.condition()),
1724        };
1725
1726        let break_expr = self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr);
1727        let if_expr = self.alloc_expr(
1728            Expr::If { condition, then_branch: body, else_branch: Some(break_expr) },
1729            syntax_ptr,
1730        );
1731        self.alloc_expr(Expr::Loop { body: if_expr, label: label.map(|it| it.1) }, syntax_ptr)
1732    }
1733
1734    /// Desugar `ast::ForExpr` from: `[opt_ident]: for <pat> in <head> <body>` into:
1735    /// ```ignore (pseudo-rust)
1736    /// match IntoIterator::into_iter(<head>) {
1737    ///     mut iter => {
1738    ///         [opt_ident]: loop {
1739    ///             match Iterator::next(&mut iter) {
1740    ///                 None => break,
1741    ///                 Some(<pat>) => <body>,
1742    ///             };
1743    ///         }
1744    ///     }
1745    /// }
1746    /// ```
1747    fn collect_for_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::ForExpr) -> ExprId {
1748        let lang_items = self.lang_items();
1749        let into_iter_fn = self.lang_path(lang_items.IntoIterIntoIter);
1750        let iter_next_fn = self.lang_path(lang_items.IteratorNext);
1751        let option_some = self.lang_path(lang_items.OptionSome);
1752        let option_none = self.lang_path(lang_items.OptionNone);
1753        let head = self.collect_expr_opt(e.iterable());
1754        let into_iter_fn_expr =
1755            self.alloc_expr(into_iter_fn.map_or(Expr::Missing, Expr::Path), syntax_ptr);
1756        let iterator = self.alloc_expr(
1757            Expr::Call { callee: into_iter_fn_expr, args: Box::new([head]) },
1758            syntax_ptr,
1759        );
1760        let none_arm = MatchArm {
1761            pat: self.alloc_pat_desugared(option_none.map_or(Pat::Missing, Pat::Path)),
1762            guard: None,
1763            expr: self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr),
1764        };
1765        let some_pat = Pat::TupleStruct {
1766            path: option_some.map(Box::new),
1767            args: Box::new([self.collect_pat_top(e.pat())]),
1768            ellipsis: None,
1769        };
1770        let label = e.label().map(|label| {
1771            (self.hygiene_id_for(label.syntax().text_range()), self.collect_label(label))
1772        });
1773        let some_arm = MatchArm {
1774            pat: self.alloc_pat_desugared(some_pat),
1775            guard: None,
1776            expr: self.with_opt_labeled_rib(label, |this| {
1777                this.collect_expr_opt(e.loop_body().map(|it| it.into()))
1778            }),
1779        };
1780        let iter_name = self.generate_new_name();
1781        let iter_expr = self.alloc_expr(Expr::Path(Path::from(iter_name.clone())), syntax_ptr);
1782        let iter_expr_mut = self.alloc_expr(
1783            Expr::Ref { expr: iter_expr, rawness: Rawness::Ref, mutability: Mutability::Mut },
1784            syntax_ptr,
1785        );
1786        let iter_next_fn_expr =
1787            self.alloc_expr(iter_next_fn.map_or(Expr::Missing, Expr::Path), syntax_ptr);
1788        let iter_next_expr = self.alloc_expr(
1789            Expr::Call { callee: iter_next_fn_expr, args: Box::new([iter_expr_mut]) },
1790            syntax_ptr,
1791        );
1792        let loop_inner = self.alloc_expr(
1793            Expr::Match { expr: iter_next_expr, arms: Box::new([none_arm, some_arm]) },
1794            syntax_ptr,
1795        );
1796        let loop_inner = self.alloc_expr(
1797            Expr::Block {
1798                id: None,
1799                statements: Box::default(),
1800                tail: Some(loop_inner),
1801                label: None,
1802            },
1803            syntax_ptr,
1804        );
1805        let loop_outer = self
1806            .alloc_expr(Expr::Loop { body: loop_inner, label: label.map(|it| it.1) }, syntax_ptr);
1807        let iter_binding =
1808            self.alloc_binding(iter_name, BindingAnnotation::Mutable, HygieneId::ROOT);
1809        let iter_pat = self.alloc_pat_desugared(Pat::Bind { id: iter_binding, subpat: None });
1810        self.add_definition_to_binding(iter_binding, iter_pat);
1811        self.alloc_expr(
1812            Expr::Match {
1813                expr: iterator,
1814                arms: Box::new([MatchArm { pat: iter_pat, guard: None, expr: loop_outer }]),
1815            },
1816            syntax_ptr,
1817        )
1818    }
1819
1820    /// Desugar `ast::TryExpr` from: `<expr>?` into:
1821    /// ```ignore (pseudo-rust)
1822    /// match Try::branch(<expr>) {
1823    ///     ControlFlow::Continue(val) => val,
1824    ///     ControlFlow::Break(residual) =>
1825    ///         // If there is an enclosing `try {...}`:
1826    ///         break 'catch_target Try::from_residual(residual),
1827    ///         // Otherwise:
1828    ///         return Try::from_residual(residual),
1829    /// }
1830    /// ```
1831    fn collect_try_operator(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::TryExpr) -> ExprId {
1832        let lang_items = self.lang_items();
1833        let try_branch = self.lang_path(lang_items.TryTraitBranch);
1834        let cf_continue = self.lang_path(lang_items.ControlFlowContinue);
1835        let cf_break = self.lang_path(lang_items.ControlFlowBreak);
1836        let try_from_residual = self.lang_path(lang_items.TryTraitFromResidual);
1837        let operand = self.collect_expr_opt(e.expr());
1838        let try_branch = self.alloc_expr(try_branch.map_or(Expr::Missing, Expr::Path), syntax_ptr);
1839        let expr = self
1840            .alloc_expr(Expr::Call { callee: try_branch, args: Box::new([operand]) }, syntax_ptr);
1841        let continue_name = self.generate_new_name();
1842        let continue_binding = self.alloc_binding(
1843            continue_name.clone(),
1844            BindingAnnotation::Unannotated,
1845            HygieneId::ROOT,
1846        );
1847        let continue_bpat =
1848            self.alloc_pat_desugared(Pat::Bind { id: continue_binding, subpat: None });
1849        self.add_definition_to_binding(continue_binding, continue_bpat);
1850        let continue_arm = MatchArm {
1851            pat: self.alloc_pat_desugared(Pat::TupleStruct {
1852                path: cf_continue.map(Box::new),
1853                args: Box::new([continue_bpat]),
1854                ellipsis: None,
1855            }),
1856            guard: None,
1857            expr: self.alloc_expr(Expr::Path(Path::from(continue_name)), syntax_ptr),
1858        };
1859        let break_name = self.generate_new_name();
1860        let break_binding =
1861            self.alloc_binding(break_name.clone(), BindingAnnotation::Unannotated, HygieneId::ROOT);
1862        let break_bpat = self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None });
1863        self.add_definition_to_binding(break_binding, break_bpat);
1864        let break_arm = MatchArm {
1865            pat: self.alloc_pat_desugared(Pat::TupleStruct {
1866                path: cf_break.map(Box::new),
1867                args: Box::new([break_bpat]),
1868                ellipsis: None,
1869            }),
1870            guard: None,
1871            expr: {
1872                let it = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr);
1873                let callee = self
1874                    .alloc_expr(try_from_residual.map_or(Expr::Missing, Expr::Path), syntax_ptr);
1875                let result =
1876                    self.alloc_expr(Expr::Call { callee, args: Box::new([it]) }, syntax_ptr);
1877                self.alloc_expr(
1878                    match self.current_try_block_label {
1879                        Some(label) => Expr::Break { expr: Some(result), label: Some(label) },
1880                        None => Expr::Return { expr: Some(result) },
1881                    },
1882                    syntax_ptr,
1883                )
1884            },
1885        };
1886        let arms = Box::new([continue_arm, break_arm]);
1887        self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
1888    }
1889
1890    fn collect_macro_call<T, U>(
1891        &mut self,
1892        mcall: ast::MacroCall,
1893        syntax_ptr: AstPtr<ast::MacroCall>,
1894        record_diagnostics: bool,
1895        collector: impl FnOnce(&mut Self, Option<T>) -> U,
1896    ) -> U
1897    where
1898        T: ast::AstNode,
1899    {
1900        let macro_call_ptr = self.expander.in_file(syntax_ptr);
1901
1902        let block_call = self.def_map.modules[self.module].scope.macro_invoc(
1903            self.expander.in_file(self.expander.ast_id_map().ast_id_for_ptr(syntax_ptr)),
1904        );
1905        let res = match block_call {
1906            // fast path, macro call is in a block module
1907            Some(call) => Ok(self.expander.enter_expand_id(self.db, call)),
1908            None => {
1909                let resolver = |path: &_| {
1910                    self.def_map
1911                        .resolve_path(
1912                            self.local_def_map,
1913                            self.db,
1914                            self.module,
1915                            path,
1916                            crate::item_scope::BuiltinShadowMode::Other,
1917                            Some(MacroSubNs::Bang),
1918                        )
1919                        .0
1920                        .take_macros()
1921                };
1922                self.expander.enter_expand(
1923                    self.db,
1924                    mcall,
1925                    self.krate,
1926                    resolver,
1927                    &mut |ptr, call| {
1928                        _ = self.store.expansions.insert(ptr.map(|(it, _)| it), call);
1929                    },
1930                )
1931            }
1932        };
1933
1934        let res = match res {
1935            Ok(res) => res,
1936            Err(UnresolvedMacro { path }) => {
1937                if record_diagnostics {
1938                    self.store.diagnostics.push(ExpressionStoreDiagnostics::UnresolvedMacroCall {
1939                        node: self.expander.in_file(syntax_ptr),
1940                        path,
1941                    });
1942                }
1943                return collector(self, None);
1944            }
1945        };
1946        // No need to push macro and parsing errors as they'll be recreated from `macro_calls()`.
1947
1948        match res.value {
1949            Some((mark, expansion)) => {
1950                // Keep collecting even with expansion errors so we can provide completions and
1951                // other services in incomplete macro expressions.
1952                if let Some(macro_file) = self.expander.current_file_id().macro_file() {
1953                    self.store.expansions.insert(macro_call_ptr, macro_file);
1954                }
1955
1956                let id = collector(self, expansion.map(|it| it.tree()));
1957                self.expander.exit(mark);
1958                id
1959            }
1960            None => collector(self, None),
1961        }
1962    }
1963
1964    fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
1965        match expr {
1966            Some(expr) => self.collect_expr(expr),
1967            None => self.missing_expr(),
1968        }
1969    }
1970
1971    fn collect_macro_as_stmt(
1972        &mut self,
1973        statements: &mut Vec<Statement>,
1974        mac: ast::MacroExpr,
1975    ) -> Option<ExprId> {
1976        let mac_call = mac.macro_call()?;
1977        let syntax_ptr = AstPtr::new(&ast::Expr::from(mac));
1978        let macro_ptr = AstPtr::new(&mac_call);
1979        let expansion = self.collect_macro_call(
1980            mac_call,
1981            macro_ptr,
1982            false,
1983            |this, expansion: Option<ast::MacroStmts>| match expansion {
1984                Some(expansion) => {
1985                    expansion.statements().for_each(|stmt| this.collect_stmt(statements, stmt));
1986                    expansion.expr().and_then(|expr| match expr {
1987                        ast::Expr::MacroExpr(mac) => this.collect_macro_as_stmt(statements, mac),
1988                        expr => Some(this.collect_expr(expr)),
1989                    })
1990                }
1991                None => None,
1992            },
1993        );
1994        expansion.inspect(|&tail| {
1995            // Make the macro-call point to its expanded expression so we can query
1996            // semantics on syntax pointers to the macro
1997            let src = self.expander.in_file(syntax_ptr);
1998            self.store.expr_map.insert(src, tail.into());
1999        })
2000    }
2001
2002    fn collect_stmt(&mut self, statements: &mut Vec<Statement>, s: ast::Stmt) {
2003        match s {
2004            ast::Stmt::LetStmt(stmt) => {
2005                if !self.check_cfg(&stmt) {
2006                    return;
2007                }
2008                let pat = self.collect_pat_top(stmt.pat());
2009                let type_ref = stmt.ty().map(|it| self.lower_type_ref_disallow_impl_trait(it));
2010                let initializer = stmt.initializer().map(|e| self.collect_expr(e));
2011                let else_branch = stmt
2012                    .let_else()
2013                    .and_then(|let_else| let_else.block_expr())
2014                    .map(|block| self.collect_block(block));
2015                statements.push(Statement::Let { pat, type_ref, initializer, else_branch });
2016            }
2017            ast::Stmt::ExprStmt(stmt) => {
2018                let expr = stmt.expr();
2019                match &expr {
2020                    Some(expr) if !self.check_cfg(expr) => return,
2021                    _ => (),
2022                }
2023                let has_semi = stmt.semicolon_token().is_some();
2024                // Note that macro could be expanded to multiple statements
2025                if let Some(ast::Expr::MacroExpr(mac)) = expr {
2026                    if let Some(expr) = self.collect_macro_as_stmt(statements, mac) {
2027                        statements.push(Statement::Expr { expr, has_semi })
2028                    }
2029                } else {
2030                    let expr = self.collect_expr_opt(expr);
2031                    statements.push(Statement::Expr { expr, has_semi });
2032                }
2033            }
2034            ast::Stmt::Item(ast::Item::MacroDef(macro_)) => {
2035                if !self.check_cfg(&macro_) {
2036                    return;
2037                }
2038                let Some(name) = macro_.name() else {
2039                    statements.push(Statement::Item(Item::Other));
2040                    return;
2041                };
2042                let name = name.as_name();
2043                let macro_id =
2044                    self.def_map.modules[self.def_map.root].scope.get(&name).take_macros();
2045                self.collect_macro_def(statements, macro_id);
2046            }
2047            ast::Stmt::Item(ast::Item::MacroRules(macro_)) => {
2048                if !self.check_cfg(&macro_) {
2049                    return;
2050                }
2051                let Some(name) = macro_.name() else {
2052                    statements.push(Statement::Item(Item::Other));
2053                    return;
2054                };
2055                let name = name.as_name();
2056                let macro_defs_count =
2057                    self.current_block_legacy_macro_defs_count.entry(name.clone()).or_insert(0);
2058                let macro_id = self.def_map.modules[self.def_map.root]
2059                    .scope
2060                    .get_legacy_macro(&name)
2061                    .and_then(|it| it.get(*macro_defs_count))
2062                    .copied();
2063                *macro_defs_count += 1;
2064                self.collect_macro_def(statements, macro_id);
2065            }
2066            ast::Stmt::Item(_item) => statements.push(Statement::Item(Item::Other)),
2067        }
2068    }
2069
2070    fn collect_macro_def(&mut self, statements: &mut Vec<Statement>, macro_id: Option<MacroId>) {
2071        let Some(macro_id) = macro_id else {
2072            never!("def map should have macro definition, but it doesn't");
2073            statements.push(Statement::Item(Item::Other));
2074            return;
2075        };
2076        let macro_id = self.db.macro_def(macro_id);
2077        statements.push(Statement::Item(Item::MacroDef(Box::new(macro_id))));
2078        self.label_ribs.push(LabelRib::new(RibKind::MacroDef(Box::new(macro_id))));
2079    }
2080
2081    fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
2082        self.collect_block_(block, |id, statements, tail| Expr::Block {
2083            id,
2084            statements,
2085            tail,
2086            label: None,
2087        })
2088    }
2089
2090    fn collect_block_(
2091        &mut self,
2092        block: ast::BlockExpr,
2093        mk_block: impl FnOnce(Option<BlockId>, Box<[Statement]>, Option<ExprId>) -> Expr,
2094    ) -> ExprId {
2095        let block_id = self.expander.ast_id_map().ast_id_for_block(&block).map(|file_local_id| {
2096            let ast_id = self.expander.in_file(file_local_id);
2097            self.db.intern_block(BlockLoc { ast_id, module: self.module })
2098        });
2099
2100        let (module, def_map) =
2101            match block_id.map(|block_id| (block_def_map(self.db, block_id), block_id)) {
2102                Some((def_map, block_id)) => {
2103                    self.store.block_scopes.push(block_id);
2104                    (def_map.root_module_id(), def_map)
2105                }
2106                None => (self.module, self.def_map),
2107            };
2108        let prev_def_map = mem::replace(&mut self.def_map, def_map);
2109        let prev_local_module = mem::replace(&mut self.module, module);
2110        let prev_legacy_macros_count = mem::take(&mut self.current_block_legacy_macro_defs_count);
2111
2112        let mut statements = Vec::new();
2113        block.statements().for_each(|s| self.collect_stmt(&mut statements, s));
2114        let tail = block.tail_expr().and_then(|e| match e {
2115            ast::Expr::MacroExpr(mac) => self.collect_macro_as_stmt(&mut statements, mac),
2116            expr => self.maybe_collect_expr(expr),
2117        });
2118        let tail = tail.or_else(|| {
2119            let stmt = statements.pop()?;
2120            if let Statement::Expr { expr, has_semi: false } = stmt {
2121                return Some(expr);
2122            }
2123            statements.push(stmt);
2124            None
2125        });
2126
2127        let syntax_node_ptr = AstPtr::new(&block.into());
2128        let expr_id = self
2129            .alloc_expr(mk_block(block_id, statements.into_boxed_slice(), tail), syntax_node_ptr);
2130
2131        self.def_map = prev_def_map;
2132        self.module = prev_local_module;
2133        self.current_block_legacy_macro_defs_count = prev_legacy_macros_count;
2134        expr_id
2135    }
2136
2137    fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
2138        match expr {
2139            Some(block) => self.collect_block(block),
2140            None => self.missing_expr(),
2141        }
2142    }
2143
2144    fn collect_labelled_block_opt(
2145        &mut self,
2146        label: Option<(HygieneId, LabelId)>,
2147        expr: Option<ast::BlockExpr>,
2148    ) -> ExprId {
2149        match label {
2150            Some((hygiene, label)) => {
2151                self.with_labeled_rib(label, hygiene, |this| this.collect_block_opt(expr))
2152            }
2153            None => self.collect_block_opt(expr),
2154        }
2155    }
2156
2157    // region: patterns
2158
2159    fn collect_pat_top(&mut self, pat: Option<ast::Pat>) -> PatId {
2160        match pat {
2161            Some(pat) => self.collect_pat(pat, &mut BindingList::default()),
2162            None => self.missing_pat(),
2163        }
2164    }
2165
2166    fn collect_pat(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatId {
2167        let pattern = match &pat {
2168            ast::Pat::IdentPat(bp) => {
2169                let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
2170                let hygiene = bp
2171                    .name()
2172                    .map(|name| self.hygiene_id_for(name.syntax().text_range()))
2173                    .unwrap_or(HygieneId::ROOT);
2174
2175                let annotation =
2176                    BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
2177                let subpat = bp.pat().map(|subpat| self.collect_pat(subpat, binding_list));
2178
2179                let is_simple_ident_pat =
2180                    annotation == BindingAnnotation::Unannotated && subpat.is_none();
2181                let (binding, pattern) = if is_simple_ident_pat {
2182                    // This could also be a single-segment path pattern. To
2183                    // decide that, we need to try resolving the name.
2184                    let (resolved, _) = self.def_map.resolve_path(
2185                        self.local_def_map,
2186                        self.db,
2187                        self.module,
2188                        &name.clone().into(),
2189                        BuiltinShadowMode::Other,
2190                        None,
2191                    );
2192                    // Funnily enough, record structs/variants *can* be shadowed
2193                    // by pattern bindings (but unit or tuple structs/variants
2194                    // can't).
2195                    match resolved.take_values() {
2196                        Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())),
2197                        Some(ModuleDefId::EnumVariantId(variant))
2198                        // FIXME: This can cause a cycle if the user is writing invalid code
2199                            if variant.fields(self.db).shape != FieldsShape::Record =>
2200                        {
2201                            (None, Pat::Path(name.into()))
2202                        }
2203                        Some(ModuleDefId::AdtId(AdtId::StructId(s)))
2204                        // FIXME: This can cause a cycle if the user is writing invalid code
2205                            if self.db.struct_signature(s).shape != FieldsShape::Record =>
2206                        {
2207                            (None, Pat::Path(name.into()))
2208                        }
2209                        // shadowing statics is an error as well, so we just ignore that case here
2210                        _ => {
2211                            let id = binding_list.find(self, name, hygiene, annotation);
2212                            (Some(id), Pat::Bind { id, subpat })
2213                        }
2214                    }
2215                } else {
2216                    let id = binding_list.find(self, name, hygiene, annotation);
2217                    (Some(id), Pat::Bind { id, subpat })
2218                };
2219
2220                let ptr = AstPtr::new(&pat);
2221                let pat = self.alloc_pat(pattern, ptr);
2222                if let Some(binding_id) = binding {
2223                    self.add_definition_to_binding(binding_id, pat);
2224                }
2225                return pat;
2226            }
2227            ast::Pat::TupleStructPat(p) => {
2228                let path = p
2229                    .path()
2230                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator))
2231                    .map(Box::new);
2232                let (args, ellipsis) = self.collect_tuple_pat(
2233                    p.fields(),
2234                    comma_follows_token(p.l_paren_token()),
2235                    binding_list,
2236                );
2237                Pat::TupleStruct { path, args, ellipsis }
2238            }
2239            ast::Pat::RefPat(p) => {
2240                let pat = self.collect_pat_opt(p.pat(), binding_list);
2241                let mutability = Mutability::from_mutable(p.mut_token().is_some());
2242                Pat::Ref { pat, mutability }
2243            }
2244            ast::Pat::PathPat(p) => {
2245                let path = p
2246                    .path()
2247                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator));
2248                path.map(Pat::Path).unwrap_or(Pat::Missing)
2249            }
2250            ast::Pat::OrPat(p) => 'b: {
2251                let prev_is_used = mem::take(&mut binding_list.is_used);
2252                let prev_reject_new = mem::take(&mut binding_list.reject_new);
2253                let mut pats = Vec::with_capacity(p.pats().count());
2254                let mut it = p.pats();
2255                let Some(first) = it.next() else {
2256                    break 'b Pat::Or(Box::new([]));
2257                };
2258                pats.push(self.collect_pat(first, binding_list));
2259                binding_list.reject_new = true;
2260                for rest in it {
2261                    for (_, it) in binding_list.is_used.iter_mut() {
2262                        *it = false;
2263                    }
2264                    pats.push(self.collect_pat(rest, binding_list));
2265                    for (&id, &is_used) in binding_list.is_used.iter() {
2266                        if !is_used {
2267                            self.store.bindings[id].problems =
2268                                Some(BindingProblems::NotBoundAcrossAll);
2269                        }
2270                    }
2271                }
2272                binding_list.reject_new = prev_reject_new;
2273                let current_is_used = mem::replace(&mut binding_list.is_used, prev_is_used);
2274                for (id, _) in current_is_used.into_iter() {
2275                    binding_list.check_is_used(self, id);
2276                }
2277                if let &[pat] = &*pats {
2278                    // Leading pipe without real OR pattern. Leaving an one-item OR pattern may confuse later stages.
2279                    return pat;
2280                }
2281                Pat::Or(pats.into())
2282            }
2283            ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat(), binding_list),
2284            ast::Pat::TuplePat(p) => {
2285                let (args, ellipsis) = self.collect_tuple_pat(
2286                    p.fields(),
2287                    comma_follows_token(p.l_paren_token()),
2288                    binding_list,
2289                );
2290                Pat::Tuple { args, ellipsis }
2291            }
2292            ast::Pat::WildcardPat(_) => Pat::Wild,
2293            ast::Pat::RecordPat(p) => {
2294                let path = p
2295                    .path()
2296                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator))
2297                    .map(Box::new);
2298                let record_pat_field_list =
2299                    &p.record_pat_field_list().expect("every struct should have a field list");
2300                let args = record_pat_field_list
2301                    .fields()
2302                    .filter_map(|f| {
2303                        if !self.check_cfg(&f) {
2304                            return None;
2305                        }
2306                        let ast_pat = f.pat()?;
2307                        let pat = self.collect_pat(ast_pat, binding_list);
2308                        let name = f.field_name()?.as_name();
2309                        let src = self.expander.in_file(AstPtr::new(&f).wrap_right());
2310                        self.store.pat_field_map_back.insert(pat, src);
2311                        Some(RecordFieldPat { name, pat })
2312                    })
2313                    .collect();
2314
2315                let ellipsis = record_pat_field_list.rest_pat().is_some();
2316
2317                Pat::Record { path, args, ellipsis }
2318            }
2319            ast::Pat::SlicePat(p) => {
2320                let SlicePatComponents { prefix, slice, suffix } = p.components();
2321
2322                // FIXME properly handle `RestPat`
2323                Pat::Slice {
2324                    prefix: prefix.into_iter().map(|p| self.collect_pat(p, binding_list)).collect(),
2325                    slice: slice.map(|p| self.collect_pat(p, binding_list)),
2326                    suffix: suffix.into_iter().map(|p| self.collect_pat(p, binding_list)).collect(),
2327                }
2328            }
2329            ast::Pat::LiteralPat(lit) => 'b: {
2330                let Some((hir_lit, ast_lit)) = pat_literal_to_hir(lit) else {
2331                    break 'b Pat::Missing;
2332                };
2333                let expr = Expr::Literal(hir_lit);
2334                let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
2335                let expr_id = self.alloc_expr(expr, expr_ptr);
2336                Pat::Lit(expr_id)
2337            }
2338            ast::Pat::RestPat(_) => {
2339                // `RestPat` requires special handling and should not be mapped
2340                // to a Pat. Here we are using `Pat::Missing` as a fallback for
2341                // when `RestPat` is mapped to `Pat`, which can easily happen
2342                // when the source code being analyzed has a malformed pattern
2343                // which includes `..` in a place where it isn't valid.
2344
2345                Pat::Missing
2346            }
2347            ast::Pat::BoxPat(boxpat) => {
2348                let inner = self.collect_pat_opt(boxpat.pat(), binding_list);
2349                Pat::Box { inner }
2350            }
2351            ast::Pat::ConstBlockPat(const_block_pat) => {
2352                if let Some(block) = const_block_pat.block_expr() {
2353                    let expr_id = self.with_label_rib(RibKind::Constant, |this| {
2354                        this.with_binding_owner(|this| this.collect_block(block))
2355                    });
2356                    Pat::ConstBlock(expr_id)
2357                } else {
2358                    Pat::Missing
2359                }
2360            }
2361            ast::Pat::MacroPat(mac) => match mac.macro_call() {
2362                Some(call) => {
2363                    let macro_ptr = AstPtr::new(&call);
2364                    let src = self.expander.in_file(AstPtr::new(&pat));
2365                    let pat =
2366                        self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
2367                            this.collect_pat_opt(expanded_pat, binding_list)
2368                        });
2369                    self.store.pat_map.insert(src, pat.into());
2370                    return pat;
2371                }
2372                None => Pat::Missing,
2373            },
2374            ast::Pat::RangePat(p) => {
2375                let mut range_part_lower = |p: Option<ast::Pat>| -> Option<ExprId> {
2376                    p.and_then(|it| {
2377                        let ptr = PatPtr::new(&it);
2378                        match &it {
2379                            ast::Pat::LiteralPat(it) => Some(self.alloc_expr_from_pat(
2380                                Expr::Literal(pat_literal_to_hir(it)?.0),
2381                                ptr,
2382                            )),
2383                            ast::Pat::IdentPat(ident) if ident.is_simple_ident() => ident
2384                                .name()
2385                                .map(|name| name.as_name())
2386                                .map(Path::from)
2387                                .map(|path| self.alloc_expr_from_pat(Expr::Path(path), ptr)),
2388                            ast::Pat::PathPat(p) => p
2389                                .path()
2390                                .and_then(|path| {
2391                                    self.lower_path(path, &mut Self::impl_trait_error_allocator)
2392                                })
2393                                .map(|parsed| self.alloc_expr_from_pat(Expr::Path(parsed), ptr)),
2394                            // We only need to handle literal, ident (if bare) and path patterns here,
2395                            // as any other pattern as a range pattern operand is semantically invalid.
2396                            _ => None,
2397                        }
2398                    })
2399                };
2400                let start = range_part_lower(p.start());
2401                let end = range_part_lower(p.end());
2402                // FIXME: Exclusive ended pattern range is stabilised
2403                match p.op_kind() {
2404                    Some(range_type) => Pat::Range { start, end, range_type },
2405                    None => Pat::Missing,
2406                }
2407            }
2408        };
2409        let ptr = AstPtr::new(&pat);
2410        self.alloc_pat(pattern, ptr)
2411    }
2412
2413    fn collect_pat_opt(&mut self, pat: Option<ast::Pat>, binding_list: &mut BindingList) -> PatId {
2414        match pat {
2415            Some(pat) => self.collect_pat(pat, binding_list),
2416            None => self.missing_pat(),
2417        }
2418    }
2419
2420    fn collect_tuple_pat(
2421        &mut self,
2422        args: AstChildren<ast::Pat>,
2423        has_leading_comma: bool,
2424        binding_list: &mut BindingList,
2425    ) -> (Box<[PatId]>, Option<u32>) {
2426        let args: Vec<_> = args.map(|p| self.collect_pat_possibly_rest(p, binding_list)).collect();
2427        // Find the location of the `..`, if there is one. Note that we do not
2428        // consider the possibility of there being multiple `..` here.
2429        let ellipsis = args.iter().position(|p| p.is_right()).map(|it| it as u32);
2430
2431        // We want to skip the `..` pattern here, since we account for it above.
2432        let mut args: Vec<_> = args.into_iter().filter_map(Either::left).collect();
2433        // if there is a leading comma, the user is most likely to type out a leading pattern
2434        // so we insert a missing pattern at the beginning for IDE features
2435        if has_leading_comma {
2436            args.insert(0, self.missing_pat());
2437        }
2438
2439        (args.into_boxed_slice(), ellipsis)
2440    }
2441
2442    // `collect_pat` rejects `ast::Pat::RestPat`, but it should be handled in some cases that
2443    // it is the macro expansion result of an arg sub-pattern in a slice or tuple pattern.
2444    fn collect_pat_possibly_rest(
2445        &mut self,
2446        pat: ast::Pat,
2447        binding_list: &mut BindingList,
2448    ) -> Either<PatId, ()> {
2449        match &pat {
2450            ast::Pat::RestPat(_) => Either::Right(()),
2451            ast::Pat::MacroPat(mac) => match mac.macro_call() {
2452                Some(call) => {
2453                    let macro_ptr = AstPtr::new(&call);
2454                    let src = self.expander.in_file(AstPtr::new(&pat));
2455                    let pat =
2456                        self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
2457                            if let Some(expanded_pat) = expanded_pat {
2458                                this.collect_pat_possibly_rest(expanded_pat, binding_list)
2459                            } else {
2460                                Either::Left(this.missing_pat())
2461                            }
2462                        });
2463                    if let Some(pat) = pat.left() {
2464                        self.store.pat_map.insert(src, pat.into());
2465                    }
2466                    pat
2467                }
2468                None => {
2469                    let ptr = AstPtr::new(&pat);
2470                    Either::Left(self.alloc_pat(Pat::Missing, ptr))
2471                }
2472            },
2473            _ => Either::Left(self.collect_pat(pat, binding_list)),
2474        }
2475    }
2476
2477    // endregion: patterns
2478
2479    /// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when
2480    /// not.
2481    fn check_cfg(&mut self, owner: &dyn ast::HasAttrs) -> bool {
2482        let enabled = self.expander.is_cfg_enabled(owner, self.cfg_options);
2483        match enabled {
2484            Ok(()) => true,
2485            Err(cfg) => {
2486                self.store.diagnostics.push(ExpressionStoreDiagnostics::InactiveCode {
2487                    node: self.expander.in_file(SyntaxNodePtr::new(owner.syntax())),
2488                    cfg,
2489                    opts: self.cfg_options.clone(),
2490                });
2491                false
2492            }
2493        }
2494    }
2495
2496    fn add_definition_to_binding(&mut self, binding_id: BindingId, pat_id: PatId) {
2497        self.store.binding_definitions.entry(binding_id).or_default().push(pat_id);
2498    }
2499
2500    // region: labels
2501
2502    fn collect_label(&mut self, ast_label: ast::Label) -> LabelId {
2503        let label = Label {
2504            name: ast_label
2505                .lifetime()
2506                .as_ref()
2507                .map_or_else(Name::missing, |lt| Name::new_lifetime(&lt.text())),
2508        };
2509        self.alloc_label(label, AstPtr::new(&ast_label))
2510    }
2511
2512    fn resolve_label(
2513        &self,
2514        lifetime: Option<ast::Lifetime>,
2515    ) -> Result<Option<LabelId>, ExpressionStoreDiagnostics> {
2516        let Some(lifetime) = lifetime else { return Ok(None) };
2517        let mut hygiene_id =
2518            self.expander.hygiene_for_range(self.db, lifetime.syntax().text_range());
2519        let mut hygiene_info = if hygiene_id.is_root() {
2520            None
2521        } else {
2522            hygiene_id.lookup().outer_expn(self.db).map(|expansion| {
2523                let expansion = self.db.lookup_intern_macro_call(expansion.into());
2524                (hygiene_id.lookup().parent(self.db), expansion.def)
2525            })
2526        };
2527        let name = Name::new_lifetime(&lifetime.text());
2528
2529        for (rib_idx, rib) in self.label_ribs.iter().enumerate().rev() {
2530            match &rib.kind {
2531                RibKind::Normal(label_name, id, label_hygiene) => {
2532                    if *label_name == name && *label_hygiene == hygiene_id {
2533                        return if self.is_label_valid_from_rib(rib_idx) {
2534                            Ok(Some(*id))
2535                        } else {
2536                            Err(ExpressionStoreDiagnostics::UnreachableLabel {
2537                                name,
2538                                node: self.expander.in_file(AstPtr::new(&lifetime)),
2539                            })
2540                        };
2541                    }
2542                }
2543                RibKind::MacroDef(macro_id) => {
2544                    if let Some((parent_ctx, label_macro_id)) = hygiene_info
2545                        && label_macro_id == **macro_id
2546                    {
2547                        // A macro is allowed to refer to labels from before its declaration.
2548                        // Therefore, if we got to the rib of its declaration, give up its hygiene
2549                        // and use its parent expansion.
2550
2551                        hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent(self.db));
2552                        hygiene_info = parent_ctx.outer_expn(self.db).map(|expansion| {
2553                            let expansion = self.db.lookup_intern_macro_call(expansion.into());
2554                            (parent_ctx.parent(self.db), expansion.def)
2555                        });
2556                    }
2557                }
2558                _ => {}
2559            }
2560        }
2561
2562        Err(ExpressionStoreDiagnostics::UndeclaredLabel {
2563            name,
2564            node: self.expander.in_file(AstPtr::new(&lifetime)),
2565        })
2566    }
2567
2568    fn is_label_valid_from_rib(&self, rib_index: usize) -> bool {
2569        !self.label_ribs[rib_index + 1..].iter().any(|rib| rib.kind.is_label_barrier())
2570    }
2571
2572    fn pop_label_rib(&mut self) {
2573        // We need to pop all macro defs, plus one rib.
2574        while let Some(LabelRib { kind: RibKind::MacroDef(_) }) = self.label_ribs.pop() {
2575            // Do nothing.
2576        }
2577    }
2578
2579    fn with_label_rib<T>(&mut self, kind: RibKind, f: impl FnOnce(&mut Self) -> T) -> T {
2580        self.label_ribs.push(LabelRib::new(kind));
2581        let res = f(self);
2582        self.pop_label_rib();
2583        res
2584    }
2585
2586    fn with_labeled_rib<T>(
2587        &mut self,
2588        label: LabelId,
2589        hygiene: HygieneId,
2590        f: impl FnOnce(&mut Self) -> T,
2591    ) -> T {
2592        self.label_ribs.push(LabelRib::new(RibKind::Normal(
2593            self.store.labels[label].name.clone(),
2594            label,
2595            hygiene,
2596        )));
2597        let res = f(self);
2598        self.pop_label_rib();
2599        res
2600    }
2601
2602    fn with_opt_labeled_rib<T>(
2603        &mut self,
2604        label: Option<(HygieneId, LabelId)>,
2605        f: impl FnOnce(&mut Self) -> T,
2606    ) -> T {
2607        match label {
2608            None => f(self),
2609            Some((hygiene, label)) => self.with_labeled_rib(label, hygiene, f),
2610        }
2611    }
2612    // endregion: labels
2613
2614    fn expand_macros_to_string(&mut self, expr: ast::Expr) -> Option<(ast::String, bool)> {
2615        let m = match expr {
2616            ast::Expr::MacroExpr(m) => m,
2617            ast::Expr::Literal(l) => {
2618                return match l.kind() {
2619                    ast::LiteralKind::String(s) => Some((s, true)),
2620                    _ => None,
2621                };
2622            }
2623            _ => return None,
2624        };
2625        let e = m.macro_call()?;
2626        let macro_ptr = AstPtr::new(&e);
2627        let (exp, _) = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
2628            expansion.and_then(|it| this.expand_macros_to_string(it))
2629        })?;
2630        Some((exp, false))
2631    }
2632
2633    fn lang_path(&self, lang: Option<impl Into<LangItemTarget>>) -> Option<Path> {
2634        Some(Path::LangItem(lang?.into(), None))
2635    }
2636
2637    fn ty_rel_lang_path(
2638        &self,
2639        lang: Option<impl Into<LangItemTarget>>,
2640        relative_name: Symbol,
2641    ) -> Option<Path> {
2642        Some(Path::LangItem(lang?.into(), Some(Name::new_symbol_root(relative_name))))
2643    }
2644
2645    fn ty_rel_lang_path_expr(
2646        &self,
2647        lang: Option<impl Into<LangItemTarget>>,
2648        relative_name: Symbol,
2649    ) -> Expr {
2650        self.ty_rel_lang_path(lang, relative_name).map_or(Expr::Missing, Expr::Path)
2651    }
2652}
2653
2654fn pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)> {
2655    let ast_lit = lit.literal()?;
2656    let mut hir_lit: Literal = ast_lit.kind().into();
2657    if lit.minus_token().is_some() {
2658        hir_lit = hir_lit.negate()?;
2659    }
2660    Some((hir_lit, ast_lit))
2661}
2662
2663impl ExprCollector<'_> {
2664    fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
2665        let src = self.expander.in_file(ptr);
2666        let id = self.store.exprs.alloc(expr);
2667        self.store.expr_map_back.insert(id, src.map(AstPtr::wrap_left));
2668        self.store.expr_map.insert(src, id.into());
2669        id
2670    }
2671    // FIXME: desugared exprs don't have ptr, that's wrong and should be fixed.
2672    // Migrate to alloc_expr_desugared_with_ptr and then rename back
2673    fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
2674        self.store.exprs.alloc(expr)
2675    }
2676    fn alloc_expr_desugared_with_ptr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
2677        let src = self.expander.in_file(ptr);
2678        let id = self.store.exprs.alloc(expr);
2679        self.store.expr_map_back.insert(id, src.map(AstPtr::wrap_left));
2680        // We intentionally don't fill this as it could overwrite a non-desugared entry
2681        // self.store.expr_map.insert(src, id);
2682        id
2683    }
2684    fn missing_expr(&mut self) -> ExprId {
2685        self.alloc_expr_desugared(Expr::Missing)
2686    }
2687
2688    fn alloc_binding(
2689        &mut self,
2690        name: Name,
2691        mode: BindingAnnotation,
2692        hygiene: HygieneId,
2693    ) -> BindingId {
2694        let binding = self.store.bindings.alloc(Binding { name, mode, problems: None, hygiene });
2695        self.unowned_bindings.push(binding);
2696        binding
2697    }
2698
2699    fn alloc_pat_from_expr(&mut self, pat: Pat, ptr: ExprPtr) -> PatId {
2700        let src = self.expander.in_file(ptr);
2701        let id = self.store.pats.alloc(pat);
2702        self.store.expr_map.insert(src, id.into());
2703        self.store.pat_map_back.insert(id, src.map(AstPtr::wrap_left));
2704        id
2705    }
2706
2707    fn alloc_expr_from_pat(&mut self, expr: Expr, ptr: PatPtr) -> ExprId {
2708        let src = self.expander.in_file(ptr);
2709        let id = self.store.exprs.alloc(expr);
2710        self.store.pat_map.insert(src, id.into());
2711        self.store.expr_map_back.insert(id, src.map(AstPtr::wrap_right));
2712        id
2713    }
2714
2715    fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
2716        let src = self.expander.in_file(ptr);
2717        let id = self.store.pats.alloc(pat);
2718        self.store.pat_map_back.insert(id, src.map(AstPtr::wrap_right));
2719        self.store.pat_map.insert(src, id.into());
2720        id
2721    }
2722    // FIXME: desugared pats don't have ptr, that's wrong and should be fixed somehow.
2723    fn alloc_pat_desugared(&mut self, pat: Pat) -> PatId {
2724        self.store.pats.alloc(pat)
2725    }
2726    fn missing_pat(&mut self) -> PatId {
2727        self.store.pats.alloc(Pat::Missing)
2728    }
2729
2730    fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId {
2731        let src = self.expander.in_file(ptr);
2732        let id = self.store.labels.alloc(label);
2733        self.store.label_map_back.insert(id, src);
2734        self.store.label_map.insert(src, id);
2735        id
2736    }
2737    // FIXME: desugared labels don't have ptr, that's wrong and should be fixed somehow.
2738    fn alloc_label_desugared(&mut self, label: Label) -> LabelId {
2739        self.store.labels.alloc(label)
2740    }
2741
2742    fn is_lowering_awaitable_block(&self) -> &Awaitable {
2743        self.awaitable_context.as_ref().unwrap_or(&Awaitable::No("unknown"))
2744    }
2745
2746    fn with_awaitable_block<T>(
2747        &mut self,
2748        awaitable: Awaitable,
2749        f: impl FnOnce(&mut Self) -> T,
2750    ) -> T {
2751        let orig = self.awaitable_context.replace(awaitable);
2752        let res = f(self);
2753        self.awaitable_context = orig;
2754        res
2755    }
2756
2757    fn hygiene_id_for(&self, range: TextRange) -> HygieneId {
2758        self.expander.hygiene_for_range(self.db, range)
2759    }
2760}
2761
2762fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool {
2763    (|| syntax::algo::skip_trivia_token(t?.next_token()?, syntax::Direction::Next))()
2764        .is_some_and(|it| it.kind() == syntax::T![,])
2765}
2766
2767/// This function find the AST fragment that corresponds to an `AssociatedTypeBinding` in the HIR.
2768pub fn hir_assoc_type_binding_to_ast(
2769    segment_args: &ast::GenericArgList,
2770    binding_idx: u32,
2771) -> Option<ast::AssocTypeArg> {
2772    segment_args
2773        .generic_args()
2774        .filter_map(|arg| match arg {
2775            ast::GenericArg::AssocTypeArg(it) => Some(it),
2776            _ => None,
2777        })
2778        .filter(|binding| binding.param_list().is_none() && binding.name_ref().is_some())
2779        .nth(binding_idx as usize)
2780}
2781
2782/// This function find the AST generic argument from the one in the HIR. Does not support the `Self` argument.
2783pub fn hir_generic_arg_to_ast(
2784    args: &ast::GenericArgList,
2785    arg_idx: u32,
2786    has_self_arg: bool,
2787) -> Option<ast::GenericArg> {
2788    args.generic_args()
2789        .filter(|arg| match arg {
2790            ast::GenericArg::AssocTypeArg(_) => false,
2791            ast::GenericArg::LifetimeArg(arg) => arg.lifetime().is_some(),
2792            ast::GenericArg::ConstArg(_) | ast::GenericArg::TypeArg(_) => true,
2793        })
2794        .nth(arg_idx as usize - has_self_arg as usize)
2795}