src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs RUST 3,387 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 3,387.
1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`2//! representation.34mod asm;5mod format_args;6mod generics;7mod path;89use std::{cell::OnceCell, mem};1011use arrayvec::ArrayVec;12use base_db::FxIndexSet;13use cfg::CfgOptions;14use either::Either;15use hir_expand::{16    HirFileId, InFile, MacroDefId,17    mod_path::ModPath,18    name::{AsName, Name},19    span_map::SpanMap,20};21use intern::{Symbol, sym};22use rustc_abi::ExternAbi;23use rustc_hash::FxHashMap;24use smallvec::SmallVec;25use stdx::never;26use syntax::{27    AstNode, AstPtr, SyntaxNodePtr,28    ast::{29        self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasGenericArgs,30        HasGenericParams, HasLoopBody, HasName, HasTypeBounds, IsString, RangeItem,31        SlicePatComponents,32    },33};34use thin_vec::ThinVec;35use tt::TextRange;3637use crate::{38    AdtId, BlockId, BlockLoc, ConstId, DefWithBodyId, FunctionId, GenericDefId, ImplId,39    ItemContainerId, MacroId, ModuleDefId, ModuleId, TraitId, TypeAliasId, UnresolvedMacro,40    attrs::AttrFlags,41    db::DefDatabase,42    expr_store::{43        Body, BodySourceMap, ExprPtr, ExprRoot, ExpressionStore, ExpressionStoreBuilder,44        ExpressionStoreDiagnostics, ExpressionStoreSourceMap, HygieneId, LabelPtr, LifetimePtr,45        PatPtr, TypePtr,46        expander::Expander,47        lower::generics::ImplTraitLowerFn,48        path::{AssociatedTypeBinding, GenericArg, GenericArgs, GenericArgsParentheses, Path},49    },50    hir::{51        Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind,52        CoroutineKind, CoroutineSource, Expr, ExprId, Item, Label, LabelId, Literal, LoopSource,53        MatchArm, Movability, OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread,54        Statement, generics::GenericParams,55    },56    item_scope::BuiltinShadowMode,57    item_tree::FieldsShape,58    lang_item::{LangItemTarget, LangItems},59    nameres::{DefMap, LocalDefMap, MacroSubNs, block_def_map},60    signatures::StructSignature,61    type_ref::{62        ArrayType, ConstRef, FnType, LifetimeRef, LifetimeRefId, Mutability, PathId, Rawness,63        RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, UseArgRef,64    },65};6667pub use self::path::hir_segment_to_ast_segment;6869pub(super) fn lower_body(70    db: &dyn DefDatabase,71    owner: DefWithBodyId,72    current_file_id: HirFileId,73    module: ModuleId,74    parameters: Option<ast::ParamList>,75    body: Option<ast::Expr>,76    is_async_fn: bool,77    is_gen_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 interleaved81    // 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, their83    // hygiene is different.8485    let mut self_params = ArrayVec::new();86    let mut source_map_self_param = None;87    let mut params = vec![];88    let mut collector = ExprCollector::new(db, module, current_file_id);8990    let skip_body = AttrFlags::query(91        db,92        match owner {93            DefWithBodyId::FunctionId(it) => it.into(),94            DefWithBodyId::StaticId(it) => it.into(),95            DefWithBodyId::ConstId(it) => it.into(),96            DefWithBodyId::VariantId(it) => it.into(),97        },98    )99    .contains(AttrFlags::RUST_ANALYZER_SKIP);100    // If #[rust_analyzer::skip] annotated, only construct enough information for the signature101    // and skip the body.102    if skip_body {103        if let Some(param_list) = parameters {104            if let Some(self_param_syn) =105                param_list.self_param().filter(|self_param| collector.check_cfg(self_param))106            {107                let is_mutable =108                    self_param_syn.mut_token().is_some() && self_param_syn.amp_token().is_none();109                let hygiene = self_param_syn110                    .name()111                    .map(|name| collector.hygiene_id_for(name.syntax().text_range()))112                    .unwrap_or(HygieneId::ROOT);113                let binding_id: la_arena::Idx<Binding> = collector.alloc_binding(114                    Name::new_symbol_root(sym::self_),115                    BindingAnnotation::new(is_mutable, false),116                    hygiene,117                );118                self_params.push(binding_id);119                source_map_self_param =120                    Some(collector.expander.in_file(AstPtr::new(&self_param_syn)));121            }122            let count = param_list.params().filter(|it| collector.check_cfg(it)).count();123            params = (0..count).map(|_| collector.missing_pat()).collect();124        };125        collector.with_expr_root(|collector| collector.missing_expr());126        let (store, source_map) = collector.store.finish();127        return (128            Body { store, params: params.into_boxed_slice(), self_params },129            BodySourceMap { self_param: source_map_self_param, store: source_map },130        );131    }132133    if let Some(param_list) = parameters {134        if let Some(self_param_syn) = param_list.self_param().filter(|it| collector.check_cfg(it)) {135            let is_mutable =136                self_param_syn.mut_token().is_some() && self_param_syn.amp_token().is_none();137            let hygiene = self_param_syn138                .name()139                .map(|name| collector.hygiene_id_for(name.syntax().text_range()))140                .unwrap_or(HygieneId::ROOT);141            let binding_id: la_arena::Idx<Binding> = collector.alloc_binding(142                Name::new_symbol_root(sym::self_),143                BindingAnnotation::new(is_mutable, false),144                hygiene,145            );146            self_params.push(binding_id);147            source_map_self_param = Some(collector.expander.in_file(AstPtr::new(&self_param_syn)));148        }149150        let is_extern = matches!(151            owner,152            DefWithBodyId::FunctionId(id)153                if matches!(id.loc(db).container, ItemContainerId::ExternBlockId(_)),154        );155156        for param in param_list.params() {157            if collector.check_cfg(&param) {158                let param_pat = if is_extern {159                    collector.collect_extern_fn_param(param.pat())160                } else {161                    collector.collect_pat_top(param.pat())162                };163                params.push(param_pat);164            }165        }166    };167168    collector.with_expr_root(|collector| {169        collector.collect(170            &mut self_params,171            &mut params,172            body,173            if is_async_fn {174                Awaitable::Yes175            } else {176                match owner {177                    DefWithBodyId::FunctionId(..) => Awaitable::No("non-async function"),178                    DefWithBodyId::StaticId(..) => Awaitable::No("static"),179                    DefWithBodyId::ConstId(..) => Awaitable::No("constant"),180                    DefWithBodyId::VariantId(..) => Awaitable::No("enum variant"),181                }182            },183            is_async_fn,184            is_gen_fn,185        )186    });187188    let (store, source_map) = collector.store.finish();189    (190        Body { store, params: params.into_boxed_slice(), self_params },191        BodySourceMap { self_param: source_map_self_param, store: source_map },192    )193}194195pub(crate) fn lower_type_ref(196    db: &dyn DefDatabase,197    module: ModuleId,198    type_ref: InFile<Option<ast::Type>>,199) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId) {200    let mut expr_collector = ExprCollector::new(db, module, type_ref.file_id);201    let type_ref =202        expr_collector.lower_type_ref_opt(type_ref.value, &mut ExprCollector::impl_trait_allocator);203    let (store, source_map) = expr_collector.store.finish();204    (store, source_map, type_ref)205}206207pub fn lower_generic_params(208    db: &dyn DefDatabase,209    module: ModuleId,210    def: GenericDefId,211    file_id: HirFileId,212    param_list: Option<ast::GenericParamList>,213    where_clause: Option<ast::WhereClause>,214) -> (ExpressionStore, GenericParams, ExpressionStoreSourceMap) {215    let mut expr_collector = ExprCollector::new(db, module, file_id);216    let mut collector = generics::GenericParamsCollector::new(def);217    collector.lower(&mut expr_collector, param_list, where_clause);218    let params = collector.finish();219    let (store, source_map) = expr_collector.store.finish();220    (store, params, source_map)221}222223pub(crate) fn lower_impl(224    db: &dyn DefDatabase,225    module: ModuleId,226    impl_syntax: InFile<ast::Impl>,227    impl_id: ImplId,228) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId, Option<TraitRef>, GenericParams) {229    let mut expr_collector = ExprCollector::new(db, module, impl_syntax.file_id);230    let self_ty =231        expr_collector.lower_type_ref_opt_disallow_impl_trait(impl_syntax.value.self_ty());232    let trait_ = impl_syntax.value.trait_().and_then(|it| match &it {233        ast::Type::PathType(path_type) => {234            let path = expr_collector235                .lower_path_type(path_type, &mut ExprCollector::impl_trait_allocator)?;236            Some(TraitRef { path: expr_collector.alloc_path(path, AstPtr::new(&it)) })237        }238        _ => None,239    });240    let mut collector = generics::GenericParamsCollector::new(impl_id.into());241    collector.lower(242        &mut expr_collector,243        impl_syntax.value.generic_param_list(),244        impl_syntax.value.where_clause(),245    );246    let params = collector.finish();247    let (store, source_map) = expr_collector.store.finish();248    (store, source_map, self_ty, trait_, params)249}250251pub(crate) fn lower_trait(252    db: &dyn DefDatabase,253    module: ModuleId,254    trait_syntax: InFile<ast::Trait>,255    trait_id: TraitId,256) -> (ExpressionStore, ExpressionStoreSourceMap, GenericParams) {257    let mut expr_collector = ExprCollector::new(db, module, trait_syntax.file_id);258    let mut collector = generics::GenericParamsCollector::with_self_param(259        &mut expr_collector,260        trait_id.into(),261        trait_syntax.value.type_bound_list(),262    );263    collector.lower(264        &mut expr_collector,265        trait_syntax.value.generic_param_list(),266        trait_syntax.value.where_clause(),267    );268    let params = collector.finish();269    let (store, source_map) = expr_collector.store.finish();270    (store, source_map, params)271}272273pub(crate) fn lower_type_alias(274    db: &dyn DefDatabase,275    module: ModuleId,276    alias: InFile<ast::TypeAlias>,277    type_alias_id: TypeAliasId,278) -> (ExpressionStore, ExpressionStoreSourceMap, GenericParams, Box<[TypeBound]>, Option<TypeRefId>)279{280    let mut expr_collector = ExprCollector::new(db, module, alias.file_id);281    let bounds = alias282        .value283        .type_bound_list()284        .map(|bounds| {285            bounds286                .bounds()287                .map(|bound| {288                    expr_collector.lower_type_bound(bound, &mut ExprCollector::impl_trait_allocator)289                })290                .collect()291        })292        .unwrap_or_default();293    let mut collector = generics::GenericParamsCollector::new(type_alias_id.into());294    collector.lower(295        &mut expr_collector,296        alias.value.generic_param_list(),297        alias.value.where_clause(),298    );299    let params = collector.finish();300    let type_ref = alias301        .value302        .ty()303        .map(|ty| expr_collector.lower_type_ref(ty, &mut ExprCollector::impl_trait_allocator));304    let (store, source_map) = expr_collector.store.finish();305    (store, source_map, params, bounds, type_ref)306}307308pub(crate) fn lower_function(309    db: &dyn DefDatabase,310    module: ModuleId,311    fn_: InFile<ast::Fn>,312    function_id: FunctionId,313) -> (314    ExpressionStore,315    ExpressionStoreSourceMap,316    GenericParams,317    Box<[TypeRefId]>,318    Option<TypeRefId>,319    bool,320    bool,321) {322    let mut expr_collector = ExprCollector::new(db, module, fn_.file_id);323    let mut collector = generics::GenericParamsCollector::new(function_id.into());324    collector.lower(&mut expr_collector, fn_.value.generic_param_list(), fn_.value.where_clause());325    let mut params = vec![];326    let mut has_self_param = false;327    let mut has_variadic = false;328    collector.collect_impl_trait(&mut expr_collector, |collector, mut impl_trait_lower_fn| {329        if let Some(param_list) = fn_.value.param_list() {330            if let Some(param) = param_list.self_param() {331                let enabled = collector.check_cfg(&param);332                if enabled {333                    has_self_param = true;334                    params.push(match param.ty() {335                        Some(ty) => collector.lower_type_ref(ty, &mut impl_trait_lower_fn),336                        None => {337                            let self_type = collector.alloc_type_ref_desugared(TypeRef::Path(338                                Name::new_symbol_root(sym::Self_).into(),339                            ));340                            let lifetime = param341                                .lifetime()342                                .map(|lifetime| collector.lower_lifetime_ref(lifetime));343                            match param.kind() {344                                ast::SelfParamKind::Owned => self_type,345                                ast::SelfParamKind::Ref => collector.alloc_type_ref_desugared(346                                    TypeRef::Reference(Box::new(RefType {347                                        ty: self_type,348                                        lifetime,349                                        mutability: Mutability::Shared,350                                    })),351                                ),352                                ast::SelfParamKind::MutRef => collector.alloc_type_ref_desugared(353                                    TypeRef::Reference(Box::new(RefType {354                                        ty: self_type,355                                        lifetime,356                                        mutability: Mutability::Mut,357                                    })),358                                ),359                            }360                        }361                    });362                }363            }364            let p = param_list365                .params()366                .filter(|param| collector.check_cfg(param))367                .filter(|param| {368                    let is_variadic = param.dotdotdot_token().is_some();369                    has_variadic |= is_variadic;370                    !is_variadic371                })372                .map(|param| param.ty())373                // FIXME374                .collect::<Vec<_>>();375            for p in p {376                params.push(collector.lower_type_ref_opt(p, &mut impl_trait_lower_fn));377            }378        }379    });380    let generics = collector.finish();381    let return_type = fn_.value.ret_type().map(|ret_type| {382        expr_collector.lower_type_ref_opt(ret_type.ty(), &mut ExprCollector::impl_trait_allocator)383    });384385    let return_type = if fn_.value.async_token().is_some() || fn_.value.gen_token().is_some() {386        let (path, assoc_name) =387            match (fn_.value.async_token().is_some(), fn_.value.gen_token().is_some()) {388                (true, true) => {389                    (hir_expand::mod_path::path![core::async_iter::AsyncIterator], sym::Item)390                }391                (true, false) => (hir_expand::mod_path::path![core::future::Future], sym::Output),392                (false, true) => (hir_expand::mod_path::path![core::iter::Iterator], sym::Item),393                (false, false) => unreachable!(),394            };395        let mut generic_args: Vec<_> =396            std::iter::repeat_n(None, path.segments().len() - 1).collect();397        let binding = AssociatedTypeBinding {398            name: Name::new_symbol_root(assoc_name),399            args: None,400            type_ref: Some(401                return_type402                    .unwrap_or_else(|| expr_collector.alloc_type_ref_desugared(TypeRef::unit())),403            ),404            bounds: Box::default(),405        };406        generic_args407            .push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() }));408409        let path = Path::from_known_path(path, generic_args);410        let path = PathId::from_type_ref_unchecked(411            expr_collector.alloc_type_ref_desugared(TypeRef::Path(path)),412        );413        let ty_bound = TypeBound::Path(path, TraitBoundModifier::None);414        Some(415            expr_collector416                .alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound]))),417        )418    } else {419        return_type420    };421    let (store, source_map) = expr_collector.store.finish();422    (423        store,424        source_map,425        generics,426        params.into_boxed_slice(),427        return_type,428        has_self_param,429        has_variadic,430    )431}432433pub struct ExprCollector<'db> {434    db: &'db dyn DefDatabase,435    cfg_options: &'db CfgOptions,436    expander: Expander<'db>,437    def_map: &'db DefMap,438    local_def_map: &'db LocalDefMap,439    module: ModuleId,440    lang_items: OnceCell<&'db LangItems>,441    pub store: ExpressionStoreBuilder,442443    // state stuff444    // Prevent nested impl traits like `impl Foo<impl Bar>`.445    outer_impl_trait: bool,446447    is_lowering_coroutine: bool,448449    /// Legacy (`macro_rules!`) macros can have multiple definitions and shadow each other,450    /// and we need to find the current definition. So we track the number of definitions we saw.451    current_block_legacy_macro_defs_count: FxHashMap<Name, usize>,452453    current_try_block: Option<TryBlock>,454455    label_ribs: Vec<LabelRib>,456    unowned_bindings: Vec<BindingId>,457458    awaitable_context: Option<Awaitable>,459    krate: base_db::Crate,460461    name_generator_index: usize,462}463464#[derive(Clone, Debug)]465struct LabelRib {466    kind: RibKind,467}468469impl LabelRib {470    fn new(kind: RibKind) -> Self {471        LabelRib { kind }472    }473}474475#[derive(Clone, Debug, PartialEq, Eq)]476enum RibKind {477    Normal(Name, LabelId, HygieneId),478    Closure,479    Constant,480    MacroDef(Box<MacroDefId>),481}482483impl RibKind {484    /// This rib forbids referring to labels defined in upwards ribs.485    fn is_label_barrier(&self) -> bool {486        match self {487            RibKind::Normal(..) | RibKind::MacroDef(_) => false,488            RibKind::Closure | RibKind::Constant => true,489        }490    }491}492493#[derive(PartialEq, Eq, Debug, Copy, Clone)]494enum Awaitable {495    Yes,496    No(&'static str),497}498499enum TryBlock {500    // `try { ... }`501    Homogeneous { label: LabelId },502    // `try bikeshed Ty { ... }`503    Heterogeneous { label: LabelId },504}505506#[derive(Debug, Default)]507struct BindingList {508    map: FxHashMap<(Name, HygieneId), BindingId>,509    is_used: FxHashMap<BindingId, bool>,510    reject_new: bool,511}512513impl BindingList {514    fn find(515        &mut self,516        ec: &mut ExprCollector<'_>,517        name: Name,518        hygiene: HygieneId,519        mode: BindingAnnotation,520    ) -> BindingId {521        let id = *self522            .map523            .entry((name, hygiene))524            .or_insert_with_key(|(name, hygiene)| ec.alloc_binding(name.clone(), mode, *hygiene));525        if ec.store.bindings[id].mode != mode {526            ec.store.bindings[id].problems = Some(BindingProblems::BoundInconsistently);527        }528        self.check_is_used(ec, id);529        id530    }531532    fn check_is_used(&mut self, ec: &mut ExprCollector<'_>, id: BindingId) {533        match self.is_used.get(&id) {534            None => {535                if self.reject_new {536                    ec.store.bindings[id].problems = Some(BindingProblems::NotBoundAcrossAll);537                }538            }539            Some(true) => {540                ec.store.bindings[id].problems = Some(BindingProblems::BoundMoreThanOnce);541            }542            Some(false) => {}543        }544        self.is_used.insert(id, true);545    }546}547548impl<'db> ExprCollector<'db> {549    pub fn new(550        db: &dyn DefDatabase,551        module: ModuleId,552        current_file_id: HirFileId,553    ) -> ExprCollector<'_> {554        let (def_map, local_def_map) = module.local_def_map(db);555        let expander = Expander::new(db, current_file_id, def_map);556        let krate = module.krate(db);557        let mut result = ExprCollector {558            db,559            cfg_options: krate.cfg_options(db),560            module,561            def_map,562            local_def_map,563            lang_items: OnceCell::new(),564            store: ExpressionStoreBuilder::default(),565            expander,566            current_try_block: None,567            is_lowering_coroutine: false,568            label_ribs: Vec::new(),569            unowned_bindings: Vec::new(),570            awaitable_context: None,571            current_block_legacy_macro_defs_count: FxHashMap::default(),572            outer_impl_trait: false,573            krate,574            name_generator_index: 0,575        };576        result.store.inference_roots = Some(SmallVec::new());577        result578    }579580    fn generate_new_name(&mut self) -> Name {581        let index = self.name_generator_index;582        self.name_generator_index += 1;583        Name::generate_new_name(index)584    }585586    #[inline]587    pub(crate) fn lang_items(&self) -> &'db LangItems {588        self.lang_items.get_or_init(|| crate::lang_item::lang_items(self.db, self.def_map.krate()))589    }590591    #[inline]592    pub(crate) fn span_map(&self) -> SpanMap<'_> {593        self.expander.span_map()594    }595596    pub(in crate::expr_store) fn lower_lifetime_ref(597        &mut self,598        lifetime: ast::Lifetime,599    ) -> LifetimeRefId {600        // FIXME: Keyword check?601        let lifetime_ref = match &*lifetime.text() {602            "" | "'" => LifetimeRef::Error,603            "'static" => LifetimeRef::Static,604            "'_" => LifetimeRef::Placeholder,605            text => LifetimeRef::Named(Name::new_lifetime(text)),606        };607        self.alloc_lifetime_ref(lifetime_ref, AstPtr::new(&lifetime))608    }609610    pub(in crate::expr_store) fn lower_lifetime_ref_opt(611        &mut self,612        lifetime: Option<ast::Lifetime>,613    ) -> LifetimeRefId {614        match lifetime {615            Some(lifetime) => self.lower_lifetime_ref(lifetime),616            None => self.alloc_lifetime_ref_desugared(LifetimeRef::Placeholder),617        }618    }619620    /// Converts an `ast::TypeRef` to a `hir::TypeRef`.621    pub(in crate::expr_store) fn lower_type_ref(622        &mut self,623        node: ast::Type,624        impl_trait_lower_fn: ImplTraitLowerFn<'_>,625    ) -> TypeRefId {626        let ty = match &node {627            ast::Type::ParenType(inner) => {628                return self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);629            }630            ast::Type::TupleType(inner) => TypeRef::Tuple(ThinVec::from_iter(Vec::from_iter(631                inner.fields().map(|it| self.lower_type_ref(it, impl_trait_lower_fn)),632            ))),633            ast::Type::NeverType(..) => TypeRef::Never,634            ast::Type::PathType(inner) => inner635                .path()636                .and_then(|it| self.lower_path(it, impl_trait_lower_fn))637                .map(TypeRef::Path)638                .unwrap_or(TypeRef::Error),639            ast::Type::PtrType(inner) => {640                let inner_ty = self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);641                let mutability = Mutability::from_mutable(inner.mut_token().is_some());642                TypeRef::RawPtr(inner_ty, mutability)643            }644            ast::Type::ArrayType(inner) => {645                let len = self.lower_const_arg_opt(inner.const_arg());646                TypeRef::Array(ArrayType {647                    ty: self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn),648                    len,649                })650            }651            ast::Type::SliceType(inner) => {652                TypeRef::Slice(self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn))653            }654            ast::Type::RefType(inner) => {655                let inner_ty = self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);656                let lifetime = inner.lifetime().map(|lt| self.lower_lifetime_ref(lt));657                let mutability = Mutability::from_mutable(inner.mut_token().is_some());658                TypeRef::Reference(Box::new(RefType { ty: inner_ty, lifetime, mutability }))659            }660            ast::Type::InferType(_inner) => TypeRef::Placeholder,661            ast::Type::FnPtrType(inner) => {662                let ret_ty = inner663                    .ret_type()664                    .and_then(|rt| rt.ty())665                    .map(|it| self.lower_type_ref(it, impl_trait_lower_fn))666                    .unwrap_or_else(|| self.alloc_type_ref_desugared(TypeRef::unit()));667                let mut is_varargs = false;668                let mut params = if let Some(pl) = inner.param_list() {669                    if let Some(param) = pl.params().last() {670                        is_varargs = param.dotdotdot_token().is_some();671                    }672673                    pl.params()674                        .map(|it| {675                            let type_ref = self.lower_type_ref_opt(it.ty(), impl_trait_lower_fn);676                            let name = match it.pat() {677                                Some(ast::Pat::IdentPat(it)) => Some(678                                    it.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing),679                                ),680                                _ => None,681                            };682                            (name, type_ref)683                        })684                        .collect()685                } else {686                    Vec::with_capacity(1)687                };688                fn lower_abi(abi: ast::Abi) -> ExternAbi {689                    abi.abi_string()690                        .and_then(|abi| abi.text_without_quotes().parse().ok())691                        .unwrap_or(ExternAbi::FALLBACK)692                }693694                let abi = inner.abi().map(lower_abi).unwrap_or(ExternAbi::Rust);695                params.push((None, ret_ty));696                TypeRef::Fn(Box::new(FnType {697                    is_varargs,698                    is_unsafe: inner.unsafe_token().is_some(),699                    abi,700                    params: params.into_boxed_slice(),701                }))702            }703            // for types are close enough for our purposes to the inner type for now...704            ast::Type::ForType(inner) => {705                return self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);706            }707            ast::Type::ImplTraitType(inner) => {708                if self.outer_impl_trait {709                    // Disallow nested impl traits710                    TypeRef::Error711                } else {712                    return self.with_outer_impl_trait_scope(true, |this| {713                        let type_bounds =714                            this.type_bounds_from_ast(inner.type_bound_list(), impl_trait_lower_fn);715                        impl_trait_lower_fn(this, AstPtr::new(&node), type_bounds)716                    });717                }718            }719            ast::Type::DynTraitType(inner) => TypeRef::DynTrait(720                self.type_bounds_from_ast(inner.type_bound_list(), impl_trait_lower_fn),721            ),722            ast::Type::PatternType(inner) => TypeRef::PatternType(723                self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn),724                self.collect_ty_pat_opt(inner.pat()),725            ),726            ast::Type::MacroType(mt) => match mt.macro_call() {727                Some(mcall) => {728                    let macro_ptr = AstPtr::new(&mcall);729                    let src = self.expander.in_file(AstPtr::new(&node));730                    let id = self.collect_macro_call(mcall, macro_ptr, true, |this, expansion| {731                        this.lower_type_ref_opt(expansion, impl_trait_lower_fn)732                    });733                    self.store.types_map.insert(src, id);734                    return id;735                }736                None => TypeRef::Error,737            },738        };739        self.alloc_type_ref(ty, AstPtr::new(&node))740    }741742    pub(crate) fn lower_type_ref_disallow_impl_trait(&mut self, node: ast::Type) -> TypeRefId {743        self.lower_type_ref(node, &mut Self::impl_trait_error_allocator)744    }745746    pub(crate) fn lower_type_ref_opt(747        &mut self,748        node: Option<ast::Type>,749        impl_trait_lower_fn: ImplTraitLowerFn<'_>,750    ) -> TypeRefId {751        match node {752            Some(node) => self.lower_type_ref(node, impl_trait_lower_fn),753            None => self.alloc_error_type(),754        }755    }756757    pub(crate) fn lower_type_ref_opt_disallow_impl_trait(758        &mut self,759        node: Option<ast::Type>,760    ) -> TypeRefId {761        self.lower_type_ref_opt(node, &mut Self::impl_trait_error_allocator)762    }763764    fn alloc_type_ref(&mut self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {765        let id = self.store.types.alloc(type_ref);766        let ptr = self.expander.in_file(node);767        self.store.types_map_back.insert(id, ptr);768        self.store.types_map.insert(ptr, id);769        id770    }771772    fn alloc_lifetime_ref(773        &mut self,774        lifetime_ref: LifetimeRef,775        node: LifetimePtr,776    ) -> LifetimeRefId {777        let id = self.store.lifetimes.alloc(lifetime_ref);778        let ptr = self.expander.in_file(node);779        self.store.lifetime_map_back.insert(id, ptr);780        self.store.lifetime_map.insert(ptr, id);781        id782    }783784    fn alloc_type_ref_desugared(&mut self, type_ref: TypeRef) -> TypeRefId {785        self.store.types.alloc(type_ref)786    }787788    fn alloc_lifetime_ref_desugared(&mut self, lifetime_ref: LifetimeRef) -> LifetimeRefId {789        self.store.lifetimes.alloc(lifetime_ref)790    }791792    fn alloc_error_type(&mut self) -> TypeRefId {793        self.store.types.alloc(TypeRef::Error)794    }795796    pub fn lower_path(797        &mut self,798        ast: ast::Path,799        impl_trait_lower_fn: ImplTraitLowerFn<'_>,800    ) -> Option<Path> {801        super::lower::path::lower_path(self, ast, impl_trait_lower_fn)802    }803804    fn with_outer_impl_trait_scope<R>(805        &mut self,806        impl_trait: bool,807        f: impl FnOnce(&mut Self) -> R,808    ) -> R {809        let old = mem::replace(&mut self.outer_impl_trait, impl_trait);810        let result = f(self);811        self.outer_impl_trait = old;812        result813    }814815    pub fn impl_trait_error_allocator(816        ec: &mut ExprCollector<'_>,817        ptr: TypePtr,818        _: ThinVec<TypeBound>,819    ) -> TypeRefId {820        ec.alloc_type_ref(TypeRef::Error, ptr)821    }822823    fn impl_trait_allocator(824        ec: &mut ExprCollector<'_>,825        ptr: TypePtr,826        bounds: ThinVec<TypeBound>,827    ) -> TypeRefId {828        ec.alloc_type_ref(TypeRef::ImplTrait(bounds), ptr)829    }830831    fn alloc_path(&mut self, path: Path, node: TypePtr) -> PathId {832        PathId::from_type_ref_unchecked(self.alloc_type_ref(TypeRef::Path(path), node))833    }834835    /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)836    /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).837    pub(in crate::expr_store) fn lower_generic_args_from_fn_path(838        &mut self,839        args: Option<ast::ParenthesizedArgList>,840        ret_type: Option<ast::RetType>,841        impl_trait_lower_fn: ImplTraitLowerFn<'_>,842    ) -> Option<GenericArgs> {843        let params = args?;844        let mut param_types = Vec::new();845        for param in params.type_args() {846            let type_ref = self.lower_type_ref_opt(param.ty(), impl_trait_lower_fn);847            param_types.push(type_ref);848        }849        let args = Box::new([GenericArg::Type(850            self.alloc_type_ref_desugared(TypeRef::Tuple(ThinVec::from_iter(param_types))),851        )]);852        let bindings = if let Some(ret_type) = ret_type {853            let type_ref = self.lower_type_ref_opt(ret_type.ty(), impl_trait_lower_fn);854            Box::new([AssociatedTypeBinding {855                name: Name::new_symbol_root(sym::Output),856                args: None,857                type_ref: Some(type_ref),858                bounds: Box::default(),859            }])860        } else {861            // -> ()862            let type_ref = self.alloc_type_ref_desugared(TypeRef::unit());863            Box::new([AssociatedTypeBinding {864                name: Name::new_symbol_root(sym::Output),865                args: None,866                type_ref: Some(type_ref),867                bounds: Box::default(),868            }])869        };870        Some(GenericArgs {871            args,872            has_self_type: false,873            bindings,874            parenthesized: GenericArgsParentheses::ParenSugar,875        })876    }877878    pub(super) fn lower_generic_args(879        &mut self,880        node: ast::GenericArgList,881        impl_trait_lower_fn: ImplTraitLowerFn<'_>,882    ) -> Option<GenericArgs> {883        // This needs to be kept in sync with `hir_generic_arg_to_ast()`.884        let mut args = Vec::new();885        let mut bindings = Vec::new();886        for generic_arg in node.generic_args() {887            match generic_arg {888                ast::GenericArg::TypeArg(type_arg) => {889                    let type_ref = self.lower_type_ref_opt(type_arg.ty(), impl_trait_lower_fn);890                    args.push(GenericArg::Type(type_ref));891                }892                ast::GenericArg::AssocTypeArg(assoc_type_arg) => {893                    // This needs to be kept in sync with `hir_assoc_type_binding_to_ast()`.894                    if assoc_type_arg.param_list().is_some() {895                        // We currently ignore associated return type bounds.896                        continue;897                    }898                    if let Some(name_ref) = assoc_type_arg.name_ref() {899                        // Nested impl traits like `impl Foo<Assoc = impl Bar>` are allowed900                        self.with_outer_impl_trait_scope(false, |this| {901                            let name = name_ref.as_name();902                            let args = assoc_type_arg903                                .generic_arg_list()904                                .and_then(|args| this.lower_generic_args(args, impl_trait_lower_fn))905                                .or_else(|| {906                                    assoc_type_arg907                                        .return_type_syntax()908                                        .map(|_| GenericArgs::return_type_notation())909                                });910                            let type_ref = assoc_type_arg911                                .ty()912                                .map(|it| this.lower_type_ref(it, impl_trait_lower_fn));913                            let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {914                                l.bounds()915                                    .map(|it| this.lower_type_bound(it, impl_trait_lower_fn))916                                    .collect()917                            } else {918                                Box::default()919                            };920                            bindings.push(AssociatedTypeBinding { name, args, type_ref, bounds });921                        });922                    }923                }924                ast::GenericArg::LifetimeArg(lifetime_arg) => {925                    if let Some(lifetime) = lifetime_arg.lifetime() {926                        let lifetime_ref = self.lower_lifetime_ref(lifetime);927                        args.push(GenericArg::Lifetime(lifetime_ref))928                    }929                }930                ast::GenericArg::ConstArg(arg) => {931                    let arg = self.lower_const_arg(arg);932                    args.push(GenericArg::Const(arg))933                }934            }935        }936937        if args.is_empty() && bindings.is_empty() {938            return None;939        }940        Some(GenericArgs {941            args: args.into_boxed_slice(),942            has_self_type: false,943            bindings: bindings.into_boxed_slice(),944            parenthesized: GenericArgsParentheses::No,945        })946    }947948    /// Lowers a desugared coroutine body after moving all of the arguments949    /// into the body. This is to make sure that the future actually owns the950    /// arguments that are passed to the function, and to ensure things like951    /// drop order are stable.952    fn lower_coroutine_body_with_moved_arguments(953        &mut self,954        self_params: &mut ArrayVec<BindingId, 2>,955        params: &mut [PatId],956        body: ExprId,957        kind: CoroutineKind,958        coroutine_source: CoroutineSource,959    ) -> ExprId {960        // Async function parameters are lowered into the closure body so that they are961        // captured and so that the drop order matches the equivalent non-async functions.962        //963        // from:964        //965        //     async fn foo(<pattern>: <ty>, <pattern>: <ty>, <pattern>: <ty>) {966        //         <body>967        //     }968        //969        // into:970        //971        //     fn foo(__arg0: <ty>, __arg1: <ty>, __arg2: <ty>) {972        //       async move {973        //         let __arg2 = __arg2;974        //         let <pattern> = __arg2;975        //         let __arg1 = __arg1;976        //         let <pattern> = __arg1;977        //         let __arg0 = __arg0;978        //         let <pattern> = __arg0;979        //         drop-temps { <body> } // see comments later in fn for details980        //       }981        //     }982        //983        // If `<pattern>` is a simple ident, then it is lowered to a single984        // `let <pattern> = <pattern>;` statement as an optimization.985986        let mut statements = Vec::new();987988        if let Some(&self_param) = self_params.first() {989            let Binding { ref name, mode, hygiene, .. } = self.store.bindings[self_param];990            let name = name.clone();991            let child_binding_id = self.alloc_binding(name.clone(), mode, hygiene);992            let child_pat_id =993                self.alloc_pat_desugared(Pat::Bind { id: child_binding_id, subpat: None });994            self.add_definition_to_binding(child_binding_id, child_pat_id);995            let expr = self.alloc_expr_desugared(Expr::Path(name.into()));996            if !hygiene.is_root() {997                self.store.ident_hygiene.insert(expr.into(), hygiene);998            }999            statements.push(Statement::Let {1000                pat: child_pat_id,1001                type_ref: None,1002                initializer: Some(expr),1003                else_branch: None,1004            });1005            self_params.push(child_binding_id);1006        }10071008        for param in params {1009            let (name, hygiene, is_simple_parameter) = match self.store.pats[*param] {1010                // Check if this is a binding pattern, if so, we can optimize and avoid adding a1011                // `let <pat> = __argN;` statement. In this case, we do not rename the parameter.1012                Pat::Bind { id, subpat: None, .. }1013                    if matches!(1014                        self.store.bindings[id].mode,1015                        BindingAnnotation::Unannotated | BindingAnnotation::Mutable1016                    ) =>1017                {1018                    (self.store.bindings[id].name.clone(), self.store.bindings[id].hygiene, true)1019                }1020                Pat::Bind { id, .. } => {1021                    // If this is a `ref` binding, we can't leave it as is but we can at least reuse the name, for better display.1022                    (self.store.bindings[id].name.clone(), self.store.bindings[id].hygiene, false)1023                }1024                _ => (self.generate_new_name(), HygieneId::ROOT, false),1025            };1026            let pat_syntax = self.store.pat_map_back.get(*param).copied();1027            let child_binding_id =1028                self.alloc_binding(name.clone(), BindingAnnotation::Mutable, hygiene);1029            let child_pat_id =1030                self.alloc_pat_desugared(Pat::Bind { id: child_binding_id, subpat: None });1031            self.add_definition_to_binding(child_binding_id, child_pat_id);1032            if let Some(pat_syntax) = pat_syntax {1033                self.store.pat_map_back.insert(child_pat_id, pat_syntax);1034            }1035            let expr = self.alloc_expr_desugared(Expr::Path(name.clone().into()));1036            if !hygiene.is_root() {1037                self.store.ident_hygiene.insert(expr.into(), hygiene);1038            }1039            statements.push(Statement::Let {1040                pat: child_pat_id,1041                type_ref: None,1042                initializer: Some(expr),1043                else_branch: None,1044            });1045            if !is_simple_parameter {1046                let expr = self.alloc_expr_desugared(Expr::Path(name.clone().into()));1047                if !hygiene.is_root() {1048                    self.store.ident_hygiene.insert(expr.into(), hygiene);1049                }1050                statements.push(Statement::Let {1051                    pat: *param,1052                    type_ref: None,1053                    initializer: Some(expr),1054                    else_branch: None,1055                });10561057                let parent_binding_id =1058                    self.alloc_binding(name.clone(), BindingAnnotation::Mutable, hygiene);1059                let parent_pat_id =1060                    self.alloc_pat_desugared(Pat::Bind { id: parent_binding_id, subpat: None });1061                self.add_definition_to_binding(parent_binding_id, parent_pat_id);1062                if let Some(pat_syntax) = pat_syntax {1063                    self.store.pat_map_back.insert(parent_pat_id, pat_syntax);1064                }1065                *param = parent_pat_id;1066            }1067        }10681069        let coroutine = self.desugared_coroutine_expr(1070            kind,1071            coroutine_source,1072            // The default capture mode here is by-ref. Later on during upvar analysis,1073            // we will force the captured arguments to by-move, but for async closures,1074            // we want to make sure that we avoid unnecessarily moving captures, or else1075            // all async closures would default to `FnOnce` as their calling mode.1076            CaptureBy::Ref,1077            None,1078            statements.into_boxed_slice(),1079            Some(body),1080        );1081        // It's important that this comes last, see the lowering of async closures for why.1082        self.alloc_expr_desugared(coroutine)1083    }10841085    fn desugared_coroutine_expr(1086        &mut self,1087        kind: CoroutineKind,1088        source: CoroutineSource,1089        capture_by: CaptureBy,1090        id: Option<BlockId>,1091        statements: Box<[Statement]>,1092        tail: Option<ExprId>,1093    ) -> Expr {1094        let block = self.alloc_expr_desugared(Expr::Block { label: None, id, statements, tail });1095        Expr::Closure {1096            args: Box::default(),1097            arg_types: Box::default(),1098            ret_type: None,1099            body: block,1100            closure_kind: ClosureKind::Coroutine { kind, source },1101            capture_by,1102        }1103    }11041105    fn collect(1106        &mut self,1107        self_params: &mut ArrayVec<BindingId, 2>,1108        params: &mut [PatId],1109        expr: Option<ast::Expr>,1110        awaitable: Awaitable,1111        is_async_fn: bool,1112        is_gen_fn: bool,1113    ) -> ExprId {1114        self.awaitable_context.replace(awaitable);1115        self.with_label_rib(RibKind::Closure, |this| {1116            let body = this.collect_expr_opt(expr);1117            if is_async_fn || is_gen_fn {1118                let kind = match (is_async_fn, is_gen_fn) {1119                    (true, true) => CoroutineKind::AsyncGen,1120                    (true, false) => CoroutineKind::Async,1121                    (false, true) => CoroutineKind::Gen,1122                    (false, false) => unreachable!(),1123                };1124                this.lower_coroutine_body_with_moved_arguments(1125                    self_params,1126                    params,1127                    body,1128                    kind,1129                    CoroutineSource::Fn,1130                )1131            } else {1132                body1133            }1134        })1135    }11361137    fn type_bounds_from_ast(1138        &mut self,1139        type_bounds_opt: Option<ast::TypeBoundList>,1140        impl_trait_lower_fn: ImplTraitLowerFn<'_>,1141    ) -> ThinVec<TypeBound> {1142        if let Some(type_bounds) = type_bounds_opt {1143            ThinVec::from_iter(Vec::from_iter(1144                type_bounds.bounds().map(|it| self.lower_type_bound(it, impl_trait_lower_fn)),1145            ))1146        } else {1147            ThinVec::from_iter([])1148        }1149    }11501151    fn lower_path_type(1152        &mut self,1153        path_type: &ast::PathType,1154        impl_trait_lower_fn: ImplTraitLowerFn<'_>,1155    ) -> Option<Path> {1156        let path = self.lower_path(path_type.path()?, impl_trait_lower_fn)?;1157        Some(path)1158    }11591160    fn lower_type_bound(1161        &mut self,1162        node: ast::TypeBound,1163        impl_trait_lower_fn: ImplTraitLowerFn<'_>,1164    ) -> TypeBound {1165        let Some(kind) = node.kind() else { return TypeBound::Error };1166        match kind {1167            ast::TypeBoundKind::PathType(binder, path_type) => {1168                let binder = match binder.and_then(|it| it.generic_param_list()) {1169                    Some(gpl) => gpl1170                        .lifetime_params()1171                        .flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(&lt.text())))1172                        .collect(),1173                    None => ThinVec::default(),1174                };1175                let m = match node.question_mark_token() {1176                    Some(_) => TraitBoundModifier::Maybe,1177                    None => TraitBoundModifier::None,1178                };1179                self.lower_path_type(&path_type, impl_trait_lower_fn)1180                    .map(|p| {1181                        let path = self.alloc_path(p, AstPtr::new(&path_type).upcast());1182                        if binder.is_empty() {1183                            TypeBound::Path(path, m)1184                        } else {1185                            TypeBound::ForLifetime(binder, path)1186                        }1187                    })1188                    .unwrap_or(TypeBound::Error)1189            }1190            ast::TypeBoundKind::Use(gal) => TypeBound::Use(1191                gal.use_bound_generic_args()1192                    .map(|p| match p {1193                        ast::UseBoundGenericArg::Lifetime(l) => {1194                            UseArgRef::Lifetime(self.lower_lifetime_ref(l))1195                        }1196                        ast::UseBoundGenericArg::NameRef(n) => UseArgRef::Name(n.as_name()),1197                    })1198                    .collect(),1199            ),1200            ast::TypeBoundKind::Lifetime(lifetime) => {1201                TypeBound::Lifetime(self.lower_lifetime_ref(lifetime))1202            }1203        }1204    }12051206    fn lower_const_arg_opt(&mut self, arg: Option<ast::ConstArg>) -> ConstRef {1207        ConstRef {1208            expr: self.with_fresh_binding_expr_root(|this| {1209                this.collect_expr_opt(arg.and_then(|arg| arg.expr()))1210            }),1211        }1212    }12131214    pub fn lower_const_arg(&mut self, arg: ast::ConstArg) -> ConstRef {1215        ConstRef {1216            expr: self.with_fresh_binding_expr_root(|this| this.collect_expr_opt(arg.expr())),1217        }1218    }12191220    fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {1221        self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr())1222    }12231224    pub(in crate::expr_store) fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {1225        match expr {1226            Some(expr) => self.collect_expr(expr),1227            None => self.missing_expr(),1228        }1229    }12301231    /// Returns `None` if and only if the expression is `#[cfg]`d out.1232    fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {1233        let syntax_ptr = AstPtr::new(&expr);1234        if !self.check_cfg(&expr) {1235            return None;1236        }12371238        // FIXME: Move some of these arms out into separate methods for clarity1239        Some(match expr {1240            ast::Expr::IfExpr(e) => {1241                let then_branch = self.collect_block_opt(e.then_branch());12421243                let else_branch = e.else_branch().map(|b| match b {1244                    ast::ElseBranch::Block(it) => self.collect_block(it),1245                    ast::ElseBranch::IfExpr(elif) => {1246                        let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();1247                        self.collect_expr(expr)1248                    }1249                });12501251                let condition = self.collect_expr_opt(e.condition());12521253                self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)1254            }1255            ast::Expr::LetExpr(e) => {1256                let pat = self.collect_pat_top(e.pat());1257                let expr = self.collect_expr_opt(e.expr());1258                self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr)1259            }1260            ast::Expr::BlockExpr(e) => match e.modifier() {1261                Some(ast::BlockModifier::Try { try_token: _, bikeshed_token: _, result_type }) => {1262                    self.desugar_try_block(e, result_type)1263                }1264                Some(ast::BlockModifier::Unsafe(_)) => {1265                    self.collect_block_(e, |_, id, statements, tail| Expr::Unsafe {1266                        id,1267                        statements,1268                        tail,1269                    })1270                }1271                Some(ast::BlockModifier::Label(label)) => {1272                    let label_hygiene = self.hygiene_id_for(label.syntax().text_range());1273                    let label_id = self.collect_label(label);1274                    self.with_labeled_rib(label_id, label_hygiene, |this| {1275                        this.collect_block_(e, |_, id, statements, tail| Expr::Block {1276                            id,1277                            statements,1278                            tail,1279                            label: Some(label_id),1280                        })1281                    })1282                }1283                Some(ast::BlockModifier::Async(_)) => {1284                    let capture_by =1285                        if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };1286                    self.with_label_rib(RibKind::Closure, |this| {1287                        this.with_awaitable_block(Awaitable::Yes, |this| {1288                            this.collect_block_(e, |this, id, statements, tail| {1289                                this.desugared_coroutine_expr(1290                                    CoroutineKind::Async,1291                                    CoroutineSource::Block,1292                                    capture_by,1293                                    id,1294                                    statements,1295                                    tail,1296                                )1297                            })1298                        })1299                    })1300                }1301                Some(ast::BlockModifier::Gen(_)) => {1302                    let capture_by =1303                        if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };1304                    self.with_label_rib(RibKind::Closure, |this| {1305                        this.with_awaitable_block(Awaitable::No("non-async gen block"), |this| {1306                            this.collect_block_(e, |this, id, statements, tail| {1307                                this.desugared_coroutine_expr(1308                                    CoroutineKind::Gen,1309                                    CoroutineSource::Block,1310                                    capture_by,1311                                    id,1312                                    statements,1313                                    tail,1314                                )1315                            })1316                        })1317                    })1318                }1319                Some(ast::BlockModifier::AsyncGen(_)) => {1320                    let capture_by =1321                        if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };1322                    self.with_label_rib(RibKind::Closure, |this| {1323                        this.with_awaitable_block(Awaitable::Yes, |this| {1324                            this.collect_block_(e, |this, id, statements, tail| {1325                                this.desugared_coroutine_expr(1326                                    CoroutineKind::AsyncGen,1327                                    CoroutineSource::Block,1328                                    capture_by,1329                                    id,1330                                    statements,1331                                    tail,1332                                )1333                            })1334                        })1335                    })1336                }1337                Some(ast::BlockModifier::Const(_)) => {1338                    self.with_label_rib(RibKind::Constant, |this| {1339                        this.with_awaitable_block(Awaitable::No("constant block"), |this| {1340                            this.with_binding_owner(|this| {1341                                let inner_expr = this.collect_block(e);1342                                this.alloc_expr(Expr::Const(inner_expr), syntax_ptr)1343                            })1344                        })1345                    })1346                }1347                None => self.collect_block(e),1348            },1349            ast::Expr::LoopExpr(e) => {1350                let label = e.label().map(|label| {1351                    (self.hygiene_id_for(label.syntax().text_range()), self.collect_label(label))1352                });1353                let body = self.collect_labelled_block_opt(label, e.loop_body());1354                self.alloc_expr(Expr::Loop { body, label: label.map(|it| it.1), source: LoopSource::Loop }, syntax_ptr)1355            }1356            ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e),1357            ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e),1358            ast::Expr::CallExpr(e) => {1359                // FIXME(MINIMUM_SUPPORTED_TOOLCHAIN_VERSION): Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c1360                let is_rustc_box = {1361                    let attrs = e.attrs();1362                    attrs.filter_map(|it| it.as_simple_atom()).any(|it| it == "rustc_box")1363                };1364                if is_rustc_box {1365                    let expr = self.collect_expr_opt(e.arg_list().and_then(|it| it.args().next()));1366                    self.alloc_expr(Expr::Box { expr }, syntax_ptr)1367                } else {1368                    let callee = self.collect_expr_opt(e.expr());1369                    let args = if let Some(arg_list) = e.arg_list() {1370                        arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()1371                    } else {1372                        Box::default()1373                    };1374                    self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)1375                }1376            }1377            ast::Expr::MethodCallExpr(e) => {1378                let receiver = self.collect_expr_opt(e.receiver());1379                let args = if let Some(arg_list) = e.arg_list() {1380                    arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()1381                } else {1382                    Box::default()1383                };1384                let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);1385                let generic_args = e1386                    .generic_arg_list()1387                    .and_then(|it| {1388                        self.lower_generic_args(it, &mut Self::impl_trait_error_allocator)1389                    })1390                    .map(Box::new);1391                self.alloc_expr(1392                    Expr::MethodCall { receiver, method_name, args, generic_args },1393                    syntax_ptr,1394                )1395            }1396            ast::Expr::MatchExpr(e) => {1397                let expr = self.collect_expr_opt(e.expr());1398                let arms = if let Some(match_arm_list) = e.match_arm_list() {1399                    match_arm_list1400                        .arms()1401                        .filter_map(|arm| {1402                            if self.check_cfg(&arm) {1403                                Some(MatchArm {1404                                    pat: self.collect_pat_top(arm.pat()),1405                                    expr: self.collect_expr_opt(arm.expr()),1406                                    guard: arm1407                                        .guard()1408                                        .map(|guard| self.collect_expr_opt(guard.condition())),1409                                })1410                            } else {1411                                None1412                            }1413                        })1414                        .collect()1415                } else {1416                    Box::default()1417                };1418                self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)1419            }1420            ast::Expr::PathExpr(e) => {1421                let (path, hygiene) = self1422                    .collect_expr_path(e)1423                    .map(|(path, hygiene)| (Expr::Path(path), hygiene))1424                    .unwrap_or((Expr::Missing, HygieneId::ROOT));1425                let expr_id = self.alloc_expr(path, syntax_ptr);1426                if !hygiene.is_root() {1427                    self.store.ident_hygiene.insert(expr_id.into(), hygiene);1428                }1429                expr_id1430            }1431            ast::Expr::ContinueExpr(e) => {1432                let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {1433                    self.store.diagnostics.push(e);1434                    None1435                });1436                self.alloc_expr(Expr::Continue { label }, syntax_ptr)1437            }1438            ast::Expr::BreakExpr(e) => {1439                let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {1440                    self.store.diagnostics.push(e);1441                    None1442                });1443                let expr = e.expr().map(|e| self.collect_expr(e));1444                self.alloc_expr(Expr::Break { expr, label }, syntax_ptr)1445            }1446            ast::Expr::ParenExpr(e) => {1447                let inner = self.collect_expr_opt(e.expr());1448                // make the paren expr point to the inner expression as well for IDE resolution1449                let src = self.expander.in_file(syntax_ptr);1450                self.store.expr_map.insert(src, inner.into());1451                inner1452            }1453            ast::Expr::ReturnExpr(e) => {1454                let expr = e.expr().map(|e| self.collect_expr(e));1455                self.alloc_expr(Expr::Return { expr }, syntax_ptr)1456            }1457            ast::Expr::BecomeExpr(e) => {1458                let expr =1459                    e.expr().map(|e| self.collect_expr(e)).unwrap_or_else(|| self.missing_expr());1460                self.alloc_expr(Expr::Become { expr }, syntax_ptr)1461            }1462            ast::Expr::YieldExpr(e) => {1463                self.is_lowering_coroutine = true;1464                let expr = e.expr().map(|e| self.collect_expr(e));1465                self.alloc_expr(Expr::Yield { expr }, syntax_ptr)1466            }1467            ast::Expr::YeetExpr(e) => {1468                let expr = e.expr().map(|e| self.collect_expr(e));1469                self.alloc_expr(Expr::Yeet { expr }, syntax_ptr)1470            }1471            ast::Expr::RecordExpr(e) => {1472                let path = e1473                    .path()1474                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator));1475                let Some(path) = path else {1476                    return Some(self.missing_expr());1477                };1478                let record_lit = if let Some(nfl) = e.record_expr_field_list() {1479                    let fields = nfl1480                        .fields()1481                        .filter_map(|field| {1482                            if !self.check_cfg(&field) {1483                                return None;1484                            }14851486                            let name = field.field_name()?.as_name();14871488                            let expr = match field.expr() {1489                                Some(e) => self.collect_expr(e),1490                                None => self.missing_expr(),1491                            };1492                            let src = self.expander.in_file(AstPtr::new(&field));1493                            self.store.field_map_back.insert(expr, src);1494                            Some(RecordLitField { name, expr })1495                        })1496                        .collect();1497                    let spread_expr = nfl.spread().map(|s| self.collect_expr(s));1498                    let has_spread_syntax = nfl.dotdot_token().is_some();1499                    let spread = match (spread_expr, has_spread_syntax) {1500                        (None, false) => RecordSpread::None,1501                        (None, true) => RecordSpread::FieldDefaults,1502                        (Some(expr), _) => RecordSpread::Expr(expr),1503                    };1504                    Expr::RecordLit { path, fields, spread }1505                } else {1506                    Expr::RecordLit { path, fields: Box::default(), spread: RecordSpread::None }1507                };15081509                self.alloc_expr(record_lit, syntax_ptr)1510            }1511            ast::Expr::FieldExpr(e) => {1512                let expr = self.collect_expr_opt(e.expr());1513                let name = match e.field_access() {1514                    Some(kind) => kind.as_name(),1515                    _ => Name::missing(),1516                };1517                self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)1518            }1519            ast::Expr::AwaitExpr(e) => {1520                let expr = self.collect_expr_opt(e.expr());1521                if let Awaitable::No(location) = self.is_lowering_awaitable_block() {1522                    self.store.diagnostics.push(ExpressionStoreDiagnostics::AwaitOutsideOfAsync {1523                        node: self.expander.in_file(AstPtr::new(&e)),1524                        location: location.to_string(),1525                    });1526                }1527                self.alloc_expr(Expr::Await { expr }, syntax_ptr)1528            }1529            ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e),1530            ast::Expr::CastExpr(e) => {1531                let expr = self.collect_expr_opt(e.expr());1532                let type_ref = self.lower_type_ref_opt_disallow_impl_trait(e.ty());1533                self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)1534            }1535            ast::Expr::RefExpr(e) => {1536                let expr = self.collect_expr_opt(e.expr());1537                let raw_tok = e.raw_token().is_some();1538                let mutability = if raw_tok {1539                    if e.mut_token().is_some() { Mutability::Mut } else { Mutability::Shared }1540                } else {1541                    Mutability::from_mutable(e.mut_token().is_some())1542                };1543                let rawness = Rawness::from_raw(raw_tok);1544                self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)1545            }1546            ast::Expr::PrefixExpr(e) => {1547                let expr = self.collect_expr_opt(e.expr());1548                match e.op_kind() {1549                    Some(op) => self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr),1550                    None => self.alloc_expr(Expr::Missing, syntax_ptr),1551                }1552            }1553            ast::Expr::ClosureExpr(e) => self.with_label_rib(RibKind::Closure, |this| {1554                let mut is_coroutine_closure = false;1555                let closure = this.with_binding_owner_and_return(|this| {1556                    let mut args = Vec::new();1557                    let mut arg_types = Vec::new();1558                    // For coroutine closures, the body, aka. the coroutine is the bindings owner, and not the closure.1559                    if let Some(pl) = e.param_list() {1560                        let num_params = pl.params().count();1561                        args.reserve_exact(num_params);1562                        arg_types.reserve_exact(num_params);1563                        for param in pl.params() {1564                            let pat = this.collect_pat_top(param.pat());1565                            let type_ref =1566                                param.ty().map(|it| this.lower_type_ref_disallow_impl_trait(it));1567                            args.push(pat);1568                            arg_types.push(type_ref);1569                        }1570                    }1571                    let ret_type = e1572                        .ret_type()1573                        .and_then(|r| r.ty())1574                        .map(|it| this.lower_type_ref_disallow_impl_trait(it));15751576                    let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);1577                    let prev_try_block = this.current_try_block.take();15781579                    let awaitable = if e.async_token().is_some() {1580                        Awaitable::Yes1581                    } else {1582                        Awaitable::No("non-async closure")1583                    };1584                    let mut body = this1585                        .with_awaitable_block(awaitable, |this| this.collect_expr_opt(e.body()));1586                    let kind = {1587                        if e.async_token().is_some() && e.gen_token().is_some() {1588                            Some(CoroutineKind::AsyncGen)1589                        } else if e.async_token().is_some() {1590                            Some(CoroutineKind::Async)1591                        } else if e.gen_token().is_some() {1592                            Some(CoroutineKind::Gen)1593                        } else {1594                            None1595                        }1596                    };15971598                    let closure_kind = if let Some(kind) = kind {1599                        // It's important that this expr is allocated immediately before the closure.1600                        // We rely on it for `coroutine_for_closure()`.1601                        body = this.lower_coroutine_body_with_moved_arguments(1602                            &mut ArrayVec::new(),1603                            &mut args,1604                            body,1605                            kind,1606                            CoroutineSource::Closure,1607                        );1608                        is_coroutine_closure = true;16091610                        ClosureKind::CoroutineClosure(kind)1611                    } else if this.is_lowering_coroutine {1612                        let movability = if e.static_token().is_some() {1613                            Movability::Static1614                        } else {1615                            Movability::Movable1616                        };1617                        ClosureKind::OldCoroutine(movability)1618                    } else {1619                        ClosureKind::Closure1620                    };1621                    let capture_by =1622                        if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };1623                    this.is_lowering_coroutine = prev_is_lowering_coroutine;1624                    this.current_try_block = prev_try_block;1625                    let closure = this.alloc_expr(1626                        Expr::Closure {1627                            args: args.into(),1628                            arg_types: arg_types.into(),1629                            ret_type,1630                            body,1631                            closure_kind,1632                            capture_by,1633                        },1634                        syntax_ptr,1635                    );16361637                    (if is_coroutine_closure { body } else { closure }, closure)1638                });16391640                if is_coroutine_closure {1641                    let Expr::Closure { args, .. } = &this.store.exprs[closure] else {1642                        unreachable!()1643                    };1644                    for &arg in args {1645                        let Pat::Bind { id, .. } = this.store.pats[arg] else {1646                            never!("`lower_coroutine_body_with_moved_arguments()` should make sure the coroutine closure only have simple bind args");1647                            continue;1648                        };1649                        this.store.binding_owners.insert(id, closure);1650                    }1651                }16521653                closure1654            }),1655            ast::Expr::BinExpr(e) => {1656                let op = e.op_kind();1657                if let Some(ast::BinaryOp::Assignment { op: None }) = op {1658                    let target = self.collect_expr_as_pat_opt(e.lhs());1659                    let value = self.collect_expr_opt(e.rhs());1660                    self.alloc_expr(Expr::Assignment { target, value }, syntax_ptr)1661                } else {1662                    let lhs = self.collect_expr_opt(e.lhs());1663                    let rhs = self.collect_expr_opt(e.rhs());1664                    self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)1665                }1666            }1667            ast::Expr::TupleExpr(e) => {1668                let mut exprs: Vec<_> = e.fields().map(|expr| self.collect_expr(expr)).collect();1669                // if there is a leading comma, the user is most likely to type out a leading expression1670                // so we insert a missing expression at the beginning for IDE features1671                if comma_follows_token(e.l_paren_token()) {1672                    exprs.insert(0, self.missing_expr());1673                }16741675                self.alloc_expr(Expr::Tuple { exprs: exprs.into_boxed_slice() }, syntax_ptr)1676            }1677            ast::Expr::ArrayExpr(e) => {1678                let kind = e.kind();16791680                match kind {1681                    ArrayExprKind::ElementList(e) => {1682                        let elements = e1683                            .filter_map(|expr| {1684                                if self.check_cfg(&expr) {1685                                    Some(self.collect_expr(expr))1686                                } else {1687                                    None1688                                }1689                            })1690                            .collect();1691                        self.alloc_expr(Expr::Array(Array::ElementList { elements }), syntax_ptr)1692                    }1693                    ArrayExprKind::Repeat { initializer, repeat } => {1694                        let initializer = self.collect_expr_opt(initializer);1695                        let repeat = self.with_label_rib(RibKind::Constant, |this| {1696                            if let Some(repeat) = repeat {1697                                this.with_binding_owner(|this| this.collect_expr(repeat))1698                            } else {1699                                this.missing_expr()1700                            }1701                        });1702                        self.alloc_expr(1703                            Expr::Array(Array::Repeat { initializer, repeat }),1704                            syntax_ptr,1705                        )1706                    }1707                }1708            }17091710            ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr),1711            ast::Expr::IndexExpr(e) => {1712                let base = self.collect_expr_opt(e.base());1713                let index = self.collect_expr_opt(e.index());1714                self.alloc_expr(Expr::Index { base, index }, syntax_ptr)1715            }1716            ast::Expr::RangeExpr(e) => {1717                let lhs = e.start().map(|lhs| self.collect_expr(lhs));1718                let rhs = e.end().map(|rhs| self.collect_expr(rhs));1719                match e.op_kind() {1720                    Some(range_type) => {1721                        self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)1722                    }1723                    None => self.alloc_expr(Expr::Missing, syntax_ptr),1724                }1725            }1726            ast::Expr::MacroExpr(e) => {1727                let e = e.macro_call()?;1728                let macro_ptr = AstPtr::new(&e);1729                let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {1730                    expansion.map(|it| this.collect_expr(it))1731                });1732                match id {1733                    Some(id) => {1734                        // Make the macro-call point to its expanded expression so we can query1735                        // semantics on syntax pointers to the macro1736                        let src = self.expander.in_file(syntax_ptr);1737                        self.store.expr_map.insert(src, id.into());1738                        id1739                    }1740                    None => self.alloc_expr(Expr::Missing, syntax_ptr),1741                }1742            }1743            ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),1744            ast::Expr::AsmExpr(e) => self.lower_inline_asm(e, syntax_ptr),1745            ast::Expr::OffsetOfExpr(e) => {1746                let container = self.lower_type_ref_opt_disallow_impl_trait(e.ty());1747                let fields = e.fields().map(|it| it.as_name()).collect();1748                self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)1749            }1750            ast::Expr::FormatArgsExpr(f) => self.collect_format_args(f, syntax_ptr),1751            ast::Expr::IncludeBytesExpr(_) => self.alloc_expr(Expr::IncludeBytes, syntax_ptr)1752        })1753    }17541755    fn collect_expr_path(&mut self, e: ast::PathExpr) -> Option<(Path, HygieneId)> {1756        e.path().and_then(|path| {1757            let path = self.lower_path(path, &mut Self::impl_trait_error_allocator)?;1758            // Need to enable `mod_path.len() < 1` for `self`.1759            let may_be_variable = matches!(&path, Path::BarePath(mod_path) if mod_path.len() <= 1);1760            let hygiene = if may_be_variable {1761                self.hygiene_id_for(e.syntax().text_range())1762            } else {1763                HygieneId::ROOT1764            };1765            Some((path, hygiene))1766        })1767    }17681769    /// Whether this path should be lowered as destructuring assignment, or as a normal assignment.1770    fn path_is_destructuring_assignment(&self, path: &ModPath) -> bool {1771        // rustc has access to a full resolver here, including local variables and generic params, and it checks the following1772        // criteria: a path not lowered as destructuring assignment if it can *fully resolve* to something that is *not*1773        // a const, a unit struct or a variant.1774        // We don't have access to a full resolver here. So we should do the same as rustc, but assuming that local variables1775        // could be resolved to nothing (fortunately, there cannot be a local variable shadowing a unit struct/variant/const,1776        // as that is an error). We don't need to consider const params as it's an error to refer to these in patterns.1777        let (resolution, unresolved_idx, _) = self.def_map.resolve_path_locally(1778            self.local_def_map,1779            self.db,1780            self.module,1781            path,1782            BuiltinShadowMode::Other,1783        );1784        match unresolved_idx {1785            Some(_) => {1786                // If `Some(_)`, path could be resolved to unit struct/variant/const with type information, i.e. an assoc type or const.1787                // If `None`, path could be a local variable.1788                resolution.take_types().is_some()1789            }1790            None => match resolution.take_values() {1791                // We don't need to consider non-unit structs/variants, as those are not value types.1792                Some(ModuleDefId::EnumVariantId(_))1793                | Some(ModuleDefId::AdtId(_))1794                | Some(ModuleDefId::ConstId(_)) => true,1795                _ => false,1796            },1797        }1798    }17991800    fn collect_expr_as_pat_opt(&mut self, expr: Option<ast::Expr>) -> PatId {1801        match expr {1802            Some(expr) => self.collect_expr_as_pat(expr),1803            _ => self.missing_pat(),1804        }1805    }18061807    fn collect_expr_as_pat(&mut self, expr: ast::Expr) -> PatId {1808        self.maybe_collect_expr_as_pat(&expr).unwrap_or_else(|| {1809            let src = self.expander.in_file(AstPtr::new(&expr).wrap_left());1810            let expr = self.collect_expr(expr);1811            // Do not use `alloc_pat_from_expr()` here, it will override the entry in `expr_map`.1812            let id = self.store.pats.alloc(Pat::Expr(expr));1813            self.store.pat_map_back.insert(id, src);1814            id1815        })1816    }18171818    fn maybe_collect_expr_as_pat(&mut self, expr: &ast::Expr) -> Option<PatId> {1819        if !self.check_cfg(expr) {1820            return None;1821        }1822        let syntax_ptr = AstPtr::new(expr);18231824        let result = match expr {1825            ast::Expr::UnderscoreExpr(_) => self.alloc_pat_from_expr(Pat::Wild, syntax_ptr),1826            ast::Expr::ParenExpr(e) => {1827                // We special-case `(..)` for consistency with patterns.1828                if let Some(ast::Expr::RangeExpr(range)) = e.expr()1829                    && range.is_range_full()1830                {1831                    return Some(self.alloc_pat_from_expr(1832                        Pat::Tuple { args: Box::default(), ellipsis: Some(0) },1833                        syntax_ptr,1834                    ));1835                }1836                return e.expr().and_then(|expr| self.maybe_collect_expr_as_pat(&expr));1837            }1838            ast::Expr::TupleExpr(e) => {1839                let (ellipsis, args) = collect_tuple(self, e.fields());1840                self.alloc_pat_from_expr(Pat::Tuple { args, ellipsis }, syntax_ptr)1841            }1842            ast::Expr::ArrayExpr(e) => {1843                if e.semicolon_token().is_some() {1844                    return None;1845                }18461847                let mut elements = e.exprs();1848                let prefix = elements1849                    .by_ref()1850                    .map_while(|elem| collect_possibly_rest(self, elem).left())1851                    .collect();1852                let suffix = elements.map(|elem| self.collect_expr_as_pat(elem)).collect();1853                self.alloc_pat_from_expr(Pat::Slice { prefix, slice: None, suffix }, syntax_ptr)1854            }1855            ast::Expr::CallExpr(e) => {1856                let path = collect_path(self, e.expr()?)?;1857                let path = path1858                    .path()1859                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator));1860                let Some(path) = path else {1861                    return Some(self.missing_pat());1862                };1863                let (ellipsis, args) = collect_tuple(self, e.arg_list()?.args());1864                self.alloc_pat_from_expr(Pat::TupleStruct { path, args, ellipsis }, syntax_ptr)1865            }1866            ast::Expr::PathExpr(e) => {1867                let (path, hygiene) = self.collect_expr_path(e.clone())?;1868                let mod_path = path.mod_path().expect("should not lower to lang path");1869                if self.path_is_destructuring_assignment(mod_path) {1870                    let pat_id = self.alloc_pat_from_expr(Pat::Path(path), syntax_ptr);1871                    if !hygiene.is_root() {1872                        self.store.ident_hygiene.insert(pat_id.into(), hygiene);1873                    }1874                    pat_id1875                } else {1876                    return None;1877                }1878            }1879            ast::Expr::MacroExpr(e) => {1880                let e = e.macro_call()?;1881                let macro_ptr = AstPtr::new(&e);1882                let src = self.expander.in_file(AstPtr::new(expr));1883                let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {1884                    this.collect_expr_as_pat_opt(expansion)1885                });1886                self.store.expr_map.insert(src, id.into());1887                id1888            }1889            ast::Expr::RecordExpr(e) => {1890                let path = e1891                    .path()1892                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator));1893                let Some(path) = path else {1894                    return Some(self.missing_pat());1895                };1896                let record_field_list = e.record_expr_field_list()?;1897                let ellipsis = record_field_list.dotdot_token().is_some();1898                if let Some(spread) = record_field_list.spread() {1899                    self.store.diagnostics.push(1900                        ExpressionStoreDiagnostics::FruInDestructuringAssignment {1901                            node: self.expander.in_file(AstPtr::new(&spread)),1902                        },1903                    );1904                }1905                let args = record_field_list1906                    .fields()1907                    .filter_map(|f| {1908                        if !self.check_cfg(&f) {1909                            return None;1910                        }1911                        let field_expr = f.expr()?;1912                        let pat = self.collect_expr_as_pat(field_expr);1913                        let name = f.field_name()?.as_name();1914                        let src = self.expander.in_file(AstPtr::new(&f).wrap_left());1915                        self.store.pat_field_map_back.insert(pat, src);1916                        Some(RecordFieldPat { name, pat })1917                    })1918                    .collect();1919                self.alloc_pat_from_expr(Pat::Record { path, args, ellipsis }, syntax_ptr)1920            }1921            _ => return None,1922        };1923        return Some(result);19241925        fn collect_path(this: &mut ExprCollector<'_>, expr: ast::Expr) -> Option<ast::PathExpr> {1926            match expr {1927                ast::Expr::PathExpr(e) => Some(e),1928                ast::Expr::MacroExpr(mac) => {1929                    let call = mac.macro_call()?;1930                    {1931                        let macro_ptr = AstPtr::new(&call);1932                        this.collect_macro_call(call, macro_ptr, true, |this, expanded_path| {1933                            collect_path(this, expanded_path?)1934                        })1935                    }1936                }1937                _ => None,1938            }1939        }19401941        fn collect_possibly_rest(1942            this: &mut ExprCollector<'_>,1943            expr: ast::Expr,1944        ) -> Either<PatId, ()> {1945            match &expr {1946                ast::Expr::RangeExpr(e) if e.is_range_full() => Either::Right(()),1947                ast::Expr::MacroExpr(mac) => match mac.macro_call() {1948                    Some(call) => {1949                        let macro_ptr = AstPtr::new(&call);1950                        let pat = this.collect_macro_call(1951                            call,1952                            macro_ptr,1953                            true,1954                            |this, expanded_expr| match expanded_expr {1955                                Some(expanded_pat) => collect_possibly_rest(this, expanded_pat),1956                                None => Either::Left(this.missing_pat()),1957                            },1958                        );1959                        if let Either::Left(pat) = pat {1960                            let src = this.expander.in_file(AstPtr::new(&expr).wrap_left());1961                            this.store.pat_map_back.insert(pat, src);1962                        }1963                        pat1964                    }1965                    None => {1966                        let ptr = AstPtr::new(&expr);1967                        Either::Left(this.alloc_pat_from_expr(Pat::Missing, ptr))1968                    }1969                },1970                _ => Either::Left(this.collect_expr_as_pat(expr)),1971            }1972        }19731974        fn collect_tuple(1975            this: &mut ExprCollector<'_>,1976            fields: ast::AstChildren<ast::Expr>,1977        ) -> (Option<u32>, Box<[la_arena::Idx<Pat>]>) {1978            let mut ellipsis = None;1979            let args = fields1980                .enumerate()1981                .filter_map(|(idx, elem)| {1982                    match collect_possibly_rest(this, elem) {1983                        Either::Left(pat) => Some(pat),1984                        Either::Right(()) => {1985                            if ellipsis.is_none() {1986                                ellipsis = Some(idx as u32);1987                            }1988                            // FIXME: Report an error here otherwise.1989                            None1990                        }1991                    }1992                })1993                .collect();1994            (ellipsis, args)1995        }1996    }19971998    /// The callback should return two exprs: the first is the bindings owner, the second is the expr to return.1999    fn with_binding_owner_and_return(2000        &mut self,

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.