hir_def/expr_store/
lower.rs

1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
2//! representation.
3
4mod asm;
5mod generics;
6mod path;
7
8use std::mem;
9
10use base_db::FxIndexSet;
11use cfg::CfgOptions;
12use either::Either;
13use hir_expand::{
14    HirFileId, InFile, MacroDefId,
15    mod_path::tool_path,
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, AstToken as _, 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    builtin_type::BuiltinUint,
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,
51        format_args::{
52            self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind,
53            FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions,
54            FormatPlaceholder, FormatSign, FormatTrait,
55        },
56        generics::GenericParams,
57    },
58    item_scope::BuiltinShadowMode,
59    item_tree::FieldsShape,
60    lang_item::LangItem,
61    nameres::{DefMap, LocalDefMap, MacroSubNs, block_def_map},
62    type_ref::{
63        ArrayType, ConstRef, FnType, LifetimeRef, LifetimeRefId, Mutability, PathId, Rawness,
64        RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, UseArgRef,
65    },
66};
67
68pub use self::path::hir_segment_to_ast_segment;
69
70pub(super) fn lower_body(
71    db: &dyn DefDatabase,
72    owner: DefWithBodyId,
73    current_file_id: HirFileId,
74    module: ModuleId,
75    parameters: Option<ast::ParamList>,
76    body: Option<ast::Expr>,
77    is_async_fn: bool,
78) -> (Body, BodySourceMap) {
79    // We cannot leave the root span map empty and let any identifier from it be treated as root,
80    // because when inside nested macros `SyntaxContextId`s from the outer macro will be interleaved
81    // with the inner macro, and that will cause confusion because they won't be the same as `ROOT`
82    // even though they should be the same. Also, when the body comes from multiple expansions, their
83    // hygiene is different.
84
85    let mut self_param = None;
86    let mut source_map_self_param = None;
87    let mut params = vec![];
88    let mut collector = ExprCollector::new(db, module, current_file_id);
89
90    let skip_body = match owner {
91        DefWithBodyId::FunctionId(it) => db.attrs(it.into()),
92        DefWithBodyId::StaticId(it) => db.attrs(it.into()),
93        DefWithBodyId::ConstId(it) => db.attrs(it.into()),
94        DefWithBodyId::VariantId(it) => db.attrs(it.into()),
95    }
96    .rust_analyzer_tool()
97    .any(|attr| *attr.path() == tool_path![skip]);
98    // If #[rust_analyzer::skip] annotated, only construct enough information for the signature
99    // and skip the body.
100    if skip_body {
101        if let Some(param_list) = parameters {
102            if let Some(self_param_syn) =
103                param_list.self_param().filter(|self_param| collector.check_cfg(self_param))
104            {
105                let is_mutable =
106                    self_param_syn.mut_token().is_some() && self_param_syn.amp_token().is_none();
107                let hygiene = self_param_syn
108                    .name()
109                    .map(|name| collector.hygiene_id_for(name.syntax().text_range()))
110                    .unwrap_or(HygieneId::ROOT);
111                let binding_id: la_arena::Idx<Binding> = collector.alloc_binding(
112                    Name::new_symbol_root(sym::self_),
113                    BindingAnnotation::new(is_mutable, false),
114                    hygiene,
115                );
116                self_param = Some(binding_id);
117                source_map_self_param =
118                    Some(collector.expander.in_file(AstPtr::new(&self_param_syn)));
119            }
120            let count = param_list.params().filter(|it| collector.check_cfg(it)).count();
121            params = (0..count).map(|_| collector.missing_pat()).collect();
122        };
123        let body_expr = collector.missing_expr();
124        let (store, source_map) = collector.store.finish();
125        return (
126            Body { store, params: params.into_boxed_slice(), self_param, body_expr },
127            BodySourceMap { self_param: source_map_self_param, store: source_map },
128        );
129    }
130
131    if let Some(param_list) = parameters {
132        if let Some(self_param_syn) = param_list.self_param().filter(|it| collector.check_cfg(it)) {
133            let is_mutable =
134                self_param_syn.mut_token().is_some() && self_param_syn.amp_token().is_none();
135            let hygiene = self_param_syn
136                .name()
137                .map(|name| collector.hygiene_id_for(name.syntax().text_range()))
138                .unwrap_or(HygieneId::ROOT);
139            let binding_id: la_arena::Idx<Binding> = collector.alloc_binding(
140                Name::new_symbol_root(sym::self_),
141                BindingAnnotation::new(is_mutable, false),
142                hygiene,
143            );
144            self_param = Some(binding_id);
145            source_map_self_param = Some(collector.expander.in_file(AstPtr::new(&self_param_syn)));
146        }
147
148        for param in param_list.params() {
149            if collector.check_cfg(&param) {
150                let param_pat = collector.collect_pat_top(param.pat());
151                params.push(param_pat);
152            }
153        }
154    };
155
156    let body_expr = collector.collect(
157        body,
158        if is_async_fn {
159            Awaitable::Yes
160        } else {
161            match owner {
162                DefWithBodyId::FunctionId(..) => Awaitable::No("non-async function"),
163                DefWithBodyId::StaticId(..) => Awaitable::No("static"),
164                DefWithBodyId::ConstId(..) => Awaitable::No("constant"),
165                DefWithBodyId::VariantId(..) => Awaitable::No("enum variant"),
166            }
167        },
168    );
169
170    let (store, source_map) = collector.store.finish();
171    (
172        Body { store, params: params.into_boxed_slice(), self_param, body_expr },
173        BodySourceMap { self_param: source_map_self_param, store: source_map },
174    )
175}
176
177pub(crate) fn lower_type_ref(
178    db: &dyn DefDatabase,
179    module: ModuleId,
180    type_ref: InFile<Option<ast::Type>>,
181) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId) {
182    let mut expr_collector = ExprCollector::new(db, module, type_ref.file_id);
183    let type_ref =
184        expr_collector.lower_type_ref_opt(type_ref.value, &mut ExprCollector::impl_trait_allocator);
185    let (store, source_map) = expr_collector.store.finish();
186    (store, source_map, type_ref)
187}
188
189pub(crate) fn lower_generic_params(
190    db: &dyn DefDatabase,
191    module: ModuleId,
192    def: GenericDefId,
193    file_id: HirFileId,
194    param_list: Option<ast::GenericParamList>,
195    where_clause: Option<ast::WhereClause>,
196) -> (Arc<ExpressionStore>, Arc<GenericParams>, ExpressionStoreSourceMap) {
197    let mut expr_collector = ExprCollector::new(db, module, file_id);
198    let mut collector = generics::GenericParamsCollector::new(def);
199    collector.lower(&mut expr_collector, param_list, where_clause);
200    let params = collector.finish();
201    let (store, source_map) = expr_collector.store.finish();
202    (Arc::new(store), params, source_map)
203}
204
205pub(crate) fn lower_impl(
206    db: &dyn DefDatabase,
207    module: ModuleId,
208    impl_syntax: InFile<ast::Impl>,
209    impl_id: ImplId,
210) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId, Option<TraitRef>, Arc<GenericParams>) {
211    let mut expr_collector = ExprCollector::new(db, module, impl_syntax.file_id);
212    let self_ty =
213        expr_collector.lower_type_ref_opt_disallow_impl_trait(impl_syntax.value.self_ty());
214    let trait_ = impl_syntax.value.trait_().and_then(|it| match &it {
215        ast::Type::PathType(path_type) => {
216            let path = expr_collector
217                .lower_path_type(path_type, &mut ExprCollector::impl_trait_allocator)?;
218            Some(TraitRef { path: expr_collector.alloc_path(path, AstPtr::new(&it)) })
219        }
220        _ => None,
221    });
222    let mut collector = generics::GenericParamsCollector::new(impl_id.into());
223    collector.lower(
224        &mut expr_collector,
225        impl_syntax.value.generic_param_list(),
226        impl_syntax.value.where_clause(),
227    );
228    let params = collector.finish();
229    let (store, source_map) = expr_collector.store.finish();
230    (store, source_map, self_ty, trait_, params)
231}
232
233pub(crate) fn lower_trait(
234    db: &dyn DefDatabase,
235    module: ModuleId,
236    trait_syntax: InFile<ast::Trait>,
237    trait_id: TraitId,
238) -> (ExpressionStore, ExpressionStoreSourceMap, Arc<GenericParams>) {
239    let mut expr_collector = ExprCollector::new(db, module, trait_syntax.file_id);
240    let mut collector = generics::GenericParamsCollector::with_self_param(
241        &mut expr_collector,
242        trait_id.into(),
243        trait_syntax.value.type_bound_list(),
244    );
245    collector.lower(
246        &mut expr_collector,
247        trait_syntax.value.generic_param_list(),
248        trait_syntax.value.where_clause(),
249    );
250    let params = collector.finish();
251    let (store, source_map) = expr_collector.store.finish();
252    (store, source_map, params)
253}
254
255pub(crate) fn lower_type_alias(
256    db: &dyn DefDatabase,
257    module: ModuleId,
258    alias: InFile<ast::TypeAlias>,
259    type_alias_id: TypeAliasId,
260) -> (
261    ExpressionStore,
262    ExpressionStoreSourceMap,
263    Arc<GenericParams>,
264    Box<[TypeBound]>,
265    Option<TypeRefId>,
266) {
267    let mut expr_collector = ExprCollector::new(db, module, alias.file_id);
268    let bounds = alias
269        .value
270        .type_bound_list()
271        .map(|bounds| {
272            bounds
273                .bounds()
274                .map(|bound| {
275                    expr_collector.lower_type_bound(bound, &mut ExprCollector::impl_trait_allocator)
276                })
277                .collect()
278        })
279        .unwrap_or_default();
280    let mut collector = generics::GenericParamsCollector::new(type_alias_id.into());
281    collector.lower(
282        &mut expr_collector,
283        alias.value.generic_param_list(),
284        alias.value.where_clause(),
285    );
286    let params = collector.finish();
287    let type_ref = alias
288        .value
289        .ty()
290        .map(|ty| expr_collector.lower_type_ref(ty, &mut ExprCollector::impl_trait_allocator));
291    let (store, source_map) = expr_collector.store.finish();
292    (store, source_map, params, bounds, type_ref)
293}
294
295pub(crate) fn lower_function(
296    db: &dyn DefDatabase,
297    module: ModuleId,
298    fn_: InFile<ast::Fn>,
299    function_id: FunctionId,
300) -> (
301    ExpressionStore,
302    ExpressionStoreSourceMap,
303    Arc<GenericParams>,
304    Box<[TypeRefId]>,
305    Option<TypeRefId>,
306    bool,
307    bool,
308) {
309    let mut expr_collector = ExprCollector::new(db, module, fn_.file_id);
310    let mut collector = generics::GenericParamsCollector::new(function_id.into());
311    collector.lower(&mut expr_collector, fn_.value.generic_param_list(), fn_.value.where_clause());
312    let mut params = vec![];
313    let mut has_self_param = false;
314    let mut has_variadic = false;
315    collector.collect_impl_trait(&mut expr_collector, |collector, mut impl_trait_lower_fn| {
316        if let Some(param_list) = fn_.value.param_list() {
317            if let Some(param) = param_list.self_param() {
318                let enabled = collector.check_cfg(&param);
319                if enabled {
320                    has_self_param = true;
321                    params.push(match param.ty() {
322                        Some(ty) => collector.lower_type_ref(ty, &mut impl_trait_lower_fn),
323                        None => {
324                            let self_type = collector.alloc_type_ref_desugared(TypeRef::Path(
325                                Name::new_symbol_root(sym::Self_).into(),
326                            ));
327                            let lifetime = param
328                                .lifetime()
329                                .map(|lifetime| collector.lower_lifetime_ref(lifetime));
330                            match param.kind() {
331                                ast::SelfParamKind::Owned => self_type,
332                                ast::SelfParamKind::Ref => collector.alloc_type_ref_desugared(
333                                    TypeRef::Reference(Box::new(RefType {
334                                        ty: self_type,
335                                        lifetime,
336                                        mutability: Mutability::Shared,
337                                    })),
338                                ),
339                                ast::SelfParamKind::MutRef => collector.alloc_type_ref_desugared(
340                                    TypeRef::Reference(Box::new(RefType {
341                                        ty: self_type,
342                                        lifetime,
343                                        mutability: Mutability::Mut,
344                                    })),
345                                ),
346                            }
347                        }
348                    });
349                }
350            }
351            let p = param_list
352                .params()
353                .filter(|param| collector.check_cfg(param))
354                .filter(|param| {
355                    let is_variadic = param.dotdotdot_token().is_some();
356                    has_variadic |= is_variadic;
357                    !is_variadic
358                })
359                .map(|param| param.ty())
360                // FIXME
361                .collect::<Vec<_>>();
362            for p in p {
363                params.push(collector.lower_type_ref_opt(p, &mut impl_trait_lower_fn));
364            }
365        }
366    });
367    let generics = collector.finish();
368    let return_type = fn_.value.ret_type().map(|ret_type| {
369        expr_collector.lower_type_ref_opt(ret_type.ty(), &mut ExprCollector::impl_trait_allocator)
370    });
371
372    let return_type = if fn_.value.async_token().is_some() {
373        let path = hir_expand::mod_path::path![core::future::Future];
374        let mut generic_args: Vec<_> =
375            std::iter::repeat_n(None, path.segments().len() - 1).collect();
376        let binding = AssociatedTypeBinding {
377            name: Name::new_symbol_root(sym::Output),
378            args: None,
379            type_ref: Some(
380                return_type
381                    .unwrap_or_else(|| expr_collector.alloc_type_ref_desugared(TypeRef::unit())),
382            ),
383            bounds: Box::default(),
384        };
385        generic_args
386            .push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() }));
387
388        let path = Path::from_known_path(path, generic_args);
389        let path = PathId::from_type_ref_unchecked(
390            expr_collector.alloc_type_ref_desugared(TypeRef::Path(path)),
391        );
392        let ty_bound = TypeBound::Path(path, TraitBoundModifier::None);
393        Some(
394            expr_collector
395                .alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound]))),
396        )
397    } else {
398        return_type
399    };
400    let (store, source_map) = expr_collector.store.finish();
401    (
402        store,
403        source_map,
404        generics,
405        params.into_boxed_slice(),
406        return_type,
407        has_self_param,
408        has_variadic,
409    )
410}
411
412pub struct ExprCollector<'db> {
413    db: &'db dyn DefDatabase,
414    cfg_options: &'db CfgOptions,
415    expander: Expander,
416    def_map: &'db DefMap,
417    local_def_map: &'db LocalDefMap,
418    module: ModuleId,
419    pub store: ExpressionStoreBuilder,
420
421    // state stuff
422    // Prevent nested impl traits like `impl Foo<impl Bar>`.
423    outer_impl_trait: bool,
424
425    is_lowering_coroutine: bool,
426
427    /// Legacy (`macro_rules!`) macros can have multiple definitions and shadow each other,
428    /// and we need to find the current definition. So we track the number of definitions we saw.
429    current_block_legacy_macro_defs_count: FxHashMap<Name, usize>,
430
431    current_try_block_label: Option<LabelId>,
432
433    label_ribs: Vec<LabelRib>,
434    current_binding_owner: Option<ExprId>,
435
436    awaitable_context: Option<Awaitable>,
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 ExprCollector<'_> {
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        ExprCollector {
525            db,
526            cfg_options: module.krate().cfg_options(db),
527            module,
528            def_map,
529            local_def_map,
530            store: ExpressionStoreBuilder::default(),
531            expander,
532            current_try_block_label: None,
533            is_lowering_coroutine: false,
534            label_ribs: Vec::new(),
535            current_binding_owner: None,
536            awaitable_context: None,
537            current_block_legacy_macro_defs_count: FxHashMap::default(),
538            outer_impl_trait: false,
539        }
540    }
541
542    #[inline]
543    pub(crate) fn span_map(&self) -> SpanMapRef<'_> {
544        self.expander.span_map()
545    }
546
547    pub fn lower_lifetime_ref(&mut self, lifetime: ast::Lifetime) -> LifetimeRefId {
548        // FIXME: Keyword check?
549        let lifetime_ref = match &*lifetime.text() {
550            "" | "'" => LifetimeRef::Error,
551            "'static" => LifetimeRef::Static,
552            "'_" => LifetimeRef::Placeholder,
553            text => LifetimeRef::Named(Name::new_lifetime(text)),
554        };
555        self.alloc_lifetime_ref(lifetime_ref, AstPtr::new(&lifetime))
556    }
557
558    pub fn lower_lifetime_ref_opt(&mut self, lifetime: Option<ast::Lifetime>) -> LifetimeRefId {
559        match lifetime {
560            Some(lifetime) => self.lower_lifetime_ref(lifetime),
561            None => self.alloc_lifetime_ref_desugared(LifetimeRef::Placeholder),
562        }
563    }
564
565    /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
566    pub fn lower_type_ref(
567        &mut self,
568        node: ast::Type,
569        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
570    ) -> TypeRefId {
571        let ty = match &node {
572            ast::Type::ParenType(inner) => {
573                return self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);
574            }
575            ast::Type::TupleType(inner) => TypeRef::Tuple(ThinVec::from_iter(Vec::from_iter(
576                inner.fields().map(|it| self.lower_type_ref(it, impl_trait_lower_fn)),
577            ))),
578            ast::Type::NeverType(..) => TypeRef::Never,
579            ast::Type::PathType(inner) => inner
580                .path()
581                .and_then(|it| self.lower_path(it, impl_trait_lower_fn))
582                .map(TypeRef::Path)
583                .unwrap_or(TypeRef::Error),
584            ast::Type::PtrType(inner) => {
585                let inner_ty = self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);
586                let mutability = Mutability::from_mutable(inner.mut_token().is_some());
587                TypeRef::RawPtr(inner_ty, mutability)
588            }
589            ast::Type::ArrayType(inner) => {
590                let len = self.lower_const_arg_opt(inner.const_arg());
591                TypeRef::Array(ArrayType {
592                    ty: self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn),
593                    len,
594                })
595            }
596            ast::Type::SliceType(inner) => {
597                TypeRef::Slice(self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn))
598            }
599            ast::Type::RefType(inner) => {
600                let inner_ty = self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);
601                let lifetime = inner.lifetime().map(|lt| self.lower_lifetime_ref(lt));
602                let mutability = Mutability::from_mutable(inner.mut_token().is_some());
603                TypeRef::Reference(Box::new(RefType { ty: inner_ty, lifetime, mutability }))
604            }
605            ast::Type::InferType(_inner) => TypeRef::Placeholder,
606            ast::Type::FnPtrType(inner) => {
607                let ret_ty = inner
608                    .ret_type()
609                    .and_then(|rt| rt.ty())
610                    .map(|it| self.lower_type_ref(it, impl_trait_lower_fn))
611                    .unwrap_or_else(|| self.alloc_type_ref_desugared(TypeRef::unit()));
612                let mut is_varargs = false;
613                let mut params = if let Some(pl) = inner.param_list() {
614                    if let Some(param) = pl.params().last() {
615                        is_varargs = param.dotdotdot_token().is_some();
616                    }
617
618                    pl.params()
619                        .map(|it| {
620                            let type_ref = self.lower_type_ref_opt(it.ty(), impl_trait_lower_fn);
621                            let name = match it.pat() {
622                                Some(ast::Pat::IdentPat(it)) => Some(
623                                    it.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing),
624                                ),
625                                _ => None,
626                            };
627                            (name, type_ref)
628                        })
629                        .collect()
630                } else {
631                    Vec::with_capacity(1)
632                };
633                fn lower_abi(abi: ast::Abi) -> Symbol {
634                    match abi.abi_string() {
635                        Some(tok) => Symbol::intern(tok.text_without_quotes()),
636                        // `extern` default to be `extern "C"`.
637                        _ => sym::C,
638                    }
639                }
640
641                let abi = inner.abi().map(lower_abi);
642                params.push((None, ret_ty));
643                TypeRef::Fn(Box::new(FnType {
644                    is_varargs,
645                    is_unsafe: inner.unsafe_token().is_some(),
646                    abi,
647                    params: params.into_boxed_slice(),
648                }))
649            }
650            // for types are close enough for our purposes to the inner type for now...
651            ast::Type::ForType(inner) => {
652                return self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);
653            }
654            ast::Type::ImplTraitType(inner) => {
655                if self.outer_impl_trait {
656                    // Disallow nested impl traits
657                    TypeRef::Error
658                } else {
659                    return self.with_outer_impl_trait_scope(true, |this| {
660                        let type_bounds =
661                            this.type_bounds_from_ast(inner.type_bound_list(), impl_trait_lower_fn);
662                        impl_trait_lower_fn(this, AstPtr::new(&node), type_bounds)
663                    });
664                }
665            }
666            ast::Type::DynTraitType(inner) => TypeRef::DynTrait(
667                self.type_bounds_from_ast(inner.type_bound_list(), impl_trait_lower_fn),
668            ),
669            ast::Type::MacroType(mt) => match mt.macro_call() {
670                Some(mcall) => {
671                    let macro_ptr = AstPtr::new(&mcall);
672                    let src = self.expander.in_file(AstPtr::new(&node));
673                    let id = self.collect_macro_call(mcall, macro_ptr, true, |this, expansion| {
674                        this.lower_type_ref_opt(expansion, impl_trait_lower_fn)
675                    });
676                    self.store.types_map.insert(src, id);
677                    return id;
678                }
679                None => TypeRef::Error,
680            },
681        };
682        self.alloc_type_ref(ty, AstPtr::new(&node))
683    }
684
685    pub(crate) fn lower_type_ref_disallow_impl_trait(&mut self, node: ast::Type) -> TypeRefId {
686        self.lower_type_ref(node, &mut Self::impl_trait_error_allocator)
687    }
688
689    pub(crate) fn lower_type_ref_opt(
690        &mut self,
691        node: Option<ast::Type>,
692        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
693    ) -> TypeRefId {
694        match node {
695            Some(node) => self.lower_type_ref(node, impl_trait_lower_fn),
696            None => self.alloc_error_type(),
697        }
698    }
699
700    pub(crate) fn lower_type_ref_opt_disallow_impl_trait(
701        &mut self,
702        node: Option<ast::Type>,
703    ) -> TypeRefId {
704        self.lower_type_ref_opt(node, &mut Self::impl_trait_error_allocator)
705    }
706
707    fn alloc_type_ref(&mut self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {
708        let id = self.store.types.alloc(type_ref);
709        let ptr = self.expander.in_file(node);
710        self.store.types_map_back.insert(id, ptr);
711        self.store.types_map.insert(ptr, id);
712        id
713    }
714
715    fn alloc_lifetime_ref(
716        &mut self,
717        lifetime_ref: LifetimeRef,
718        node: LifetimePtr,
719    ) -> LifetimeRefId {
720        let id = self.store.lifetimes.alloc(lifetime_ref);
721        let ptr = self.expander.in_file(node);
722        self.store.lifetime_map_back.insert(id, ptr);
723        self.store.lifetime_map.insert(ptr, id);
724        id
725    }
726
727    fn alloc_type_ref_desugared(&mut self, type_ref: TypeRef) -> TypeRefId {
728        self.store.types.alloc(type_ref)
729    }
730
731    fn alloc_lifetime_ref_desugared(&mut self, lifetime_ref: LifetimeRef) -> LifetimeRefId {
732        self.store.lifetimes.alloc(lifetime_ref)
733    }
734
735    fn alloc_error_type(&mut self) -> TypeRefId {
736        self.store.types.alloc(TypeRef::Error)
737    }
738
739    pub fn lower_path(
740        &mut self,
741        ast: ast::Path,
742        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
743    ) -> Option<Path> {
744        super::lower::path::lower_path(self, ast, impl_trait_lower_fn)
745    }
746
747    fn with_outer_impl_trait_scope<R>(
748        &mut self,
749        impl_trait: bool,
750        f: impl FnOnce(&mut Self) -> R,
751    ) -> R {
752        let old = mem::replace(&mut self.outer_impl_trait, impl_trait);
753        let result = f(self);
754        self.outer_impl_trait = old;
755        result
756    }
757
758    pub fn impl_trait_error_allocator(
759        ec: &mut ExprCollector<'_>,
760        ptr: TypePtr,
761        _: ThinVec<TypeBound>,
762    ) -> TypeRefId {
763        ec.alloc_type_ref(TypeRef::Error, ptr)
764    }
765
766    fn impl_trait_allocator(
767        ec: &mut ExprCollector<'_>,
768        ptr: TypePtr,
769        bounds: ThinVec<TypeBound>,
770    ) -> TypeRefId {
771        ec.alloc_type_ref(TypeRef::ImplTrait(bounds), ptr)
772    }
773
774    fn alloc_path(&mut self, path: Path, node: TypePtr) -> PathId {
775        PathId::from_type_ref_unchecked(self.alloc_type_ref(TypeRef::Path(path), node))
776    }
777
778    /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
779    /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
780    pub fn lower_generic_args_from_fn_path(
781        &mut self,
782        args: Option<ast::ParenthesizedArgList>,
783        ret_type: Option<ast::RetType>,
784        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
785    ) -> Option<GenericArgs> {
786        let params = args?;
787        let mut param_types = Vec::new();
788        for param in params.type_args() {
789            let type_ref = self.lower_type_ref_opt(param.ty(), impl_trait_lower_fn);
790            param_types.push(type_ref);
791        }
792        let args = Box::new([GenericArg::Type(
793            self.alloc_type_ref_desugared(TypeRef::Tuple(ThinVec::from_iter(param_types))),
794        )]);
795        let bindings = if let Some(ret_type) = ret_type {
796            let type_ref = self.lower_type_ref_opt(ret_type.ty(), impl_trait_lower_fn);
797            Box::new([AssociatedTypeBinding {
798                name: Name::new_symbol_root(sym::Output),
799                args: None,
800                type_ref: Some(type_ref),
801                bounds: Box::default(),
802            }])
803        } else {
804            // -> ()
805            let type_ref = self.alloc_type_ref_desugared(TypeRef::unit());
806            Box::new([AssociatedTypeBinding {
807                name: Name::new_symbol_root(sym::Output),
808                args: None,
809                type_ref: Some(type_ref),
810                bounds: Box::default(),
811            }])
812        };
813        Some(GenericArgs {
814            args,
815            has_self_type: false,
816            bindings,
817            parenthesized: GenericArgsParentheses::ParenSugar,
818        })
819    }
820
821    pub(super) fn lower_generic_args(
822        &mut self,
823        node: ast::GenericArgList,
824        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
825    ) -> Option<GenericArgs> {
826        // This needs to be kept in sync with `hir_generic_arg_to_ast()`.
827        let mut args = Vec::new();
828        let mut bindings = Vec::new();
829        for generic_arg in node.generic_args() {
830            match generic_arg {
831                ast::GenericArg::TypeArg(type_arg) => {
832                    let type_ref = self.lower_type_ref_opt(type_arg.ty(), impl_trait_lower_fn);
833                    args.push(GenericArg::Type(type_ref));
834                }
835                ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
836                    // This needs to be kept in sync with `hir_assoc_type_binding_to_ast()`.
837                    if assoc_type_arg.param_list().is_some() {
838                        // We currently ignore associated return type bounds.
839                        continue;
840                    }
841                    if let Some(name_ref) = assoc_type_arg.name_ref() {
842                        // Nested impl traits like `impl Foo<Assoc = impl Bar>` are allowed
843                        self.with_outer_impl_trait_scope(false, |this| {
844                            let name = name_ref.as_name();
845                            let args = assoc_type_arg
846                                .generic_arg_list()
847                                .and_then(|args| this.lower_generic_args(args, impl_trait_lower_fn))
848                                .or_else(|| {
849                                    assoc_type_arg
850                                        .return_type_syntax()
851                                        .map(|_| GenericArgs::return_type_notation())
852                                });
853                            let type_ref = assoc_type_arg
854                                .ty()
855                                .map(|it| this.lower_type_ref(it, impl_trait_lower_fn));
856                            let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
857                                l.bounds()
858                                    .map(|it| this.lower_type_bound(it, impl_trait_lower_fn))
859                                    .collect()
860                            } else {
861                                Box::default()
862                            };
863                            bindings.push(AssociatedTypeBinding { name, args, type_ref, bounds });
864                        });
865                    }
866                }
867                ast::GenericArg::LifetimeArg(lifetime_arg) => {
868                    if let Some(lifetime) = lifetime_arg.lifetime() {
869                        let lifetime_ref = self.lower_lifetime_ref(lifetime);
870                        args.push(GenericArg::Lifetime(lifetime_ref))
871                    }
872                }
873                ast::GenericArg::ConstArg(arg) => {
874                    let arg = self.lower_const_arg(arg);
875                    args.push(GenericArg::Const(arg))
876                }
877            }
878        }
879
880        if args.is_empty() && bindings.is_empty() {
881            return None;
882        }
883        Some(GenericArgs {
884            args: args.into_boxed_slice(),
885            has_self_type: false,
886            bindings: bindings.into_boxed_slice(),
887            parenthesized: GenericArgsParentheses::No,
888        })
889    }
890
891    fn collect(&mut self, expr: Option<ast::Expr>, awaitable: Awaitable) -> ExprId {
892        self.awaitable_context.replace(awaitable);
893        self.with_label_rib(RibKind::Closure, |this| {
894            if awaitable == Awaitable::Yes {
895                match expr {
896                    Some(e) => {
897                        let syntax_ptr = AstPtr::new(&e);
898                        let expr = this.collect_expr(e);
899                        this.alloc_expr_desugared_with_ptr(
900                            Expr::Async { id: None, statements: Box::new([]), tail: Some(expr) },
901                            syntax_ptr,
902                        )
903                    }
904                    None => this.missing_expr(),
905                }
906            } else {
907                this.collect_expr_opt(expr)
908            }
909        })
910    }
911
912    fn type_bounds_from_ast(
913        &mut self,
914        type_bounds_opt: Option<ast::TypeBoundList>,
915        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
916    ) -> ThinVec<TypeBound> {
917        if let Some(type_bounds) = type_bounds_opt {
918            ThinVec::from_iter(Vec::from_iter(
919                type_bounds.bounds().map(|it| self.lower_type_bound(it, impl_trait_lower_fn)),
920            ))
921        } else {
922            ThinVec::from_iter([])
923        }
924    }
925
926    fn lower_path_type(
927        &mut self,
928        path_type: &ast::PathType,
929        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
930    ) -> Option<Path> {
931        let path = self.lower_path(path_type.path()?, impl_trait_lower_fn)?;
932        Some(path)
933    }
934
935    fn lower_type_bound(
936        &mut self,
937        node: ast::TypeBound,
938        impl_trait_lower_fn: ImplTraitLowerFn<'_>,
939    ) -> TypeBound {
940        match node.kind() {
941            ast::TypeBoundKind::PathType(binder, path_type) => {
942                let binder = match binder.and_then(|it| it.generic_param_list()) {
943                    Some(gpl) => gpl
944                        .lifetime_params()
945                        .flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(&lt.text())))
946                        .collect(),
947                    None => ThinVec::default(),
948                };
949                let m = match node.question_mark_token() {
950                    Some(_) => TraitBoundModifier::Maybe,
951                    None => TraitBoundModifier::None,
952                };
953                self.lower_path_type(&path_type, impl_trait_lower_fn)
954                    .map(|p| {
955                        let path = self.alloc_path(p, AstPtr::new(&path_type).upcast());
956                        if binder.is_empty() {
957                            TypeBound::Path(path, m)
958                        } else {
959                            TypeBound::ForLifetime(binder, path)
960                        }
961                    })
962                    .unwrap_or(TypeBound::Error)
963            }
964            ast::TypeBoundKind::Use(gal) => TypeBound::Use(
965                gal.use_bound_generic_args()
966                    .map(|p| match p {
967                        ast::UseBoundGenericArg::Lifetime(l) => {
968                            UseArgRef::Lifetime(self.lower_lifetime_ref(l))
969                        }
970                        ast::UseBoundGenericArg::NameRef(n) => UseArgRef::Name(n.as_name()),
971                    })
972                    .collect(),
973            ),
974            ast::TypeBoundKind::Lifetime(lifetime) => {
975                TypeBound::Lifetime(self.lower_lifetime_ref(lifetime))
976            }
977        }
978    }
979
980    fn lower_const_arg_opt(&mut self, arg: Option<ast::ConstArg>) -> ConstRef {
981        ConstRef { expr: self.collect_expr_opt(arg.and_then(|it| it.expr())) }
982    }
983
984    fn lower_const_arg(&mut self, arg: ast::ConstArg) -> ConstRef {
985        ConstRef { expr: self.collect_expr_opt(arg.expr()) }
986    }
987
988    fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
989        self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr())
990    }
991
992    /// Returns `None` if and only if the expression is `#[cfg]`d out.
993    fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
994        let syntax_ptr = AstPtr::new(&expr);
995        if !self.check_cfg(&expr) {
996            return None;
997        }
998
999        // FIXME: Move some of these arms out into separate methods for clarity
1000        Some(match expr {
1001            ast::Expr::IfExpr(e) => {
1002                let then_branch = self.collect_block_opt(e.then_branch());
1003
1004                let else_branch = e.else_branch().map(|b| match b {
1005                    ast::ElseBranch::Block(it) => self.collect_block(it),
1006                    ast::ElseBranch::IfExpr(elif) => {
1007                        let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
1008                        self.collect_expr(expr)
1009                    }
1010                });
1011
1012                let condition = self.collect_expr_opt(e.condition());
1013
1014                self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
1015            }
1016            ast::Expr::LetExpr(e) => {
1017                let pat = self.collect_pat_top(e.pat());
1018                let expr = self.collect_expr_opt(e.expr());
1019                self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr)
1020            }
1021            ast::Expr::BlockExpr(e) => match e.modifier() {
1022                Some(ast::BlockModifier::Try(_)) => self.desugar_try_block(e),
1023                Some(ast::BlockModifier::Unsafe(_)) => {
1024                    self.collect_block_(e, |id, statements, tail| Expr::Unsafe {
1025                        id,
1026                        statements,
1027                        tail,
1028                    })
1029                }
1030                Some(ast::BlockModifier::Label(label)) => {
1031                    let label_hygiene = self.hygiene_id_for(label.syntax().text_range());
1032                    let label_id = self.collect_label(label);
1033                    self.with_labeled_rib(label_id, label_hygiene, |this| {
1034                        this.collect_block_(e, |id, statements, tail| Expr::Block {
1035                            id,
1036                            statements,
1037                            tail,
1038                            label: Some(label_id),
1039                        })
1040                    })
1041                }
1042                Some(ast::BlockModifier::Async(_)) => {
1043                    self.with_label_rib(RibKind::Closure, |this| {
1044                        this.with_awaitable_block(Awaitable::Yes, |this| {
1045                            this.collect_block_(e, |id, statements, tail| Expr::Async {
1046                                id,
1047                                statements,
1048                                tail,
1049                            })
1050                        })
1051                    })
1052                }
1053                Some(ast::BlockModifier::Const(_)) => {
1054                    self.with_label_rib(RibKind::Constant, |this| {
1055                        this.with_awaitable_block(Awaitable::No("constant block"), |this| {
1056                            let (result_expr_id, prev_binding_owner) =
1057                                this.initialize_binding_owner(syntax_ptr);
1058                            let inner_expr = this.collect_block(e);
1059                            this.store.exprs[result_expr_id] = Expr::Const(inner_expr);
1060                            this.current_binding_owner = prev_binding_owner;
1061                            result_expr_id
1062                        })
1063                    })
1064                }
1065                // FIXME
1066                Some(ast::BlockModifier::AsyncGen(_)) => {
1067                    self.with_awaitable_block(Awaitable::Yes, |this| this.collect_block(e))
1068                }
1069                Some(ast::BlockModifier::Gen(_)) => self
1070                    .with_awaitable_block(Awaitable::No("non-async gen block"), |this| {
1071                        this.collect_block(e)
1072                    }),
1073                None => self.collect_block(e),
1074            },
1075            ast::Expr::LoopExpr(e) => {
1076                let label = e.label().map(|label| {
1077                    (self.hygiene_id_for(label.syntax().text_range()), self.collect_label(label))
1078                });
1079                let body = self.collect_labelled_block_opt(label, e.loop_body());
1080                self.alloc_expr(Expr::Loop { body, label: label.map(|it| it.1) }, syntax_ptr)
1081            }
1082            ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e),
1083            ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e),
1084            ast::Expr::CallExpr(e) => {
1085                // FIXME: Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c
1086                let is_rustc_box = {
1087                    let attrs = e.attrs();
1088                    attrs.filter_map(|it| it.as_simple_atom()).any(|it| it == "rustc_box")
1089                };
1090                if is_rustc_box {
1091                    let expr = self.collect_expr_opt(e.arg_list().and_then(|it| it.args().next()));
1092                    self.alloc_expr(Expr::Box { expr }, syntax_ptr)
1093                } else {
1094                    let callee = self.collect_expr_opt(e.expr());
1095                    let args = if let Some(arg_list) = e.arg_list() {
1096                        arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
1097                    } else {
1098                        Box::default()
1099                    };
1100                    self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)
1101                }
1102            }
1103            ast::Expr::MethodCallExpr(e) => {
1104                let receiver = self.collect_expr_opt(e.receiver());
1105                let args = if let Some(arg_list) = e.arg_list() {
1106                    arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()
1107                } else {
1108                    Box::default()
1109                };
1110                let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
1111                let generic_args = e
1112                    .generic_arg_list()
1113                    .and_then(|it| {
1114                        self.lower_generic_args(it, &mut Self::impl_trait_error_allocator)
1115                    })
1116                    .map(Box::new);
1117                self.alloc_expr(
1118                    Expr::MethodCall { receiver, method_name, args, generic_args },
1119                    syntax_ptr,
1120                )
1121            }
1122            ast::Expr::MatchExpr(e) => {
1123                let expr = self.collect_expr_opt(e.expr());
1124                let arms = if let Some(match_arm_list) = e.match_arm_list() {
1125                    match_arm_list
1126                        .arms()
1127                        .filter_map(|arm| {
1128                            if self.check_cfg(&arm) {
1129                                Some(MatchArm {
1130                                    pat: self.collect_pat_top(arm.pat()),
1131                                    expr: self.collect_expr_opt(arm.expr()),
1132                                    guard: arm
1133                                        .guard()
1134                                        .map(|guard| self.collect_expr_opt(guard.condition())),
1135                                })
1136                            } else {
1137                                None
1138                            }
1139                        })
1140                        .collect()
1141                } else {
1142                    Box::default()
1143                };
1144                self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
1145            }
1146            ast::Expr::PathExpr(e) => {
1147                let (path, hygiene) = self
1148                    .collect_expr_path(e)
1149                    .map(|(path, hygiene)| (Expr::Path(path), hygiene))
1150                    .unwrap_or((Expr::Missing, HygieneId::ROOT));
1151                let expr_id = self.alloc_expr(path, syntax_ptr);
1152                if !hygiene.is_root() {
1153                    self.store.ident_hygiene.insert(expr_id.into(), hygiene);
1154                }
1155                expr_id
1156            }
1157            ast::Expr::ContinueExpr(e) => {
1158                let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {
1159                    self.store.diagnostics.push(e);
1160                    None
1161                });
1162                self.alloc_expr(Expr::Continue { label }, syntax_ptr)
1163            }
1164            ast::Expr::BreakExpr(e) => {
1165                let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {
1166                    self.store.diagnostics.push(e);
1167                    None
1168                });
1169                let expr = e.expr().map(|e| self.collect_expr(e));
1170                self.alloc_expr(Expr::Break { expr, label }, syntax_ptr)
1171            }
1172            ast::Expr::ParenExpr(e) => {
1173                let inner = self.collect_expr_opt(e.expr());
1174                // make the paren expr point to the inner expression as well for IDE resolution
1175                let src = self.expander.in_file(syntax_ptr);
1176                self.store.expr_map.insert(src, inner.into());
1177                inner
1178            }
1179            ast::Expr::ReturnExpr(e) => {
1180                let expr = e.expr().map(|e| self.collect_expr(e));
1181                self.alloc_expr(Expr::Return { expr }, syntax_ptr)
1182            }
1183            ast::Expr::BecomeExpr(e) => {
1184                let expr =
1185                    e.expr().map(|e| self.collect_expr(e)).unwrap_or_else(|| self.missing_expr());
1186                self.alloc_expr(Expr::Become { expr }, syntax_ptr)
1187            }
1188            ast::Expr::YieldExpr(e) => {
1189                self.is_lowering_coroutine = true;
1190                let expr = e.expr().map(|e| self.collect_expr(e));
1191                self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
1192            }
1193            ast::Expr::YeetExpr(e) => {
1194                let expr = e.expr().map(|e| self.collect_expr(e));
1195                self.alloc_expr(Expr::Yeet { expr }, syntax_ptr)
1196            }
1197            ast::Expr::RecordExpr(e) => {
1198                let path = e
1199                    .path()
1200                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator))
1201                    .map(Box::new);
1202                let record_lit = if let Some(nfl) = e.record_expr_field_list() {
1203                    let fields = nfl
1204                        .fields()
1205                        .filter_map(|field| {
1206                            if !self.check_cfg(&field) {
1207                                return None;
1208                            }
1209
1210                            let name = field.field_name()?.as_name();
1211
1212                            let expr = match field.expr() {
1213                                Some(e) => self.collect_expr(e),
1214                                None => self.missing_expr(),
1215                            };
1216                            let src = self.expander.in_file(AstPtr::new(&field));
1217                            self.store.field_map_back.insert(expr, src);
1218                            Some(RecordLitField { name, expr })
1219                        })
1220                        .collect();
1221                    let spread = nfl.spread().map(|s| self.collect_expr(s));
1222                    Expr::RecordLit { path, fields, spread }
1223                } else {
1224                    Expr::RecordLit { path, fields: Box::default(), spread: None }
1225                };
1226
1227                self.alloc_expr(record_lit, syntax_ptr)
1228            }
1229            ast::Expr::FieldExpr(e) => {
1230                let expr = self.collect_expr_opt(e.expr());
1231                let name = match e.field_access() {
1232                    Some(kind) => kind.as_name(),
1233                    _ => Name::missing(),
1234                };
1235                self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)
1236            }
1237            ast::Expr::AwaitExpr(e) => {
1238                let expr = self.collect_expr_opt(e.expr());
1239                if let Awaitable::No(location) = self.is_lowering_awaitable_block() {
1240                    self.store.diagnostics.push(ExpressionStoreDiagnostics::AwaitOutsideOfAsync {
1241                        node: self.expander.in_file(AstPtr::new(&e)),
1242                        location: location.to_string(),
1243                    });
1244                }
1245                self.alloc_expr(Expr::Await { expr }, syntax_ptr)
1246            }
1247            ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e),
1248            ast::Expr::CastExpr(e) => {
1249                let expr = self.collect_expr_opt(e.expr());
1250                let type_ref = self.lower_type_ref_opt_disallow_impl_trait(e.ty());
1251                self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
1252            }
1253            ast::Expr::RefExpr(e) => {
1254                let expr = self.collect_expr_opt(e.expr());
1255                let raw_tok = e.raw_token().is_some();
1256                let mutability = if raw_tok {
1257                    if e.mut_token().is_some() { Mutability::Mut } else { Mutability::Shared }
1258                } else {
1259                    Mutability::from_mutable(e.mut_token().is_some())
1260                };
1261                let rawness = Rawness::from_raw(raw_tok);
1262                self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)
1263            }
1264            ast::Expr::PrefixExpr(e) => {
1265                let expr = self.collect_expr_opt(e.expr());
1266                match e.op_kind() {
1267                    Some(op) => self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr),
1268                    None => self.alloc_expr(Expr::Missing, syntax_ptr),
1269                }
1270            }
1271            ast::Expr::ClosureExpr(e) => self.with_label_rib(RibKind::Closure, |this| {
1272                let (result_expr_id, prev_binding_owner) =
1273                    this.initialize_binding_owner(syntax_ptr);
1274                let mut args = Vec::new();
1275                let mut arg_types = Vec::new();
1276                if let Some(pl) = e.param_list() {
1277                    let num_params = pl.params().count();
1278                    args.reserve_exact(num_params);
1279                    arg_types.reserve_exact(num_params);
1280                    for param in pl.params() {
1281                        let pat = this.collect_pat_top(param.pat());
1282                        let type_ref =
1283                            param.ty().map(|it| this.lower_type_ref_disallow_impl_trait(it));
1284                        args.push(pat);
1285                        arg_types.push(type_ref);
1286                    }
1287                }
1288                let ret_type = e
1289                    .ret_type()
1290                    .and_then(|r| r.ty())
1291                    .map(|it| this.lower_type_ref_disallow_impl_trait(it));
1292
1293                let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);
1294                let prev_try_block_label = this.current_try_block_label.take();
1295
1296                let awaitable = if e.async_token().is_some() {
1297                    Awaitable::Yes
1298                } else {
1299                    Awaitable::No("non-async closure")
1300                };
1301                let body =
1302                    this.with_awaitable_block(awaitable, |this| this.collect_expr_opt(e.body()));
1303
1304                let closure_kind = if this.is_lowering_coroutine {
1305                    let movability = if e.static_token().is_some() {
1306                        Movability::Static
1307                    } else {
1308                        Movability::Movable
1309                    };
1310                    ClosureKind::Coroutine(movability)
1311                } else if e.async_token().is_some() {
1312                    ClosureKind::Async
1313                } else {
1314                    ClosureKind::Closure
1315                };
1316                let capture_by =
1317                    if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };
1318                this.is_lowering_coroutine = prev_is_lowering_coroutine;
1319                this.current_binding_owner = prev_binding_owner;
1320                this.current_try_block_label = prev_try_block_label;
1321                this.store.exprs[result_expr_id] = Expr::Closure {
1322                    args: args.into(),
1323                    arg_types: arg_types.into(),
1324                    ret_type,
1325                    body,
1326                    closure_kind,
1327                    capture_by,
1328                };
1329                result_expr_id
1330            }),
1331            ast::Expr::BinExpr(e) => {
1332                let op = e.op_kind();
1333                if let Some(ast::BinaryOp::Assignment { op: None }) = op {
1334                    let target = self.collect_expr_as_pat_opt(e.lhs());
1335                    let value = self.collect_expr_opt(e.rhs());
1336                    self.alloc_expr(Expr::Assignment { target, value }, syntax_ptr)
1337                } else {
1338                    let lhs = self.collect_expr_opt(e.lhs());
1339                    let rhs = self.collect_expr_opt(e.rhs());
1340                    self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)
1341                }
1342            }
1343            ast::Expr::TupleExpr(e) => {
1344                let mut exprs: Vec<_> = e.fields().map(|expr| self.collect_expr(expr)).collect();
1345                // if there is a leading comma, the user is most likely to type out a leading expression
1346                // so we insert a missing expression at the beginning for IDE features
1347                if comma_follows_token(e.l_paren_token()) {
1348                    exprs.insert(0, self.missing_expr());
1349                }
1350
1351                self.alloc_expr(Expr::Tuple { exprs: exprs.into_boxed_slice() }, syntax_ptr)
1352            }
1353            ast::Expr::ArrayExpr(e) => {
1354                let kind = e.kind();
1355
1356                match kind {
1357                    ArrayExprKind::ElementList(e) => {
1358                        let elements = e.map(|expr| self.collect_expr(expr)).collect();
1359                        self.alloc_expr(Expr::Array(Array::ElementList { elements }), syntax_ptr)
1360                    }
1361                    ArrayExprKind::Repeat { initializer, repeat } => {
1362                        let initializer = self.collect_expr_opt(initializer);
1363                        let repeat = self.with_label_rib(RibKind::Constant, |this| {
1364                            if let Some(repeat) = repeat {
1365                                let syntax_ptr = AstPtr::new(&repeat);
1366                                this.collect_as_a_binding_owner_bad(
1367                                    |this| this.collect_expr(repeat),
1368                                    syntax_ptr,
1369                                )
1370                            } else {
1371                                this.missing_expr()
1372                            }
1373                        });
1374                        self.alloc_expr(
1375                            Expr::Array(Array::Repeat { initializer, repeat }),
1376                            syntax_ptr,
1377                        )
1378                    }
1379                }
1380            }
1381
1382            ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr),
1383            ast::Expr::IndexExpr(e) => {
1384                let base = self.collect_expr_opt(e.base());
1385                let index = self.collect_expr_opt(e.index());
1386                self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
1387            }
1388            ast::Expr::RangeExpr(e) => {
1389                let lhs = e.start().map(|lhs| self.collect_expr(lhs));
1390                let rhs = e.end().map(|rhs| self.collect_expr(rhs));
1391                match e.op_kind() {
1392                    Some(range_type) => {
1393                        self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)
1394                    }
1395                    None => self.alloc_expr(Expr::Missing, syntax_ptr),
1396                }
1397            }
1398            ast::Expr::MacroExpr(e) => {
1399                let e = e.macro_call()?;
1400                let macro_ptr = AstPtr::new(&e);
1401                let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
1402                    expansion.map(|it| this.collect_expr(it))
1403                });
1404                match id {
1405                    Some(id) => {
1406                        // Make the macro-call point to its expanded expression so we can query
1407                        // semantics on syntax pointers to the macro
1408                        let src = self.expander.in_file(syntax_ptr);
1409                        self.store.expr_map.insert(src, id.into());
1410                        id
1411                    }
1412                    None => self.alloc_expr(Expr::Missing, syntax_ptr),
1413                }
1414            }
1415            ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
1416            ast::Expr::AsmExpr(e) => self.lower_inline_asm(e, syntax_ptr),
1417            ast::Expr::OffsetOfExpr(e) => {
1418                let container = self.lower_type_ref_opt_disallow_impl_trait(e.ty());
1419                let fields = e.fields().map(|it| it.as_name()).collect();
1420                self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
1421            }
1422            ast::Expr::FormatArgsExpr(f) => self.collect_format_args(f, syntax_ptr),
1423        })
1424    }
1425
1426    fn collect_expr_path(&mut self, e: ast::PathExpr) -> Option<(Path, HygieneId)> {
1427        e.path().and_then(|path| {
1428            let path = self.lower_path(path, &mut Self::impl_trait_error_allocator)?;
1429            // Need to enable `mod_path.len() < 1` for `self`.
1430            let may_be_variable = matches!(&path, Path::BarePath(mod_path) if mod_path.len() <= 1);
1431            let hygiene = if may_be_variable {
1432                self.hygiene_id_for(e.syntax().text_range())
1433            } else {
1434                HygieneId::ROOT
1435            };
1436            Some((path, hygiene))
1437        })
1438    }
1439
1440    fn collect_expr_as_pat_opt(&mut self, expr: Option<ast::Expr>) -> PatId {
1441        match expr {
1442            Some(expr) => self.collect_expr_as_pat(expr),
1443            _ => self.missing_pat(),
1444        }
1445    }
1446
1447    fn collect_expr_as_pat(&mut self, expr: ast::Expr) -> PatId {
1448        self.maybe_collect_expr_as_pat(&expr).unwrap_or_else(|| {
1449            let src = self.expander.in_file(AstPtr::new(&expr).wrap_left());
1450            let expr = self.collect_expr(expr);
1451            // Do not use `alloc_pat_from_expr()` here, it will override the entry in `expr_map`.
1452            let id = self.store.pats.alloc(Pat::Expr(expr));
1453            self.store.pat_map_back.insert(id, src);
1454            id
1455        })
1456    }
1457
1458    fn maybe_collect_expr_as_pat(&mut self, expr: &ast::Expr) -> Option<PatId> {
1459        if !self.check_cfg(expr) {
1460            return None;
1461        }
1462        let syntax_ptr = AstPtr::new(expr);
1463
1464        let result = match expr {
1465            ast::Expr::UnderscoreExpr(_) => self.alloc_pat_from_expr(Pat::Wild, syntax_ptr),
1466            ast::Expr::ParenExpr(e) => {
1467                // We special-case `(..)` for consistency with patterns.
1468                if let Some(ast::Expr::RangeExpr(range)) = e.expr()
1469                    && range.is_range_full()
1470                {
1471                    return Some(self.alloc_pat_from_expr(
1472                        Pat::Tuple { args: Box::default(), ellipsis: Some(0) },
1473                        syntax_ptr,
1474                    ));
1475                }
1476                return e.expr().and_then(|expr| self.maybe_collect_expr_as_pat(&expr));
1477            }
1478            ast::Expr::TupleExpr(e) => {
1479                let (ellipsis, args) = collect_tuple(self, e.fields());
1480                self.alloc_pat_from_expr(Pat::Tuple { args, ellipsis }, syntax_ptr)
1481            }
1482            ast::Expr::ArrayExpr(e) => {
1483                if e.semicolon_token().is_some() {
1484                    return None;
1485                }
1486
1487                let mut elements = e.exprs();
1488                let prefix = elements
1489                    .by_ref()
1490                    .map_while(|elem| collect_possibly_rest(self, elem).left())
1491                    .collect();
1492                let suffix = elements.map(|elem| self.collect_expr_as_pat(elem)).collect();
1493                self.alloc_pat_from_expr(Pat::Slice { prefix, slice: None, suffix }, syntax_ptr)
1494            }
1495            ast::Expr::CallExpr(e) => {
1496                let path = collect_path(self, e.expr()?)?;
1497                let path = path
1498                    .path()
1499                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator))
1500                    .map(Box::new);
1501                let (ellipsis, args) = collect_tuple(self, e.arg_list()?.args());
1502                self.alloc_pat_from_expr(Pat::TupleStruct { path, args, ellipsis }, syntax_ptr)
1503            }
1504            ast::Expr::PathExpr(e) => {
1505                let (path, hygiene) = self
1506                    .collect_expr_path(e.clone())
1507                    .map(|(path, hygiene)| (Pat::Path(path), hygiene))
1508                    .unwrap_or((Pat::Missing, HygieneId::ROOT));
1509                let pat_id = self.alloc_pat_from_expr(path, syntax_ptr);
1510                if !hygiene.is_root() {
1511                    self.store.ident_hygiene.insert(pat_id.into(), hygiene);
1512                }
1513                pat_id
1514            }
1515            ast::Expr::MacroExpr(e) => {
1516                let e = e.macro_call()?;
1517                let macro_ptr = AstPtr::new(&e);
1518                let src = self.expander.in_file(AstPtr::new(expr));
1519                let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
1520                    this.collect_expr_as_pat_opt(expansion)
1521                });
1522                self.store.expr_map.insert(src, id.into());
1523                id
1524            }
1525            ast::Expr::RecordExpr(e) => {
1526                let path = e
1527                    .path()
1528                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator))
1529                    .map(Box::new);
1530                let record_field_list = e.record_expr_field_list()?;
1531                let ellipsis = record_field_list.dotdot_token().is_some();
1532                // FIXME: Report an error here if `record_field_list.spread().is_some()`.
1533                let args = record_field_list
1534                    .fields()
1535                    .filter_map(|f| {
1536                        if !self.check_cfg(&f) {
1537                            return None;
1538                        }
1539                        let field_expr = f.expr()?;
1540                        let pat = self.collect_expr_as_pat(field_expr);
1541                        let name = f.field_name()?.as_name();
1542                        let src = self.expander.in_file(AstPtr::new(&f).wrap_left());
1543                        self.store.pat_field_map_back.insert(pat, src);
1544                        Some(RecordFieldPat { name, pat })
1545                    })
1546                    .collect();
1547                self.alloc_pat_from_expr(Pat::Record { path, args, ellipsis }, syntax_ptr)
1548            }
1549            _ => return None,
1550        };
1551        return Some(result);
1552
1553        fn collect_path(this: &mut ExprCollector<'_>, expr: ast::Expr) -> Option<ast::PathExpr> {
1554            match expr {
1555                ast::Expr::PathExpr(e) => Some(e),
1556                ast::Expr::MacroExpr(mac) => {
1557                    let call = mac.macro_call()?;
1558                    {
1559                        let macro_ptr = AstPtr::new(&call);
1560                        this.collect_macro_call(call, macro_ptr, true, |this, expanded_path| {
1561                            collect_path(this, expanded_path?)
1562                        })
1563                    }
1564                }
1565                _ => None,
1566            }
1567        }
1568
1569        fn collect_possibly_rest(
1570            this: &mut ExprCollector<'_>,
1571            expr: ast::Expr,
1572        ) -> Either<PatId, ()> {
1573            match &expr {
1574                ast::Expr::RangeExpr(e) if e.is_range_full() => Either::Right(()),
1575                ast::Expr::MacroExpr(mac) => match mac.macro_call() {
1576                    Some(call) => {
1577                        let macro_ptr = AstPtr::new(&call);
1578                        let pat = this.collect_macro_call(
1579                            call,
1580                            macro_ptr,
1581                            true,
1582                            |this, expanded_expr| match expanded_expr {
1583                                Some(expanded_pat) => collect_possibly_rest(this, expanded_pat),
1584                                None => Either::Left(this.missing_pat()),
1585                            },
1586                        );
1587                        if let Either::Left(pat) = pat {
1588                            let src = this.expander.in_file(AstPtr::new(&expr).wrap_left());
1589                            this.store.pat_map_back.insert(pat, src);
1590                        }
1591                        pat
1592                    }
1593                    None => {
1594                        let ptr = AstPtr::new(&expr);
1595                        Either::Left(this.alloc_pat_from_expr(Pat::Missing, ptr))
1596                    }
1597                },
1598                _ => Either::Left(this.collect_expr_as_pat(expr)),
1599            }
1600        }
1601
1602        fn collect_tuple(
1603            this: &mut ExprCollector<'_>,
1604            fields: ast::AstChildren<ast::Expr>,
1605        ) -> (Option<u32>, Box<[la_arena::Idx<Pat>]>) {
1606            let mut ellipsis = None;
1607            let args = fields
1608                .enumerate()
1609                .filter_map(|(idx, elem)| {
1610                    match collect_possibly_rest(this, elem) {
1611                        Either::Left(pat) => Some(pat),
1612                        Either::Right(()) => {
1613                            if ellipsis.is_none() {
1614                                ellipsis = Some(idx as u32);
1615                            }
1616                            // FIXME: Report an error here otherwise.
1617                            None
1618                        }
1619                    }
1620                })
1621                .collect();
1622            (ellipsis, args)
1623        }
1624    }
1625
1626    fn initialize_binding_owner(
1627        &mut self,
1628        syntax_ptr: AstPtr<ast::Expr>,
1629    ) -> (ExprId, Option<ExprId>) {
1630        let result_expr_id = self.alloc_expr(Expr::Missing, syntax_ptr);
1631        let prev_binding_owner = self.current_binding_owner.take();
1632        self.current_binding_owner = Some(result_expr_id);
1633
1634        (result_expr_id, prev_binding_owner)
1635    }
1636
1637    /// FIXME: This function is bad. It will produce a dangling `Missing` expr which wastes memory. Currently
1638    /// it is used only for const blocks and repeat expressions, which are also hacky and ideally should have
1639    /// their own body. Don't add more usage for this function so that we can remove this function after
1640    /// separating those bodies.
1641    fn collect_as_a_binding_owner_bad(
1642        &mut self,
1643        job: impl FnOnce(&mut ExprCollector<'_>) -> ExprId,
1644        syntax_ptr: AstPtr<ast::Expr>,
1645    ) -> ExprId {
1646        let (id, prev_owner) = self.initialize_binding_owner(syntax_ptr);
1647        let tmp = job(self);
1648        self.store.exprs[id] = mem::replace(&mut self.store.exprs[tmp], Expr::Missing);
1649        self.current_binding_owner = prev_owner;
1650        id
1651    }
1652
1653    /// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`,
1654    /// `try { <stmts>; }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(()) }`
1655    /// and save the `<new_label>` to use it as a break target for desugaring of the `?` operator.
1656    fn desugar_try_block(&mut self, e: BlockExpr) -> ExprId {
1657        let try_from_output = self.lang_path(LangItem::TryTraitFromOutput);
1658        let label = self.alloc_label_desugared(Label {
1659            name: Name::generate_new_name(self.store.labels.len()),
1660        });
1661        let old_label = self.current_try_block_label.replace(label);
1662
1663        let ptr = AstPtr::new(&e).upcast();
1664        let (btail, expr_id) = self.with_labeled_rib(label, HygieneId::ROOT, |this| {
1665            let mut btail = None;
1666            let block = this.collect_block_(e, |id, statements, tail| {
1667                btail = tail;
1668                Expr::Block { id, statements, tail, label: Some(label) }
1669            });
1670            (btail, block)
1671        });
1672
1673        let callee = self
1674            .alloc_expr_desugared_with_ptr(try_from_output.map_or(Expr::Missing, Expr::Path), ptr);
1675        let next_tail = match btail {
1676            Some(tail) => self
1677                .alloc_expr_desugared_with_ptr(Expr::Call { callee, args: Box::new([tail]) }, ptr),
1678            None => {
1679                let unit =
1680                    self.alloc_expr_desugared_with_ptr(Expr::Tuple { exprs: Box::new([]) }, ptr);
1681                self.alloc_expr_desugared_with_ptr(
1682                    Expr::Call { callee, args: Box::new([unit]) },
1683                    ptr,
1684                )
1685            }
1686        };
1687        let Expr::Block { tail, .. } = &mut self.store.exprs[expr_id] else {
1688            unreachable!("block was lowered to non-block");
1689        };
1690        *tail = Some(next_tail);
1691        self.current_try_block_label = old_label;
1692        expr_id
1693    }
1694
1695    /// Desugar `ast::WhileExpr` from: `[opt_ident]: while <cond> <body>` into:
1696    /// ```ignore (pseudo-rust)
1697    /// [opt_ident]: loop {
1698    ///   if <cond> {
1699    ///     <body>
1700    ///   }
1701    ///   else {
1702    ///     break;
1703    ///   }
1704    /// }
1705    /// ```
1706    /// FIXME: Rustc wraps the condition in a construct equivalent to `{ let _t = <cond>; _t }`
1707    /// to preserve drop semantics. We should probably do the same in future.
1708    fn collect_while_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::WhileExpr) -> ExprId {
1709        let label = e.label().map(|label| {
1710            (self.hygiene_id_for(label.syntax().text_range()), self.collect_label(label))
1711        });
1712        let body = self.collect_labelled_block_opt(label, e.loop_body());
1713
1714        // Labels can also be used in the condition expression, like this:
1715        // ```
1716        // fn main() {
1717        //     let mut optional = Some(0);
1718        //     'my_label: while let Some(a) = match optional {
1719        //         None => break 'my_label,
1720        //         Some(val) => Some(val),
1721        //     } {
1722        //         println!("{}", a);
1723        //         optional = None;
1724        //     }
1725        // }
1726        // ```
1727        let condition = match label {
1728            Some((label_hygiene, label)) => self.with_labeled_rib(label, label_hygiene, |this| {
1729                this.collect_expr_opt(e.condition())
1730            }),
1731            None => self.collect_expr_opt(e.condition()),
1732        };
1733
1734        let break_expr = self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr);
1735        let if_expr = self.alloc_expr(
1736            Expr::If { condition, then_branch: body, else_branch: Some(break_expr) },
1737            syntax_ptr,
1738        );
1739        self.alloc_expr(Expr::Loop { body: if_expr, label: label.map(|it| it.1) }, syntax_ptr)
1740    }
1741
1742    /// Desugar `ast::ForExpr` from: `[opt_ident]: for <pat> in <head> <body>` into:
1743    /// ```ignore (pseudo-rust)
1744    /// match IntoIterator::into_iter(<head>) {
1745    ///     mut iter => {
1746    ///         [opt_ident]: loop {
1747    ///             match Iterator::next(&mut iter) {
1748    ///                 None => break,
1749    ///                 Some(<pat>) => <body>,
1750    ///             };
1751    ///         }
1752    ///     }
1753    /// }
1754    /// ```
1755    fn collect_for_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::ForExpr) -> ExprId {
1756        let into_iter_fn = self.lang_path(LangItem::IntoIterIntoIter);
1757        let iter_next_fn = self.lang_path(LangItem::IteratorNext);
1758        let option_some = self.lang_path(LangItem::OptionSome);
1759        let option_none = self.lang_path(LangItem::OptionNone);
1760        let head = self.collect_expr_opt(e.iterable());
1761        let into_iter_fn_expr =
1762            self.alloc_expr(into_iter_fn.map_or(Expr::Missing, Expr::Path), syntax_ptr);
1763        let iterator = self.alloc_expr(
1764            Expr::Call { callee: into_iter_fn_expr, args: Box::new([head]) },
1765            syntax_ptr,
1766        );
1767        let none_arm = MatchArm {
1768            pat: self.alloc_pat_desugared(option_none.map_or(Pat::Missing, Pat::Path)),
1769            guard: None,
1770            expr: self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr),
1771        };
1772        let some_pat = Pat::TupleStruct {
1773            path: option_some.map(Box::new),
1774            args: Box::new([self.collect_pat_top(e.pat())]),
1775            ellipsis: None,
1776        };
1777        let label = e.label().map(|label| {
1778            (self.hygiene_id_for(label.syntax().text_range()), self.collect_label(label))
1779        });
1780        let some_arm = MatchArm {
1781            pat: self.alloc_pat_desugared(some_pat),
1782            guard: None,
1783            expr: self.with_opt_labeled_rib(label, |this| {
1784                this.collect_expr_opt(e.loop_body().map(|it| it.into()))
1785            }),
1786        };
1787        let iter_name = Name::generate_new_name(self.store.exprs.len());
1788        let iter_expr = self.alloc_expr(Expr::Path(Path::from(iter_name.clone())), syntax_ptr);
1789        let iter_expr_mut = self.alloc_expr(
1790            Expr::Ref { expr: iter_expr, rawness: Rawness::Ref, mutability: Mutability::Mut },
1791            syntax_ptr,
1792        );
1793        let iter_next_fn_expr =
1794            self.alloc_expr(iter_next_fn.map_or(Expr::Missing, Expr::Path), syntax_ptr);
1795        let iter_next_expr = self.alloc_expr(
1796            Expr::Call { callee: iter_next_fn_expr, args: Box::new([iter_expr_mut]) },
1797            syntax_ptr,
1798        );
1799        let loop_inner = self.alloc_expr(
1800            Expr::Match { expr: iter_next_expr, arms: Box::new([none_arm, some_arm]) },
1801            syntax_ptr,
1802        );
1803        let loop_inner = self.alloc_expr(
1804            Expr::Block {
1805                id: None,
1806                statements: Box::default(),
1807                tail: Some(loop_inner),
1808                label: None,
1809            },
1810            syntax_ptr,
1811        );
1812        let loop_outer = self
1813            .alloc_expr(Expr::Loop { body: loop_inner, label: label.map(|it| it.1) }, syntax_ptr);
1814        let iter_binding =
1815            self.alloc_binding(iter_name, BindingAnnotation::Mutable, HygieneId::ROOT);
1816        let iter_pat = self.alloc_pat_desugared(Pat::Bind { id: iter_binding, subpat: None });
1817        self.add_definition_to_binding(iter_binding, iter_pat);
1818        self.alloc_expr(
1819            Expr::Match {
1820                expr: iterator,
1821                arms: Box::new([MatchArm { pat: iter_pat, guard: None, expr: loop_outer }]),
1822            },
1823            syntax_ptr,
1824        )
1825    }
1826
1827    /// Desugar `ast::TryExpr` from: `<expr>?` into:
1828    /// ```ignore (pseudo-rust)
1829    /// match Try::branch(<expr>) {
1830    ///     ControlFlow::Continue(val) => val,
1831    ///     ControlFlow::Break(residual) =>
1832    ///         // If there is an enclosing `try {...}`:
1833    ///         break 'catch_target Try::from_residual(residual),
1834    ///         // Otherwise:
1835    ///         return Try::from_residual(residual),
1836    /// }
1837    /// ```
1838    fn collect_try_operator(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::TryExpr) -> ExprId {
1839        let try_branch = self.lang_path(LangItem::TryTraitBranch);
1840        let cf_continue = self.lang_path(LangItem::ControlFlowContinue);
1841        let cf_break = self.lang_path(LangItem::ControlFlowBreak);
1842        let try_from_residual = self.lang_path(LangItem::TryTraitFromResidual);
1843        let operand = self.collect_expr_opt(e.expr());
1844        let try_branch = self.alloc_expr(try_branch.map_or(Expr::Missing, Expr::Path), syntax_ptr);
1845        let expr = self
1846            .alloc_expr(Expr::Call { callee: try_branch, args: Box::new([operand]) }, syntax_ptr);
1847        let continue_name = Name::generate_new_name(self.store.bindings.len());
1848        let continue_binding = self.alloc_binding(
1849            continue_name.clone(),
1850            BindingAnnotation::Unannotated,
1851            HygieneId::ROOT,
1852        );
1853        let continue_bpat =
1854            self.alloc_pat_desugared(Pat::Bind { id: continue_binding, subpat: None });
1855        self.add_definition_to_binding(continue_binding, continue_bpat);
1856        let continue_arm = MatchArm {
1857            pat: self.alloc_pat_desugared(Pat::TupleStruct {
1858                path: cf_continue.map(Box::new),
1859                args: Box::new([continue_bpat]),
1860                ellipsis: None,
1861            }),
1862            guard: None,
1863            expr: self.alloc_expr(Expr::Path(Path::from(continue_name)), syntax_ptr),
1864        };
1865        let break_name = Name::generate_new_name(self.store.bindings.len());
1866        let break_binding =
1867            self.alloc_binding(break_name.clone(), BindingAnnotation::Unannotated, HygieneId::ROOT);
1868        let break_bpat = self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None });
1869        self.add_definition_to_binding(break_binding, break_bpat);
1870        let break_arm = MatchArm {
1871            pat: self.alloc_pat_desugared(Pat::TupleStruct {
1872                path: cf_break.map(Box::new),
1873                args: Box::new([break_bpat]),
1874                ellipsis: None,
1875            }),
1876            guard: None,
1877            expr: {
1878                let it = self.alloc_expr(Expr::Path(Path::from(break_name)), syntax_ptr);
1879                let callee = self
1880                    .alloc_expr(try_from_residual.map_or(Expr::Missing, Expr::Path), syntax_ptr);
1881                let result =
1882                    self.alloc_expr(Expr::Call { callee, args: Box::new([it]) }, syntax_ptr);
1883                self.alloc_expr(
1884                    match self.current_try_block_label {
1885                        Some(label) => Expr::Break { expr: Some(result), label: Some(label) },
1886                        None => Expr::Return { expr: Some(result) },
1887                    },
1888                    syntax_ptr,
1889                )
1890            },
1891        };
1892        let arms = Box::new([continue_arm, break_arm]);
1893        self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)
1894    }
1895
1896    fn collect_macro_call<T, U>(
1897        &mut self,
1898        mcall: ast::MacroCall,
1899        syntax_ptr: AstPtr<ast::MacroCall>,
1900        record_diagnostics: bool,
1901        collector: impl FnOnce(&mut Self, Option<T>) -> U,
1902    ) -> U
1903    where
1904        T: ast::AstNode,
1905    {
1906        let macro_call_ptr = self.expander.in_file(syntax_ptr);
1907        let module = self.module.local_id;
1908
1909        let block_call = self.def_map.modules[self.module.local_id].scope.macro_invoc(
1910            self.expander.in_file(self.expander.ast_id_map().ast_id_for_ptr(syntax_ptr)),
1911        );
1912        let res = match block_call {
1913            // fast path, macro call is in a block module
1914            Some(call) => Ok(self.expander.enter_expand_id(self.db, call)),
1915            None => {
1916                let resolver = |path: &_| {
1917                    self.def_map
1918                        .resolve_path(
1919                            self.local_def_map,
1920                            self.db,
1921                            module,
1922                            path,
1923                            crate::item_scope::BuiltinShadowMode::Other,
1924                            Some(MacroSubNs::Bang),
1925                        )
1926                        .0
1927                        .take_macros()
1928                };
1929                self.expander.enter_expand(
1930                    self.db,
1931                    mcall,
1932                    self.module.krate(),
1933                    resolver,
1934                    &mut |ptr, call| {
1935                        _ = self.store.expansions.insert(ptr.map(|(it, _)| it), call);
1936                    },
1937                )
1938            }
1939        };
1940
1941        let res = match res {
1942            Ok(res) => res,
1943            Err(UnresolvedMacro { path }) => {
1944                if record_diagnostics {
1945                    self.store.diagnostics.push(ExpressionStoreDiagnostics::UnresolvedMacroCall {
1946                        node: self.expander.in_file(syntax_ptr),
1947                        path,
1948                    });
1949                }
1950                return collector(self, None);
1951            }
1952        };
1953        // No need to push macro and parsing errors as they'll be recreated from `macro_calls()`.
1954
1955        match res.value {
1956            Some((mark, expansion)) => {
1957                // Keep collecting even with expansion errors so we can provide completions and
1958                // other services in incomplete macro expressions.
1959                if let Some(macro_file) = self.expander.current_file_id().macro_file() {
1960                    self.store.expansions.insert(macro_call_ptr, macro_file);
1961                }
1962
1963                let id = collector(self, expansion.map(|it| it.tree()));
1964                self.expander.exit(mark);
1965                id
1966            }
1967            None => collector(self, None),
1968        }
1969    }
1970
1971    fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
1972        match expr {
1973            Some(expr) => self.collect_expr(expr),
1974            None => self.missing_expr(),
1975        }
1976    }
1977
1978    fn collect_macro_as_stmt(
1979        &mut self,
1980        statements: &mut Vec<Statement>,
1981        mac: ast::MacroExpr,
1982    ) -> Option<ExprId> {
1983        let mac_call = mac.macro_call()?;
1984        let syntax_ptr = AstPtr::new(&ast::Expr::from(mac));
1985        let macro_ptr = AstPtr::new(&mac_call);
1986        let expansion = self.collect_macro_call(
1987            mac_call,
1988            macro_ptr,
1989            false,
1990            |this, expansion: Option<ast::MacroStmts>| match expansion {
1991                Some(expansion) => {
1992                    expansion.statements().for_each(|stmt| this.collect_stmt(statements, stmt));
1993                    expansion.expr().and_then(|expr| match expr {
1994                        ast::Expr::MacroExpr(mac) => this.collect_macro_as_stmt(statements, mac),
1995                        expr => Some(this.collect_expr(expr)),
1996                    })
1997                }
1998                None => None,
1999            },
2000        );
2001        expansion.inspect(|&tail| {
2002            // Make the macro-call point to its expanded expression so we can query
2003            // semantics on syntax pointers to the macro
2004            let src = self.expander.in_file(syntax_ptr);
2005            self.store.expr_map.insert(src, tail.into());
2006        })
2007    }
2008
2009    fn collect_stmt(&mut self, statements: &mut Vec<Statement>, s: ast::Stmt) {
2010        match s {
2011            ast::Stmt::LetStmt(stmt) => {
2012                if !self.check_cfg(&stmt) {
2013                    return;
2014                }
2015                let pat = self.collect_pat_top(stmt.pat());
2016                let type_ref = stmt.ty().map(|it| self.lower_type_ref_disallow_impl_trait(it));
2017                let initializer = stmt.initializer().map(|e| self.collect_expr(e));
2018                let else_branch = stmt
2019                    .let_else()
2020                    .and_then(|let_else| let_else.block_expr())
2021                    .map(|block| self.collect_block(block));
2022                statements.push(Statement::Let { pat, type_ref, initializer, else_branch });
2023            }
2024            ast::Stmt::ExprStmt(stmt) => {
2025                let expr = stmt.expr();
2026                match &expr {
2027                    Some(expr) if !self.check_cfg(expr) => return,
2028                    _ => (),
2029                }
2030                let has_semi = stmt.semicolon_token().is_some();
2031                // Note that macro could be expanded to multiple statements
2032                if let Some(ast::Expr::MacroExpr(mac)) = expr {
2033                    if let Some(expr) = self.collect_macro_as_stmt(statements, mac) {
2034                        statements.push(Statement::Expr { expr, has_semi })
2035                    }
2036                } else {
2037                    let expr = self.collect_expr_opt(expr);
2038                    statements.push(Statement::Expr { expr, has_semi });
2039                }
2040            }
2041            ast::Stmt::Item(ast::Item::MacroDef(macro_)) => {
2042                if !self.check_cfg(&macro_) {
2043                    return;
2044                }
2045                let Some(name) = macro_.name() else {
2046                    statements.push(Statement::Item(Item::Other));
2047                    return;
2048                };
2049                let name = name.as_name();
2050                let macro_id = self.def_map.modules[DefMap::ROOT].scope.get(&name).take_macros();
2051                self.collect_macro_def(statements, macro_id);
2052            }
2053            ast::Stmt::Item(ast::Item::MacroRules(macro_)) => {
2054                if !self.check_cfg(&macro_) {
2055                    return;
2056                }
2057                let Some(name) = macro_.name() else {
2058                    statements.push(Statement::Item(Item::Other));
2059                    return;
2060                };
2061                let name = name.as_name();
2062                let macro_defs_count =
2063                    self.current_block_legacy_macro_defs_count.entry(name.clone()).or_insert(0);
2064                let macro_id = self.def_map.modules[DefMap::ROOT]
2065                    .scope
2066                    .get_legacy_macro(&name)
2067                    .and_then(|it| it.get(*macro_defs_count))
2068                    .copied();
2069                *macro_defs_count += 1;
2070                self.collect_macro_def(statements, macro_id);
2071            }
2072            ast::Stmt::Item(_item) => statements.push(Statement::Item(Item::Other)),
2073        }
2074    }
2075
2076    fn collect_macro_def(&mut self, statements: &mut Vec<Statement>, macro_id: Option<MacroId>) {
2077        let Some(macro_id) = macro_id else {
2078            never!("def map should have macro definition, but it doesn't");
2079            statements.push(Statement::Item(Item::Other));
2080            return;
2081        };
2082        let macro_id = self.db.macro_def(macro_id);
2083        statements.push(Statement::Item(Item::MacroDef(Box::new(macro_id))));
2084        self.label_ribs.push(LabelRib::new(RibKind::MacroDef(Box::new(macro_id))));
2085    }
2086
2087    fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId {
2088        self.collect_block_(block, |id, statements, tail| Expr::Block {
2089            id,
2090            statements,
2091            tail,
2092            label: None,
2093        })
2094    }
2095
2096    fn collect_block_(
2097        &mut self,
2098        block: ast::BlockExpr,
2099        mk_block: impl FnOnce(Option<BlockId>, Box<[Statement]>, Option<ExprId>) -> Expr,
2100    ) -> ExprId {
2101        let block_id = self.expander.ast_id_map().ast_id_for_block(&block).map(|file_local_id| {
2102            let ast_id = self.expander.in_file(file_local_id);
2103            self.db.intern_block(BlockLoc { ast_id, module: self.module })
2104        });
2105
2106        let (module, def_map) =
2107            match block_id.map(|block_id| (block_def_map(self.db, block_id), block_id)) {
2108                Some((def_map, block_id)) => {
2109                    self.store.block_scopes.push(block_id);
2110                    (def_map.module_id(DefMap::ROOT), def_map)
2111                }
2112                None => (self.module, self.def_map),
2113            };
2114        let prev_def_map = mem::replace(&mut self.def_map, def_map);
2115        let prev_local_module = mem::replace(&mut self.module, module);
2116        let prev_legacy_macros_count = mem::take(&mut self.current_block_legacy_macro_defs_count);
2117
2118        let mut statements = Vec::new();
2119        block.statements().for_each(|s| self.collect_stmt(&mut statements, s));
2120        let tail = block.tail_expr().and_then(|e| match e {
2121            ast::Expr::MacroExpr(mac) => self.collect_macro_as_stmt(&mut statements, mac),
2122            expr => self.maybe_collect_expr(expr),
2123        });
2124        let tail = tail.or_else(|| {
2125            let stmt = statements.pop()?;
2126            if let Statement::Expr { expr, has_semi: false } = stmt {
2127                return Some(expr);
2128            }
2129            statements.push(stmt);
2130            None
2131        });
2132
2133        let syntax_node_ptr = AstPtr::new(&block.into());
2134        let expr_id = self
2135            .alloc_expr(mk_block(block_id, statements.into_boxed_slice(), tail), syntax_node_ptr);
2136
2137        self.def_map = prev_def_map;
2138        self.module = prev_local_module;
2139        self.current_block_legacy_macro_defs_count = prev_legacy_macros_count;
2140        expr_id
2141    }
2142
2143    fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
2144        match expr {
2145            Some(block) => self.collect_block(block),
2146            None => self.missing_expr(),
2147        }
2148    }
2149
2150    fn collect_labelled_block_opt(
2151        &mut self,
2152        label: Option<(HygieneId, LabelId)>,
2153        expr: Option<ast::BlockExpr>,
2154    ) -> ExprId {
2155        match label {
2156            Some((hygiene, label)) => {
2157                self.with_labeled_rib(label, hygiene, |this| this.collect_block_opt(expr))
2158            }
2159            None => self.collect_block_opt(expr),
2160        }
2161    }
2162
2163    // region: patterns
2164
2165    fn collect_pat_top(&mut self, pat: Option<ast::Pat>) -> PatId {
2166        match pat {
2167            Some(pat) => self.collect_pat(pat, &mut BindingList::default()),
2168            None => self.missing_pat(),
2169        }
2170    }
2171
2172    fn collect_pat(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatId {
2173        let pattern = match &pat {
2174            ast::Pat::IdentPat(bp) => {
2175                let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
2176                let hygiene = bp
2177                    .name()
2178                    .map(|name| self.hygiene_id_for(name.syntax().text_range()))
2179                    .unwrap_or(HygieneId::ROOT);
2180
2181                let annotation =
2182                    BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some());
2183                let subpat = bp.pat().map(|subpat| self.collect_pat(subpat, binding_list));
2184
2185                let is_simple_ident_pat =
2186                    annotation == BindingAnnotation::Unannotated && subpat.is_none();
2187                let (binding, pattern) = if is_simple_ident_pat {
2188                    // This could also be a single-segment path pattern. To
2189                    // decide that, we need to try resolving the name.
2190                    let (resolved, _) = self.def_map.resolve_path(
2191                        self.local_def_map,
2192                        self.db,
2193                        self.module.local_id,
2194                        &name.clone().into(),
2195                        BuiltinShadowMode::Other,
2196                        None,
2197                    );
2198                    // Funnily enough, record structs/variants *can* be shadowed
2199                    // by pattern bindings (but unit or tuple structs/variants
2200                    // can't).
2201                    match resolved.take_values() {
2202                        Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())),
2203                        Some(ModuleDefId::EnumVariantId(variant))
2204                        // FIXME: This can cause a cycle if the user is writing invalid code
2205                            if variant.fields(self.db).shape != FieldsShape::Record =>
2206                        {
2207                            (None, Pat::Path(name.into()))
2208                        }
2209                        Some(ModuleDefId::AdtId(AdtId::StructId(s)))
2210                        // FIXME: This can cause a cycle if the user is writing invalid code
2211                            if self.db.struct_signature(s).shape != FieldsShape::Record =>
2212                        {
2213                            (None, Pat::Path(name.into()))
2214                        }
2215                        // shadowing statics is an error as well, so we just ignore that case here
2216                        _ => {
2217                            let id = binding_list.find(self, name, hygiene, annotation);
2218                            (Some(id), Pat::Bind { id, subpat })
2219                        }
2220                    }
2221                } else {
2222                    let id = binding_list.find(self, name, hygiene, annotation);
2223                    (Some(id), Pat::Bind { id, subpat })
2224                };
2225
2226                let ptr = AstPtr::new(&pat);
2227                let pat = self.alloc_pat(pattern, ptr);
2228                if let Some(binding_id) = binding {
2229                    self.add_definition_to_binding(binding_id, pat);
2230                }
2231                return pat;
2232            }
2233            ast::Pat::TupleStructPat(p) => {
2234                let path = p
2235                    .path()
2236                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator))
2237                    .map(Box::new);
2238                let (args, ellipsis) = self.collect_tuple_pat(
2239                    p.fields(),
2240                    comma_follows_token(p.l_paren_token()),
2241                    binding_list,
2242                );
2243                Pat::TupleStruct { path, args, ellipsis }
2244            }
2245            ast::Pat::RefPat(p) => {
2246                let pat = self.collect_pat_opt(p.pat(), binding_list);
2247                let mutability = Mutability::from_mutable(p.mut_token().is_some());
2248                Pat::Ref { pat, mutability }
2249            }
2250            ast::Pat::PathPat(p) => {
2251                let path = p
2252                    .path()
2253                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator));
2254                path.map(Pat::Path).unwrap_or(Pat::Missing)
2255            }
2256            ast::Pat::OrPat(p) => 'b: {
2257                let prev_is_used = mem::take(&mut binding_list.is_used);
2258                let prev_reject_new = mem::take(&mut binding_list.reject_new);
2259                let mut pats = Vec::with_capacity(p.pats().count());
2260                let mut it = p.pats();
2261                let Some(first) = it.next() else {
2262                    break 'b Pat::Or(Box::new([]));
2263                };
2264                pats.push(self.collect_pat(first, binding_list));
2265                binding_list.reject_new = true;
2266                for rest in it {
2267                    for (_, it) in binding_list.is_used.iter_mut() {
2268                        *it = false;
2269                    }
2270                    pats.push(self.collect_pat(rest, binding_list));
2271                    for (&id, &is_used) in binding_list.is_used.iter() {
2272                        if !is_used {
2273                            self.store.bindings[id].problems =
2274                                Some(BindingProblems::NotBoundAcrossAll);
2275                        }
2276                    }
2277                }
2278                binding_list.reject_new = prev_reject_new;
2279                let current_is_used = mem::replace(&mut binding_list.is_used, prev_is_used);
2280                for (id, _) in current_is_used.into_iter() {
2281                    binding_list.check_is_used(self, id);
2282                }
2283                if let &[pat] = &*pats {
2284                    // Leading pipe without real OR pattern. Leaving an one-item OR pattern may confuse later stages.
2285                    return pat;
2286                }
2287                Pat::Or(pats.into())
2288            }
2289            ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat(), binding_list),
2290            ast::Pat::TuplePat(p) => {
2291                let (args, ellipsis) = self.collect_tuple_pat(
2292                    p.fields(),
2293                    comma_follows_token(p.l_paren_token()),
2294                    binding_list,
2295                );
2296                Pat::Tuple { args, ellipsis }
2297            }
2298            ast::Pat::WildcardPat(_) => Pat::Wild,
2299            ast::Pat::RecordPat(p) => {
2300                let path = p
2301                    .path()
2302                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator))
2303                    .map(Box::new);
2304                let record_pat_field_list =
2305                    &p.record_pat_field_list().expect("every struct should have a field list");
2306                let args = record_pat_field_list
2307                    .fields()
2308                    .filter_map(|f| {
2309                        if !self.check_cfg(&f) {
2310                            return None;
2311                        }
2312                        let ast_pat = f.pat()?;
2313                        let pat = self.collect_pat(ast_pat, binding_list);
2314                        let name = f.field_name()?.as_name();
2315                        let src = self.expander.in_file(AstPtr::new(&f).wrap_right());
2316                        self.store.pat_field_map_back.insert(pat, src);
2317                        Some(RecordFieldPat { name, pat })
2318                    })
2319                    .collect();
2320
2321                let ellipsis = record_pat_field_list.rest_pat().is_some();
2322
2323                Pat::Record { path, args, ellipsis }
2324            }
2325            ast::Pat::SlicePat(p) => {
2326                let SlicePatComponents { prefix, slice, suffix } = p.components();
2327
2328                // FIXME properly handle `RestPat`
2329                Pat::Slice {
2330                    prefix: prefix.into_iter().map(|p| self.collect_pat(p, binding_list)).collect(),
2331                    slice: slice.map(|p| self.collect_pat(p, binding_list)),
2332                    suffix: suffix.into_iter().map(|p| self.collect_pat(p, binding_list)).collect(),
2333                }
2334            }
2335            ast::Pat::LiteralPat(lit) => 'b: {
2336                let Some((hir_lit, ast_lit)) = pat_literal_to_hir(lit) else {
2337                    break 'b Pat::Missing;
2338                };
2339                let expr = Expr::Literal(hir_lit);
2340                let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
2341                let expr_id = self.alloc_expr(expr, expr_ptr);
2342                Pat::Lit(expr_id)
2343            }
2344            ast::Pat::RestPat(_) => {
2345                // `RestPat` requires special handling and should not be mapped
2346                // to a Pat. Here we are using `Pat::Missing` as a fallback for
2347                // when `RestPat` is mapped to `Pat`, which can easily happen
2348                // when the source code being analyzed has a malformed pattern
2349                // which includes `..` in a place where it isn't valid.
2350
2351                Pat::Missing
2352            }
2353            ast::Pat::BoxPat(boxpat) => {
2354                let inner = self.collect_pat_opt(boxpat.pat(), binding_list);
2355                Pat::Box { inner }
2356            }
2357            ast::Pat::ConstBlockPat(const_block_pat) => {
2358                if let Some(block) = const_block_pat.block_expr() {
2359                    let expr_id = self.with_label_rib(RibKind::Constant, |this| {
2360                        let syntax_ptr = AstPtr::new(&block.clone().into());
2361                        this.collect_as_a_binding_owner_bad(
2362                            |this| this.collect_block(block),
2363                            syntax_ptr,
2364                        )
2365                    });
2366                    Pat::ConstBlock(expr_id)
2367                } else {
2368                    Pat::Missing
2369                }
2370            }
2371            ast::Pat::MacroPat(mac) => match mac.macro_call() {
2372                Some(call) => {
2373                    let macro_ptr = AstPtr::new(&call);
2374                    let src = self.expander.in_file(AstPtr::new(&pat));
2375                    let pat =
2376                        self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
2377                            this.collect_pat_opt(expanded_pat, binding_list)
2378                        });
2379                    self.store.pat_map.insert(src, pat.into());
2380                    return pat;
2381                }
2382                None => Pat::Missing,
2383            },
2384            ast::Pat::RangePat(p) => {
2385                let mut range_part_lower = |p: Option<ast::Pat>| -> Option<ExprId> {
2386                    p.and_then(|it| {
2387                        let ptr = PatPtr::new(&it);
2388                        match &it {
2389                            ast::Pat::LiteralPat(it) => Some(self.alloc_expr_from_pat(
2390                                Expr::Literal(pat_literal_to_hir(it)?.0),
2391                                ptr,
2392                            )),
2393                            ast::Pat::IdentPat(ident) if ident.is_simple_ident() => ident
2394                                .name()
2395                                .map(|name| name.as_name())
2396                                .map(Path::from)
2397                                .map(|path| self.alloc_expr_from_pat(Expr::Path(path), ptr)),
2398                            ast::Pat::PathPat(p) => p
2399                                .path()
2400                                .and_then(|path| {
2401                                    self.lower_path(path, &mut Self::impl_trait_error_allocator)
2402                                })
2403                                .map(|parsed| self.alloc_expr_from_pat(Expr::Path(parsed), ptr)),
2404                            // We only need to handle literal, ident (if bare) and path patterns here,
2405                            // as any other pattern as a range pattern operand is semantically invalid.
2406                            _ => None,
2407                        }
2408                    })
2409                };
2410                let start = range_part_lower(p.start());
2411                let end = range_part_lower(p.end());
2412                Pat::Range { start, end }
2413            }
2414        };
2415        let ptr = AstPtr::new(&pat);
2416        self.alloc_pat(pattern, ptr)
2417    }
2418
2419    fn collect_pat_opt(&mut self, pat: Option<ast::Pat>, binding_list: &mut BindingList) -> PatId {
2420        match pat {
2421            Some(pat) => self.collect_pat(pat, binding_list),
2422            None => self.missing_pat(),
2423        }
2424    }
2425
2426    fn collect_tuple_pat(
2427        &mut self,
2428        args: AstChildren<ast::Pat>,
2429        has_leading_comma: bool,
2430        binding_list: &mut BindingList,
2431    ) -> (Box<[PatId]>, Option<u32>) {
2432        let args: Vec<_> = args.map(|p| self.collect_pat_possibly_rest(p, binding_list)).collect();
2433        // Find the location of the `..`, if there is one. Note that we do not
2434        // consider the possibility of there being multiple `..` here.
2435        let ellipsis = args.iter().position(|p| p.is_right()).map(|it| it as u32);
2436
2437        // We want to skip the `..` pattern here, since we account for it above.
2438        let mut args: Vec<_> = args.into_iter().filter_map(Either::left).collect();
2439        // if there is a leading comma, the user is most likely to type out a leading pattern
2440        // so we insert a missing pattern at the beginning for IDE features
2441        if has_leading_comma {
2442            args.insert(0, self.missing_pat());
2443        }
2444
2445        (args.into_boxed_slice(), ellipsis)
2446    }
2447
2448    // `collect_pat` rejects `ast::Pat::RestPat`, but it should be handled in some cases that
2449    // it is the macro expansion result of an arg sub-pattern in a slice or tuple pattern.
2450    fn collect_pat_possibly_rest(
2451        &mut self,
2452        pat: ast::Pat,
2453        binding_list: &mut BindingList,
2454    ) -> Either<PatId, ()> {
2455        match &pat {
2456            ast::Pat::RestPat(_) => Either::Right(()),
2457            ast::Pat::MacroPat(mac) => match mac.macro_call() {
2458                Some(call) => {
2459                    let macro_ptr = AstPtr::new(&call);
2460                    let src = self.expander.in_file(AstPtr::new(&pat));
2461                    let pat =
2462                        self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
2463                            if let Some(expanded_pat) = expanded_pat {
2464                                this.collect_pat_possibly_rest(expanded_pat, binding_list)
2465                            } else {
2466                                Either::Left(this.missing_pat())
2467                            }
2468                        });
2469                    if let Some(pat) = pat.left() {
2470                        self.store.pat_map.insert(src, pat.into());
2471                    }
2472                    pat
2473                }
2474                None => {
2475                    let ptr = AstPtr::new(&pat);
2476                    Either::Left(self.alloc_pat(Pat::Missing, ptr))
2477                }
2478            },
2479            _ => Either::Left(self.collect_pat(pat, binding_list)),
2480        }
2481    }
2482
2483    // endregion: patterns
2484
2485    /// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when
2486    /// not.
2487    fn check_cfg(&mut self, owner: &dyn ast::HasAttrs) -> bool {
2488        let enabled = self.expander.is_cfg_enabled(self.db, owner, self.cfg_options);
2489        match enabled {
2490            Ok(()) => true,
2491            Err(cfg) => {
2492                self.store.diagnostics.push(ExpressionStoreDiagnostics::InactiveCode {
2493                    node: self.expander.in_file(SyntaxNodePtr::new(owner.syntax())),
2494                    cfg,
2495                    opts: self.cfg_options.clone(),
2496                });
2497                false
2498            }
2499        }
2500    }
2501
2502    fn add_definition_to_binding(&mut self, binding_id: BindingId, pat_id: PatId) {
2503        self.store.binding_definitions.entry(binding_id).or_default().push(pat_id);
2504    }
2505
2506    // region: labels
2507
2508    fn collect_label(&mut self, ast_label: ast::Label) -> LabelId {
2509        let label = Label {
2510            name: ast_label
2511                .lifetime()
2512                .as_ref()
2513                .map_or_else(Name::missing, |lt| Name::new_lifetime(&lt.text())),
2514        };
2515        self.alloc_label(label, AstPtr::new(&ast_label))
2516    }
2517
2518    fn resolve_label(
2519        &self,
2520        lifetime: Option<ast::Lifetime>,
2521    ) -> Result<Option<LabelId>, ExpressionStoreDiagnostics> {
2522        let Some(lifetime) = lifetime else { return Ok(None) };
2523        let mut hygiene_id =
2524            self.expander.hygiene_for_range(self.db, lifetime.syntax().text_range());
2525        let mut hygiene_info = if hygiene_id.is_root() {
2526            None
2527        } else {
2528            hygiene_id.lookup().outer_expn(self.db).map(|expansion| {
2529                let expansion = self.db.lookup_intern_macro_call(expansion.into());
2530                (hygiene_id.lookup().parent(self.db), expansion.def)
2531            })
2532        };
2533        let name = Name::new_lifetime(&lifetime.text());
2534
2535        for (rib_idx, rib) in self.label_ribs.iter().enumerate().rev() {
2536            match &rib.kind {
2537                RibKind::Normal(label_name, id, label_hygiene) => {
2538                    if *label_name == name && *label_hygiene == hygiene_id {
2539                        return if self.is_label_valid_from_rib(rib_idx) {
2540                            Ok(Some(*id))
2541                        } else {
2542                            Err(ExpressionStoreDiagnostics::UnreachableLabel {
2543                                name,
2544                                node: self.expander.in_file(AstPtr::new(&lifetime)),
2545                            })
2546                        };
2547                    }
2548                }
2549                RibKind::MacroDef(macro_id) => {
2550                    if let Some((parent_ctx, label_macro_id)) = hygiene_info
2551                        && label_macro_id == **macro_id
2552                    {
2553                        // A macro is allowed to refer to labels from before its declaration.
2554                        // Therefore, if we got to the rib of its declaration, give up its hygiene
2555                        // and use its parent expansion.
2556
2557                        hygiene_id = HygieneId::new(parent_ctx.opaque_and_semitransparent(self.db));
2558                        hygiene_info = parent_ctx.outer_expn(self.db).map(|expansion| {
2559                            let expansion = self.db.lookup_intern_macro_call(expansion.into());
2560                            (parent_ctx.parent(self.db), expansion.def)
2561                        });
2562                    }
2563                }
2564                _ => {}
2565            }
2566        }
2567
2568        Err(ExpressionStoreDiagnostics::UndeclaredLabel {
2569            name,
2570            node: self.expander.in_file(AstPtr::new(&lifetime)),
2571        })
2572    }
2573
2574    fn is_label_valid_from_rib(&self, rib_index: usize) -> bool {
2575        !self.label_ribs[rib_index + 1..].iter().any(|rib| rib.kind.is_label_barrier())
2576    }
2577
2578    fn pop_label_rib(&mut self) {
2579        // We need to pop all macro defs, plus one rib.
2580        while let Some(LabelRib { kind: RibKind::MacroDef(_) }) = self.label_ribs.pop() {
2581            // Do nothing.
2582        }
2583    }
2584
2585    fn with_label_rib<T>(&mut self, kind: RibKind, f: impl FnOnce(&mut Self) -> T) -> T {
2586        self.label_ribs.push(LabelRib::new(kind));
2587        let res = f(self);
2588        self.pop_label_rib();
2589        res
2590    }
2591
2592    fn with_labeled_rib<T>(
2593        &mut self,
2594        label: LabelId,
2595        hygiene: HygieneId,
2596        f: impl FnOnce(&mut Self) -> T,
2597    ) -> T {
2598        self.label_ribs.push(LabelRib::new(RibKind::Normal(
2599            self.store.labels[label].name.clone(),
2600            label,
2601            hygiene,
2602        )));
2603        let res = f(self);
2604        self.pop_label_rib();
2605        res
2606    }
2607
2608    fn with_opt_labeled_rib<T>(
2609        &mut self,
2610        label: Option<(HygieneId, LabelId)>,
2611        f: impl FnOnce(&mut Self) -> T,
2612    ) -> T {
2613        match label {
2614            None => f(self),
2615            Some((hygiene, label)) => self.with_labeled_rib(label, hygiene, f),
2616        }
2617    }
2618    // endregion: labels
2619
2620    // region: format
2621    fn expand_macros_to_string(&mut self, expr: ast::Expr) -> Option<(ast::String, bool)> {
2622        let m = match expr {
2623            ast::Expr::MacroExpr(m) => m,
2624            ast::Expr::Literal(l) => {
2625                return match l.kind() {
2626                    ast::LiteralKind::String(s) => Some((s, true)),
2627                    _ => None,
2628                };
2629            }
2630            _ => return None,
2631        };
2632        let e = m.macro_call()?;
2633        let macro_ptr = AstPtr::new(&e);
2634        let (exp, _) = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
2635            expansion.and_then(|it| this.expand_macros_to_string(it))
2636        })?;
2637        Some((exp, false))
2638    }
2639
2640    fn collect_format_args(
2641        &mut self,
2642        f: ast::FormatArgsExpr,
2643        syntax_ptr: AstPtr<ast::Expr>,
2644    ) -> ExprId {
2645        let mut args = FormatArgumentsCollector::default();
2646        f.args().for_each(|arg| {
2647            args.add(FormatArgument {
2648                kind: match arg.name() {
2649                    Some(name) => FormatArgumentKind::Named(name.as_name()),
2650                    None => FormatArgumentKind::Normal,
2651                },
2652                expr: self.collect_expr_opt(arg.expr()),
2653            });
2654        });
2655        let template = f.template();
2656        let fmt_snippet = template.as_ref().and_then(|it| match it {
2657            ast::Expr::Literal(literal) => match literal.kind() {
2658                ast::LiteralKind::String(s) => Some(s.text().to_owned()),
2659                _ => None,
2660            },
2661            _ => None,
2662        });
2663        let mut mappings = vec![];
2664        let (fmt, hygiene) = match template.and_then(|template| {
2665            self.expand_macros_to_string(template.clone()).map(|it| (it, template))
2666        }) {
2667            Some(((s, is_direct_literal), template)) => {
2668                let call_ctx = self.expander.call_syntax_ctx();
2669                let hygiene = self.hygiene_id_for(s.syntax().text_range());
2670                let fmt = format_args::parse(
2671                    &s,
2672                    fmt_snippet,
2673                    args,
2674                    is_direct_literal,
2675                    |name, range| {
2676                        let expr_id = self.alloc_expr_desugared(Expr::Path(Path::from(name)));
2677                        if let Some(range) = range {
2678                            self.store
2679                                .template_map
2680                                .get_or_insert_with(Default::default)
2681                                .implicit_capture_to_source
2682                                .insert(
2683                                    expr_id,
2684                                    self.expander.in_file((AstPtr::new(&template), range)),
2685                                );
2686                        }
2687                        if !hygiene.is_root() {
2688                            self.store.ident_hygiene.insert(expr_id.into(), hygiene);
2689                        }
2690                        expr_id
2691                    },
2692                    |name, span| {
2693                        if let Some(span) = span {
2694                            mappings.push((span, name))
2695                        }
2696                    },
2697                    call_ctx,
2698                );
2699                (fmt, hygiene)
2700            }
2701            None => (
2702                FormatArgs {
2703                    template: Default::default(),
2704                    arguments: args.finish(),
2705                    orphans: Default::default(),
2706                },
2707                HygieneId::ROOT,
2708            ),
2709        };
2710
2711        // Create a list of all _unique_ (argument, format trait) combinations.
2712        // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
2713        let mut argmap = FxIndexSet::default();
2714        for piece in fmt.template.iter() {
2715            let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
2716            if let Ok(index) = placeholder.argument.index {
2717                argmap.insert((index, ArgumentType::Format(placeholder.format_trait)));
2718            }
2719        }
2720
2721        let lit_pieces = fmt
2722            .template
2723            .iter()
2724            .enumerate()
2725            .filter_map(|(i, piece)| {
2726                match piece {
2727                    FormatArgsPiece::Literal(s) => {
2728                        Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(s.clone()))))
2729                    }
2730                    &FormatArgsPiece::Placeholder(_) => {
2731                        // Inject empty string before placeholders when not already preceded by a literal piece.
2732                        if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_))
2733                        {
2734                            Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(
2735                                Symbol::empty(),
2736                            ))))
2737                        } else {
2738                            None
2739                        }
2740                    }
2741                }
2742            })
2743            .collect();
2744        let lit_pieces =
2745            self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: lit_pieces }));
2746        let lit_pieces = self.alloc_expr_desugared(Expr::Ref {
2747            expr: lit_pieces,
2748            rawness: Rawness::Ref,
2749            mutability: Mutability::Shared,
2750        });
2751        let format_options = {
2752            // Generate:
2753            //     &[format_spec_0, format_spec_1, format_spec_2]
2754            let elements = fmt
2755                .template
2756                .iter()
2757                .filter_map(|piece| {
2758                    let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
2759                    Some(self.make_format_spec(placeholder, &mut argmap))
2760                })
2761                .collect();
2762            let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements }));
2763            self.alloc_expr_desugared(Expr::Ref {
2764                expr: array,
2765                rawness: Rawness::Ref,
2766                mutability: Mutability::Shared,
2767            })
2768        };
2769
2770        // Assume that rustc version >= 1.89.0 iff lang item `format_arguments` exists
2771        // but `format_unsafe_arg` does not
2772        let fmt_args =
2773            || crate::lang_item::lang_item(self.db, self.module.krate(), LangItem::FormatArguments);
2774        let fmt_unsafe_arg =
2775            || crate::lang_item::lang_item(self.db, self.module.krate(), LangItem::FormatUnsafeArg);
2776        let use_format_args_since_1_89_0 = fmt_args().is_some() && fmt_unsafe_arg().is_none();
2777
2778        let idx = if use_format_args_since_1_89_0 {
2779            self.collect_format_args_impl(syntax_ptr, fmt, argmap, lit_pieces, format_options)
2780        } else {
2781            self.collect_format_args_before_1_89_0_impl(
2782                syntax_ptr,
2783                fmt,
2784                argmap,
2785                lit_pieces,
2786                format_options,
2787            )
2788        };
2789
2790        self.store
2791            .template_map
2792            .get_or_insert_with(Default::default)
2793            .format_args_to_captures
2794            .insert(idx, (hygiene, mappings));
2795        idx
2796    }
2797
2798    /// `format_args!` expansion implementation for rustc versions < `1.89.0`
2799    fn collect_format_args_before_1_89_0_impl(
2800        &mut self,
2801        syntax_ptr: AstPtr<ast::Expr>,
2802        fmt: FormatArgs,
2803        argmap: FxIndexSet<(usize, ArgumentType)>,
2804        lit_pieces: ExprId,
2805        format_options: ExprId,
2806    ) -> ExprId {
2807        let arguments = &*fmt.arguments.arguments;
2808
2809        let args = if arguments.is_empty() {
2810            let expr = self
2811                .alloc_expr_desugared(Expr::Array(Array::ElementList { elements: Box::default() }));
2812            self.alloc_expr_desugared(Expr::Ref {
2813                expr,
2814                rawness: Rawness::Ref,
2815                mutability: Mutability::Shared,
2816            })
2817        } else {
2818            // Generate:
2819            //     &match (&arg0, &arg1, &…) {
2820            //         args => [
2821            //             <core::fmt::Argument>::new_display(args.0),
2822            //             <core::fmt::Argument>::new_lower_hex(args.1),
2823            //             <core::fmt::Argument>::new_debug(args.0),
2824            //             …
2825            //         ]
2826            //     }
2827            let args = argmap
2828                .iter()
2829                .map(|&(arg_index, ty)| {
2830                    let arg = self.alloc_expr_desugared(Expr::Ref {
2831                        expr: arguments[arg_index].expr,
2832                        rawness: Rawness::Ref,
2833                        mutability: Mutability::Shared,
2834                    });
2835                    self.make_argument(arg, ty)
2836                })
2837                .collect();
2838            let array =
2839                self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
2840            self.alloc_expr_desugared(Expr::Ref {
2841                expr: array,
2842                rawness: Rawness::Ref,
2843                mutability: Mutability::Shared,
2844            })
2845        };
2846
2847        // Generate:
2848        //     <core::fmt::Arguments>::new_v1_formatted(
2849        //         lit_pieces,
2850        //         args,
2851        //         format_options,
2852        //         unsafe { ::core::fmt::UnsafeArg::new() }
2853        //     )
2854
2855        let new_v1_formatted = LangItem::FormatArguments.ty_rel_path(
2856            self.db,
2857            self.module.krate(),
2858            Name::new_symbol_root(sym::new_v1_formatted),
2859        );
2860        let unsafe_arg_new = LangItem::FormatUnsafeArg.ty_rel_path(
2861            self.db,
2862            self.module.krate(),
2863            Name::new_symbol_root(sym::new),
2864        );
2865        let new_v1_formatted =
2866            self.alloc_expr_desugared(new_v1_formatted.map_or(Expr::Missing, Expr::Path));
2867
2868        let unsafe_arg_new =
2869            self.alloc_expr_desugared(unsafe_arg_new.map_or(Expr::Missing, Expr::Path));
2870        let unsafe_arg_new =
2871            self.alloc_expr_desugared(Expr::Call { callee: unsafe_arg_new, args: Box::default() });
2872        let mut unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe {
2873            id: None,
2874            statements: Box::new([]),
2875            tail: Some(unsafe_arg_new),
2876        });
2877        if !fmt.orphans.is_empty() {
2878            unsafe_arg_new = self.alloc_expr_desugared(Expr::Block {
2879                id: None,
2880                // We collect the unused expressions here so that we still infer them instead of
2881                // dropping them out of the expression tree. We cannot store them in the `Unsafe`
2882                // block because then unsafe blocks within them will get a false "unused unsafe"
2883                // diagnostic (rustc has a notion of builtin unsafe blocks, but we don't).
2884                statements: fmt
2885                    .orphans
2886                    .into_iter()
2887                    .map(|expr| Statement::Expr { expr, has_semi: true })
2888                    .collect(),
2889                tail: Some(unsafe_arg_new),
2890                label: None,
2891            });
2892        }
2893
2894        self.alloc_expr(
2895            Expr::Call {
2896                callee: new_v1_formatted,
2897                args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
2898            },
2899            syntax_ptr,
2900        )
2901    }
2902
2903    /// `format_args!` expansion implementation for rustc versions >= `1.89.0`,
2904    /// especially since [this PR](https://github.com/rust-lang/rust/pull/140748)
2905    fn collect_format_args_impl(
2906        &mut self,
2907        syntax_ptr: AstPtr<ast::Expr>,
2908        fmt: FormatArgs,
2909        argmap: FxIndexSet<(usize, ArgumentType)>,
2910        lit_pieces: ExprId,
2911        format_options: ExprId,
2912    ) -> ExprId {
2913        let arguments = &*fmt.arguments.arguments;
2914
2915        let (let_stmts, args) = if arguments.is_empty() {
2916            (
2917                // Generate:
2918                //     []
2919                vec![],
2920                self.alloc_expr_desugared(Expr::Array(Array::ElementList {
2921                    elements: Box::default(),
2922                })),
2923            )
2924        } else if argmap.len() == 1 && arguments.len() == 1 {
2925            // Only one argument, so we don't need to make the `args` tuple.
2926            //
2927            // Generate:
2928            //     super let args = [<core::fmt::Arguments>::new_display(&arg)];
2929            let args = argmap
2930                .iter()
2931                .map(|&(arg_index, ty)| {
2932                    let ref_arg = self.alloc_expr_desugared(Expr::Ref {
2933                        expr: arguments[arg_index].expr,
2934                        rawness: Rawness::Ref,
2935                        mutability: Mutability::Shared,
2936                    });
2937                    self.make_argument(ref_arg, ty)
2938                })
2939                .collect();
2940            let args =
2941                self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
2942            let args_name = Name::new_symbol_root(sym::args);
2943            let args_binding = self.alloc_binding(
2944                args_name.clone(),
2945                BindingAnnotation::Unannotated,
2946                HygieneId::ROOT,
2947            );
2948            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
2949            self.add_definition_to_binding(args_binding, args_pat);
2950            // TODO: We don't have `super let` yet.
2951            let let_stmt = Statement::Let {
2952                pat: args_pat,
2953                type_ref: None,
2954                initializer: Some(args),
2955                else_branch: None,
2956            };
2957            (vec![let_stmt], self.alloc_expr_desugared(Expr::Path(args_name.into())))
2958        } else {
2959            // Generate:
2960            //     super let args = (&arg0, &arg1, &...);
2961            let args_name = Name::new_symbol_root(sym::args);
2962            let args_binding = self.alloc_binding(
2963                args_name.clone(),
2964                BindingAnnotation::Unannotated,
2965                HygieneId::ROOT,
2966            );
2967            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
2968            self.add_definition_to_binding(args_binding, args_pat);
2969            let elements = arguments
2970                .iter()
2971                .map(|arg| {
2972                    self.alloc_expr_desugared(Expr::Ref {
2973                        expr: arg.expr,
2974                        rawness: Rawness::Ref,
2975                        mutability: Mutability::Shared,
2976                    })
2977                })
2978                .collect();
2979            let args_tuple = self.alloc_expr_desugared(Expr::Tuple { exprs: elements });
2980            // TODO: We don't have `super let` yet
2981            let let_stmt1 = Statement::Let {
2982                pat: args_pat,
2983                type_ref: None,
2984                initializer: Some(args_tuple),
2985                else_branch: None,
2986            };
2987
2988            // Generate:
2989            //     super let args = [
2990            //         <core::fmt::Argument>::new_display(args.0),
2991            //         <core::fmt::Argument>::new_lower_hex(args.1),
2992            //         <core::fmt::Argument>::new_debug(args.0),
2993            //         …
2994            //     ];
2995            let args = argmap
2996                .iter()
2997                .map(|&(arg_index, ty)| {
2998                    let args_ident_expr =
2999                        self.alloc_expr_desugared(Expr::Path(args_name.clone().into()));
3000                    let arg = self.alloc_expr_desugared(Expr::Field {
3001                        expr: args_ident_expr,
3002                        name: Name::new_tuple_field(arg_index),
3003                    });
3004                    self.make_argument(arg, ty)
3005                })
3006                .collect();
3007            let array =
3008                self.alloc_expr_desugared(Expr::Array(Array::ElementList { elements: args }));
3009            let args_binding = self.alloc_binding(
3010                args_name.clone(),
3011                BindingAnnotation::Unannotated,
3012                HygieneId::ROOT,
3013            );
3014            let args_pat = self.alloc_pat_desugared(Pat::Bind { id: args_binding, subpat: None });
3015            self.add_definition_to_binding(args_binding, args_pat);
3016            let let_stmt2 = Statement::Let {
3017                pat: args_pat,
3018                type_ref: None,
3019                initializer: Some(array),
3020                else_branch: None,
3021            };
3022            (vec![let_stmt1, let_stmt2], self.alloc_expr_desugared(Expr::Path(args_name.into())))
3023        };
3024
3025        // Generate:
3026        //     &args
3027        let args = self.alloc_expr_desugared(Expr::Ref {
3028            expr: args,
3029            rawness: Rawness::Ref,
3030            mutability: Mutability::Shared,
3031        });
3032
3033        let call_block = {
3034            // Generate:
3035            //     unsafe {
3036            //         <core::fmt::Arguments>::new_v1_formatted(
3037            //             lit_pieces,
3038            //             args,
3039            //             format_options,
3040            //         )
3041            //     }
3042
3043            let new_v1_formatted = LangItem::FormatArguments.ty_rel_path(
3044                self.db,
3045                self.module.krate(),
3046                Name::new_symbol_root(sym::new_v1_formatted),
3047            );
3048            let new_v1_formatted =
3049                self.alloc_expr_desugared(new_v1_formatted.map_or(Expr::Missing, Expr::Path));
3050            let args = [lit_pieces, args, format_options];
3051            let call = self
3052                .alloc_expr_desugared(Expr::Call { callee: new_v1_formatted, args: args.into() });
3053
3054            Expr::Unsafe { id: None, statements: Box::default(), tail: Some(call) }
3055        };
3056
3057        if !let_stmts.is_empty() {
3058            // Generate:
3059            //     {
3060            //         super let …
3061            //         super let …
3062            //         <core::fmt::Arguments>::new_…(…)
3063            //     }
3064            let call = self.alloc_expr_desugared(call_block);
3065            self.alloc_expr(
3066                Expr::Block {
3067                    id: None,
3068                    statements: let_stmts.into(),
3069                    tail: Some(call),
3070                    label: None,
3071                },
3072                syntax_ptr,
3073            )
3074        } else {
3075            self.alloc_expr(call_block, syntax_ptr)
3076        }
3077    }
3078
3079    /// Generate a hir expression for a format_args placeholder specification.
3080    ///
3081    /// Generates
3082    ///
3083    /// ```text
3084    ///     <core::fmt::rt::Placeholder::new(
3085    ///         …usize, // position
3086    ///         '…', // fill
3087    ///         <core::fmt::rt::Alignment>::…, // alignment
3088    ///         …u32, // flags
3089    ///         <core::fmt::rt::Count::…>, // width
3090    ///         <core::fmt::rt::Count::…>, // precision
3091    ///     )
3092    /// ```
3093    fn make_format_spec(
3094        &mut self,
3095        placeholder: &FormatPlaceholder,
3096        argmap: &mut FxIndexSet<(usize, ArgumentType)>,
3097    ) -> ExprId {
3098        let position = match placeholder.argument.index {
3099            Ok(arg_index) => {
3100                let (i, _) =
3101                    argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
3102                self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
3103                    i as u128,
3104                    Some(BuiltinUint::Usize),
3105                )))
3106            }
3107            Err(_) => self.missing_expr(),
3108        };
3109        let &FormatOptions {
3110            ref width,
3111            ref precision,
3112            alignment,
3113            fill,
3114            sign,
3115            alternate,
3116            zero_pad,
3117            debug_hex,
3118        } = &placeholder.format_options;
3119
3120        let precision_expr = self.make_count(precision, argmap);
3121        let width_expr = self.make_count(width, argmap);
3122
3123        if self.module.krate().workspace_data(self.db).is_atleast_187() {
3124            // These need to match the constants in library/core/src/fmt/rt.rs.
3125            let align = match alignment {
3126                Some(FormatAlignment::Left) => 0,
3127                Some(FormatAlignment::Right) => 1,
3128                Some(FormatAlignment::Center) => 2,
3129                None => 3,
3130            };
3131            // This needs to match `Flag` in library/core/src/fmt/rt.rs.
3132            let flags = fill.unwrap_or(' ') as u32
3133                | ((sign == Some(FormatSign::Plus)) as u32) << 21
3134                | ((sign == Some(FormatSign::Minus)) as u32) << 22
3135                | (alternate as u32) << 23
3136                | (zero_pad as u32) << 24
3137                | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 25
3138                | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 26
3139                | (width.is_some() as u32) << 27
3140                | (precision.is_some() as u32) << 28
3141                | align << 29
3142                | 1 << 31; // Highest bit always set.
3143            let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
3144                flags as u128,
3145                Some(BuiltinUint::U32),
3146            )));
3147
3148            let position =
3149                RecordLitField { name: Name::new_symbol_root(sym::position), expr: position };
3150            let flags = RecordLitField { name: Name::new_symbol_root(sym::flags), expr: flags };
3151            let precision = RecordLitField {
3152                name: Name::new_symbol_root(sym::precision),
3153                expr: precision_expr,
3154            };
3155            let width =
3156                RecordLitField { name: Name::new_symbol_root(sym::width), expr: width_expr };
3157            self.alloc_expr_desugared(Expr::RecordLit {
3158                path: LangItem::FormatPlaceholder.path(self.db, self.module.krate()).map(Box::new),
3159                fields: Box::new([position, flags, precision, width]),
3160                spread: None,
3161            })
3162        } else {
3163            let format_placeholder_new = {
3164                let format_placeholder_new = LangItem::FormatPlaceholder.ty_rel_path(
3165                    self.db,
3166                    self.module.krate(),
3167                    Name::new_symbol_root(sym::new),
3168                );
3169                match format_placeholder_new {
3170                    Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
3171                    None => self.missing_expr(),
3172                }
3173            };
3174            // This needs to match `Flag` in library/core/src/fmt/rt.rs.
3175            let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
3176                | (((sign == Some(FormatSign::Minus)) as u32) << 1)
3177                | ((alternate as u32) << 2)
3178                | ((zero_pad as u32) << 3)
3179                | (((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4)
3180                | (((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5);
3181            let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
3182                flags as u128,
3183                Some(BuiltinUint::U32),
3184            )));
3185            let fill = self.alloc_expr_desugared(Expr::Literal(Literal::Char(fill.unwrap_or(' '))));
3186            let align = {
3187                let align = LangItem::FormatAlignment.ty_rel_path(
3188                    self.db,
3189                    self.module.krate(),
3190                    match alignment {
3191                        Some(FormatAlignment::Left) => Name::new_symbol_root(sym::Left),
3192                        Some(FormatAlignment::Right) => Name::new_symbol_root(sym::Right),
3193                        Some(FormatAlignment::Center) => Name::new_symbol_root(sym::Center),
3194                        None => Name::new_symbol_root(sym::Unknown),
3195                    },
3196                );
3197                match align {
3198                    Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
3199                    None => self.missing_expr(),
3200                }
3201            };
3202            self.alloc_expr_desugared(Expr::Call {
3203                callee: format_placeholder_new,
3204                args: Box::new([position, fill, align, flags, precision_expr, width_expr]),
3205            })
3206        }
3207    }
3208
3209    /// Generate a hir expression for a format_args Count.
3210    ///
3211    /// Generates:
3212    ///
3213    /// ```text
3214    ///     <core::fmt::rt::Count>::Is(…)
3215    /// ```
3216    ///
3217    /// or
3218    ///
3219    /// ```text
3220    ///     <core::fmt::rt::Count>::Param(…)
3221    /// ```
3222    ///
3223    /// or
3224    ///
3225    /// ```text
3226    ///     <core::fmt::rt::Count>::Implied
3227    /// ```
3228    fn make_count(
3229        &mut self,
3230        count: &Option<FormatCount>,
3231        argmap: &mut FxIndexSet<(usize, ArgumentType)>,
3232    ) -> ExprId {
3233        match count {
3234            Some(FormatCount::Literal(n)) => {
3235                let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
3236                    *n as u128,
3237                    // FIXME: Change this to Some(BuiltinUint::U16) once we drop support for toolchains < 1.88
3238                    None,
3239                )));
3240                let count_is = match LangItem::FormatCount.ty_rel_path(
3241                    self.db,
3242                    self.module.krate(),
3243                    Name::new_symbol_root(sym::Is),
3244                ) {
3245                    Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)),
3246                    None => self.missing_expr(),
3247                };
3248                self.alloc_expr_desugared(Expr::Call { callee: count_is, args: Box::new([args]) })
3249            }
3250            Some(FormatCount::Argument(arg)) => {
3251                if let Ok(arg_index) = arg.index {
3252                    let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
3253
3254                    let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
3255                        i as u128,
3256                        Some(BuiltinUint::Usize),
3257                    )));
3258                    let count_param = match LangItem::FormatCount.ty_rel_path(
3259                        self.db,
3260                        self.module.krate(),
3261                        Name::new_symbol_root(sym::Param),
3262                    ) {
3263                        Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
3264                        None => self.missing_expr(),
3265                    };
3266                    self.alloc_expr_desugared(Expr::Call {
3267                        callee: count_param,
3268                        args: Box::new([args]),
3269                    })
3270                } else {
3271                    // FIXME: This drops arg causing it to potentially not be resolved/type checked
3272                    // when typing?
3273                    self.missing_expr()
3274                }
3275            }
3276            None => match LangItem::FormatCount.ty_rel_path(
3277                self.db,
3278                self.module.krate(),
3279                Name::new_symbol_root(sym::Implied),
3280            ) {
3281                Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
3282                None => self.missing_expr(),
3283            },
3284        }
3285    }
3286
3287    /// Generate a hir expression representing an argument to a format_args invocation.
3288    ///
3289    /// Generates:
3290    ///
3291    /// ```text
3292    ///     <core::fmt::Argument>::new_…(arg)
3293    /// ```
3294    fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId {
3295        use ArgumentType::*;
3296        use FormatTrait::*;
3297
3298        let new_fn = match LangItem::FormatArgument.ty_rel_path(
3299            self.db,
3300            self.module.krate(),
3301            Name::new_symbol_root(match ty {
3302                Format(Display) => sym::new_display,
3303                Format(Debug) => sym::new_debug,
3304                Format(LowerExp) => sym::new_lower_exp,
3305                Format(UpperExp) => sym::new_upper_exp,
3306                Format(Octal) => sym::new_octal,
3307                Format(Pointer) => sym::new_pointer,
3308                Format(Binary) => sym::new_binary,
3309                Format(LowerHex) => sym::new_lower_hex,
3310                Format(UpperHex) => sym::new_upper_hex,
3311                Usize => sym::from_usize,
3312            }),
3313        ) {
3314            Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)),
3315            None => self.missing_expr(),
3316        };
3317        self.alloc_expr_desugared(Expr::Call { callee: new_fn, args: Box::new([arg]) })
3318    }
3319
3320    // endregion: format
3321
3322    fn lang_path(&self, lang: LangItem) -> Option<Path> {
3323        lang.path(self.db, self.module.krate())
3324    }
3325}
3326
3327fn pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)> {
3328    let ast_lit = lit.literal()?;
3329    let mut hir_lit: Literal = ast_lit.kind().into();
3330    if lit.minus_token().is_some() {
3331        hir_lit = hir_lit.negate()?;
3332    }
3333    Some((hir_lit, ast_lit))
3334}
3335
3336impl ExprCollector<'_> {
3337    fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
3338        let src = self.expander.in_file(ptr);
3339        let id = self.store.exprs.alloc(expr);
3340        self.store.expr_map_back.insert(id, src.map(AstPtr::wrap_left));
3341        self.store.expr_map.insert(src, id.into());
3342        id
3343    }
3344    // FIXME: desugared exprs don't have ptr, that's wrong and should be fixed.
3345    // Migrate to alloc_expr_desugared_with_ptr and then rename back
3346    fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
3347        self.store.exprs.alloc(expr)
3348    }
3349    fn alloc_expr_desugared_with_ptr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
3350        let src = self.expander.in_file(ptr);
3351        let id = self.store.exprs.alloc(expr);
3352        self.store.expr_map_back.insert(id, src.map(AstPtr::wrap_left));
3353        // We intentionally don't fill this as it could overwrite a non-desugared entry
3354        // self.store.expr_map.insert(src, id);
3355        id
3356    }
3357    fn missing_expr(&mut self) -> ExprId {
3358        self.alloc_expr_desugared(Expr::Missing)
3359    }
3360
3361    fn alloc_binding(
3362        &mut self,
3363        name: Name,
3364        mode: BindingAnnotation,
3365        hygiene: HygieneId,
3366    ) -> BindingId {
3367        let binding = self.store.bindings.alloc(Binding { name, mode, problems: None, hygiene });
3368        if let Some(owner) = self.current_binding_owner {
3369            self.store.binding_owners.insert(binding, owner);
3370        }
3371        binding
3372    }
3373
3374    fn alloc_pat_from_expr(&mut self, pat: Pat, ptr: ExprPtr) -> PatId {
3375        let src = self.expander.in_file(ptr);
3376        let id = self.store.pats.alloc(pat);
3377        self.store.expr_map.insert(src, id.into());
3378        self.store.pat_map_back.insert(id, src.map(AstPtr::wrap_left));
3379        id
3380    }
3381
3382    fn alloc_expr_from_pat(&mut self, expr: Expr, ptr: PatPtr) -> ExprId {
3383        let src = self.expander.in_file(ptr);
3384        let id = self.store.exprs.alloc(expr);
3385        self.store.pat_map.insert(src, id.into());
3386        self.store.expr_map_back.insert(id, src.map(AstPtr::wrap_right));
3387        id
3388    }
3389
3390    fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
3391        let src = self.expander.in_file(ptr);
3392        let id = self.store.pats.alloc(pat);
3393        self.store.pat_map_back.insert(id, src.map(AstPtr::wrap_right));
3394        self.store.pat_map.insert(src, id.into());
3395        id
3396    }
3397    // FIXME: desugared pats don't have ptr, that's wrong and should be fixed somehow.
3398    fn alloc_pat_desugared(&mut self, pat: Pat) -> PatId {
3399        self.store.pats.alloc(pat)
3400    }
3401    fn missing_pat(&mut self) -> PatId {
3402        self.store.pats.alloc(Pat::Missing)
3403    }
3404
3405    fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId {
3406        let src = self.expander.in_file(ptr);
3407        let id = self.store.labels.alloc(label);
3408        self.store.label_map_back.insert(id, src);
3409        self.store.label_map.insert(src, id);
3410        id
3411    }
3412    // FIXME: desugared labels don't have ptr, that's wrong and should be fixed somehow.
3413    fn alloc_label_desugared(&mut self, label: Label) -> LabelId {
3414        self.store.labels.alloc(label)
3415    }
3416
3417    fn is_lowering_awaitable_block(&self) -> &Awaitable {
3418        self.awaitable_context.as_ref().unwrap_or(&Awaitable::No("unknown"))
3419    }
3420
3421    fn with_awaitable_block<T>(
3422        &mut self,
3423        awaitable: Awaitable,
3424        f: impl FnOnce(&mut Self) -> T,
3425    ) -> T {
3426        let orig = self.awaitable_context.replace(awaitable);
3427        let res = f(self);
3428        self.awaitable_context = orig;
3429        res
3430    }
3431
3432    fn hygiene_id_for(&self, range: TextRange) -> HygieneId {
3433        self.expander.hygiene_for_range(self.db, range)
3434    }
3435}
3436
3437fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool {
3438    (|| syntax::algo::skip_trivia_token(t?.next_token()?, syntax::Direction::Next))()
3439        .is_some_and(|it| it.kind() == syntax::T![,])
3440}
3441
3442#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
3443enum ArgumentType {
3444    Format(FormatTrait),
3445    Usize,
3446}
3447
3448/// This function find the AST fragment that corresponds to an `AssociatedTypeBinding` in the HIR.
3449pub fn hir_assoc_type_binding_to_ast(
3450    segment_args: &ast::GenericArgList,
3451    binding_idx: u32,
3452) -> Option<ast::AssocTypeArg> {
3453    segment_args
3454        .generic_args()
3455        .filter_map(|arg| match arg {
3456            ast::GenericArg::AssocTypeArg(it) => Some(it),
3457            _ => None,
3458        })
3459        .filter(|binding| binding.param_list().is_none() && binding.name_ref().is_some())
3460        .nth(binding_idx as usize)
3461}
3462
3463/// This function find the AST generic argument from the one in the HIR. Does not support the `Self` argument.
3464pub fn hir_generic_arg_to_ast(
3465    args: &ast::GenericArgList,
3466    arg_idx: u32,
3467    has_self_arg: bool,
3468) -> Option<ast::GenericArg> {
3469    args.generic_args()
3470        .filter(|arg| match arg {
3471            ast::GenericArg::AssocTypeArg(_) => false,
3472            ast::GenericArg::LifetimeArg(arg) => arg.lifetime().is_some(),
3473            ast::GenericArg::ConstArg(_) | ast::GenericArg::TypeArg(_) => true,
3474        })
3475        .nth(arg_idx as usize - has_self_arg as usize)
3476}