src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs RUST 3,032 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 3,032.
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 base_db::FxIndexSet;12use cfg::CfgOptions;13use either::Either;14use hir_expand::{15    HirFileId, InFile, MacroDefId,16    name::{AsName, Name},17    span_map::SpanMapRef,18};19use intern::{Symbol, sym};20use rustc_hash::FxHashMap;21use smallvec::smallvec;22use stdx::never;23use syntax::{24    AstNode, AstPtr, SyntaxNodePtr,25    ast::{26        self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasGenericArgs,27        HasGenericParams, HasLoopBody, HasName, HasTypeBounds, IsString, RangeItem,28        SlicePatComponents,29    },30};31use thin_vec::ThinVec;32use tt::TextRange;3334use crate::{35    AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, ItemContainerId,36    MacroId, ModuleDefId, ModuleId, TraitId, TypeAliasId, UnresolvedMacro,37    attrs::AttrFlags,38    db::DefDatabase,39    expr_store::{40        Body, BodySourceMap, ExprPtr, ExpressionStore, ExpressionStoreBuilder,41        ExpressionStoreDiagnostics, ExpressionStoreSourceMap, HygieneId, LabelPtr, LifetimePtr,42        PatPtr, RootExprOrigin, 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        CoroutineSource, Expr, ExprId, Item, Label, LabelId, Literal, MatchArm, Movability,50        OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, RecordSpread, Statement,51        generics::GenericParams,52    },53    item_scope::BuiltinShadowMode,54    item_tree::FieldsShape,55    lang_item::{LangItemTarget, LangItems},56    nameres::{DefMap, LocalDefMap, MacroSubNs, block_def_map},57    signatures::StructSignature,58    type_ref::{59        ArrayType, ConstRef, FnType, LifetimeRef, LifetimeRefId, Mutability, PathId, Rawness,60        RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, UseArgRef,61    },62};6364pub use self::path::hir_segment_to_ast_segment;6566pub(super) fn lower_body(67    db: &dyn DefDatabase,68    owner: DefWithBodyId,69    current_file_id: HirFileId,70    module: ModuleId,71    parameters: Option<ast::ParamList>,72    body: Option<ast::Expr>,73    is_async_fn: bool,74) -> (Body, BodySourceMap) {75    // We cannot leave the root span map empty and let any identifier from it be treated as root,76    // because when inside nested macros `SyntaxContextId`s from the outer macro will be interleaved77    // with the inner macro, and that will cause confusion because they won't be the same as `ROOT`78    // even though they should be the same. Also, when the body comes from multiple expansions, their79    // hygiene is different.8081    let mut self_param = None;82    let mut source_map_self_param = None;83    let mut params = vec![];84    let mut collector = ExprCollector::body(db, module, current_file_id);8586    let skip_body = AttrFlags::query(87        db,88        match owner {89            DefWithBodyId::FunctionId(it) => it.into(),90            DefWithBodyId::StaticId(it) => it.into(),91            DefWithBodyId::ConstId(it) => it.into(),92            DefWithBodyId::VariantId(it) => it.into(),93        },94    )95    .contains(AttrFlags::RUST_ANALYZER_SKIP);96    // If #[rust_analyzer::skip] annotated, only construct enough information for the signature97    // and skip the body.98    if skip_body {99        if let Some(param_list) = parameters {100            if let Some(self_param_syn) =101                param_list.self_param().filter(|self_param| collector.check_cfg(self_param))102            {103                let is_mutable =104                    self_param_syn.mut_token().is_some() && self_param_syn.amp_token().is_none();105                let hygiene = self_param_syn106                    .name()107                    .map(|name| collector.hygiene_id_for(name.syntax().text_range()))108                    .unwrap_or(HygieneId::ROOT);109                let binding_id: la_arena::Idx<Binding> = collector.alloc_binding(110                    Name::new_symbol_root(sym::self_),111                    BindingAnnotation::new(is_mutable, false),112                    hygiene,113                );114                self_param = Some(binding_id);115                source_map_self_param =116                    Some(collector.expander.in_file(AstPtr::new(&self_param_syn)));117            }118            let count = param_list.params().filter(|it| collector.check_cfg(it)).count();119            params = (0..count).map(|_| collector.missing_pat()).collect();120        };121        let body_expr = collector.missing_expr();122        collector.store.inference_roots = Some(smallvec![(body_expr, RootExprOrigin::BodyRoot)]);123        let (store, source_map) = collector.store.finish();124        return (125            Body { store, params: params.into_boxed_slice(), self_param },126            BodySourceMap { self_param: source_map_self_param, store: source_map },127        );128    }129130    if let Some(param_list) = parameters {131        if let Some(self_param_syn) = param_list.self_param().filter(|it| collector.check_cfg(it)) {132            let is_mutable =133                self_param_syn.mut_token().is_some() && self_param_syn.amp_token().is_none();134            let hygiene = self_param_syn135                .name()136                .map(|name| collector.hygiene_id_for(name.syntax().text_range()))137                .unwrap_or(HygieneId::ROOT);138            let binding_id: la_arena::Idx<Binding> = collector.alloc_binding(139                Name::new_symbol_root(sym::self_),140                BindingAnnotation::new(is_mutable, false),141                hygiene,142            );143            self_param = Some(binding_id);144            source_map_self_param = Some(collector.expander.in_file(AstPtr::new(&self_param_syn)));145        }146147        let is_extern = matches!(148            owner,149            DefWithBodyId::FunctionId(id)150                if matches!(id.loc(db).container, ItemContainerId::ExternBlockId(_)),151        );152153        for param in param_list.params() {154            if collector.check_cfg(&param) {155                let param_pat = if is_extern {156                    collector.collect_extern_fn_param(param.pat())157                } else {158                    collector.collect_pat_top(param.pat())159                };160                params.push(param_pat);161            }162        }163    };164165    let body_expr = collector.collect(166        &mut params,167        body,168        if is_async_fn {169            Awaitable::Yes170        } else {171            match owner {172                DefWithBodyId::FunctionId(..) => Awaitable::No("non-async function"),173                DefWithBodyId::StaticId(..) => Awaitable::No("static"),174                DefWithBodyId::ConstId(..) => Awaitable::No("constant"),175                DefWithBodyId::VariantId(..) => Awaitable::No("enum variant"),176            }177        },178    );179    collector.store.inference_roots = Some(smallvec![(body_expr, RootExprOrigin::BodyRoot)]);180181    let (store, source_map) = collector.store.finish();182    (183        Body { store, params: params.into_boxed_slice(), self_param },184        BodySourceMap { self_param: source_map_self_param, store: source_map },185    )186}187188pub(crate) fn lower_type_ref(189    db: &dyn DefDatabase,190    module: ModuleId,191    type_ref: InFile<Option<ast::Type>>,192) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId) {193    let mut expr_collector = ExprCollector::signature(db, module, type_ref.file_id);194    let type_ref =195        expr_collector.lower_type_ref_opt(type_ref.value, &mut ExprCollector::impl_trait_allocator);196    let (store, source_map) = expr_collector.store.finish();197    (store, source_map, type_ref)198}199200pub(crate) fn lower_generic_params(201    db: &dyn DefDatabase,202    module: ModuleId,203    def: GenericDefId,204    file_id: HirFileId,205    param_list: Option<ast::GenericParamList>,206    where_clause: Option<ast::WhereClause>,207) -> (ExpressionStore, GenericParams, ExpressionStoreSourceMap) {208    let mut expr_collector = ExprCollector::signature(db, module, file_id);209    let mut collector = generics::GenericParamsCollector::new(def);210    collector.lower(&mut expr_collector, param_list, where_clause);211    let params = collector.finish();212    let (store, source_map) = expr_collector.store.finish();213    (store, params, source_map)214}215216pub(crate) fn lower_impl(217    db: &dyn DefDatabase,218    module: ModuleId,219    impl_syntax: InFile<ast::Impl>,220    impl_id: ImplId,221) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId, Option<TraitRef>, GenericParams) {222    let mut expr_collector = ExprCollector::signature(db, module, impl_syntax.file_id);223    let self_ty =224        expr_collector.lower_type_ref_opt_disallow_impl_trait(impl_syntax.value.self_ty());225    let trait_ = impl_syntax.value.trait_().and_then(|it| match &it {226        ast::Type::PathType(path_type) => {227            let path = expr_collector228                .lower_path_type(path_type, &mut ExprCollector::impl_trait_allocator)?;229            Some(TraitRef { path: expr_collector.alloc_path(path, AstPtr::new(&it)) })230        }231        _ => None,232    });233    let mut collector = generics::GenericParamsCollector::new(impl_id.into());234    collector.lower(235        &mut expr_collector,236        impl_syntax.value.generic_param_list(),237        impl_syntax.value.where_clause(),238    );239    let params = collector.finish();240    let (store, source_map) = expr_collector.store.finish();241    (store, source_map, self_ty, trait_, params)242}243244pub(crate) fn lower_trait(245    db: &dyn DefDatabase,246    module: ModuleId,247    trait_syntax: InFile<ast::Trait>,248    trait_id: TraitId,249) -> (ExpressionStore, ExpressionStoreSourceMap, GenericParams) {250    let mut expr_collector = ExprCollector::signature(db, module, trait_syntax.file_id);251    let mut collector = generics::GenericParamsCollector::with_self_param(252        &mut expr_collector,253        trait_id.into(),254        trait_syntax.value.type_bound_list(),255    );256    collector.lower(257        &mut expr_collector,258        trait_syntax.value.generic_param_list(),259        trait_syntax.value.where_clause(),260    );261    let params = collector.finish();262    let (store, source_map) = expr_collector.store.finish();263    (store, source_map, params)264}265266pub(crate) fn lower_type_alias(267    db: &dyn DefDatabase,268    module: ModuleId,269    alias: InFile<ast::TypeAlias>,270    type_alias_id: TypeAliasId,271) -> (ExpressionStore, ExpressionStoreSourceMap, GenericParams, Box<[TypeBound]>, Option<TypeRefId>)272{273    let mut expr_collector = ExprCollector::signature(db, module, alias.file_id);274    let bounds = alias275        .value276        .type_bound_list()277        .map(|bounds| {278            bounds279                .bounds()280                .map(|bound| {281                    expr_collector.lower_type_bound(bound, &mut ExprCollector::impl_trait_allocator)282                })283                .collect()284        })285        .unwrap_or_default();286    let mut collector = generics::GenericParamsCollector::new(type_alias_id.into());287    collector.lower(288        &mut expr_collector,289        alias.value.generic_param_list(),290        alias.value.where_clause(),291    );292    let params = collector.finish();293    let type_ref = alias294        .value295        .ty()296        .map(|ty| expr_collector.lower_type_ref(ty, &mut ExprCollector::impl_trait_allocator));297    let (store, source_map) = expr_collector.store.finish();298    (store, source_map, params, bounds, type_ref)299}300301pub(crate) fn lower_function(302    db: &dyn DefDatabase,303    module: ModuleId,304    fn_: InFile<ast::Fn>,305    function_id: FunctionId,306) -> (307    ExpressionStore,308    ExpressionStoreSourceMap,309    GenericParams,310    Box<[TypeRefId]>,311    Option<TypeRefId>,312    bool,313    bool,314) {315    let mut expr_collector = ExprCollector::signature(db, module, fn_.file_id);316    let mut collector = generics::GenericParamsCollector::new(function_id.into());317    collector.lower(&mut expr_collector, fn_.value.generic_param_list(), fn_.value.where_clause());318    let mut params = vec![];319    let mut has_self_param = false;320    let mut has_variadic = false;321    collector.collect_impl_trait(&mut expr_collector, |collector, mut impl_trait_lower_fn| {322        if let Some(param_list) = fn_.value.param_list() {323            if let Some(param) = param_list.self_param() {324                let enabled = collector.check_cfg(&param);325                if enabled {326                    has_self_param = true;327                    params.push(match param.ty() {328                        Some(ty) => collector.lower_type_ref(ty, &mut impl_trait_lower_fn),329                        None => {330                            let self_type = collector.alloc_type_ref_desugared(TypeRef::Path(331                                Name::new_symbol_root(sym::Self_).into(),332                            ));333                            let lifetime = param334                                .lifetime()335                                .map(|lifetime| collector.lower_lifetime_ref(lifetime));336                            match param.kind() {337                                ast::SelfParamKind::Owned => self_type,338                                ast::SelfParamKind::Ref => collector.alloc_type_ref_desugared(339                                    TypeRef::Reference(Box::new(RefType {340                                        ty: self_type,341                                        lifetime,342                                        mutability: Mutability::Shared,343                                    })),344                                ),345                                ast::SelfParamKind::MutRef => collector.alloc_type_ref_desugared(346                                    TypeRef::Reference(Box::new(RefType {347                                        ty: self_type,348                                        lifetime,349                                        mutability: Mutability::Mut,350                                    })),351                                ),352                            }353                        }354                    });355                }356            }357            let p = param_list358                .params()359                .filter(|param| collector.check_cfg(param))360                .filter(|param| {361                    let is_variadic = param.dotdotdot_token().is_some();362                    has_variadic |= is_variadic;363                    !is_variadic364                })365                .map(|param| param.ty())366                // FIXME367                .collect::<Vec<_>>();368            for p in p {369                params.push(collector.lower_type_ref_opt(p, &mut impl_trait_lower_fn));370            }371        }372    });373    let generics = collector.finish();374    let return_type = fn_.value.ret_type().map(|ret_type| {375        expr_collector.lower_type_ref_opt(ret_type.ty(), &mut ExprCollector::impl_trait_allocator)376    });377378    let return_type = if fn_.value.async_token().is_some() {379        let path = hir_expand::mod_path::path![core::future::Future];380        let mut generic_args: Vec<_> =381            std::iter::repeat_n(None, path.segments().len() - 1).collect();382        let binding = AssociatedTypeBinding {383            name: Name::new_symbol_root(sym::Output),384            args: None,385            type_ref: Some(386                return_type387                    .unwrap_or_else(|| expr_collector.alloc_type_ref_desugared(TypeRef::unit())),388            ),389            bounds: Box::default(),390        };391        generic_args392            .push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() }));393394        let path = Path::from_known_path(path, generic_args);395        let path = PathId::from_type_ref_unchecked(396            expr_collector.alloc_type_ref_desugared(TypeRef::Path(path)),397        );398        let ty_bound = TypeBound::Path(path, TraitBoundModifier::None);399        Some(400            expr_collector401                .alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound]))),402        )403    } else {404        return_type405    };406    let (store, source_map) = expr_collector.store.finish();407    (408        store,409        source_map,410        generics,411        params.into_boxed_slice(),412        return_type,413        has_self_param,414        has_variadic,415    )416}417418pub struct ExprCollector<'db> {419    db: &'db dyn DefDatabase,420    cfg_options: &'db CfgOptions,421    expander: Expander<'db>,422    def_map: &'db DefMap,423    local_def_map: &'db LocalDefMap,424    module: ModuleId,425    lang_items: OnceCell<&'db LangItems>,426    pub store: ExpressionStoreBuilder,427428    // state stuff429    // Prevent nested impl traits like `impl Foo<impl Bar>`.430    outer_impl_trait: bool,431432    is_lowering_coroutine: bool,433434    /// Legacy (`macro_rules!`) macros can have multiple definitions and shadow each other,435    /// and we need to find the current definition. So we track the number of definitions we saw.436    current_block_legacy_macro_defs_count: FxHashMap<Name, usize>,437438    current_try_block: Option<TryBlock>,439440    label_ribs: Vec<LabelRib>,441    unowned_bindings: Vec<BindingId>,442443    awaitable_context: Option<Awaitable>,444    krate: base_db::Crate,445446    name_generator_index: usize,447}448449#[derive(Clone, Debug)]450struct LabelRib {451    kind: RibKind,452}453454impl LabelRib {455    fn new(kind: RibKind) -> Self {456        LabelRib { kind }457    }458}459460#[derive(Clone, Debug, PartialEq, Eq)]461enum RibKind {462    Normal(Name, LabelId, HygieneId),463    Closure,464    Constant,465    MacroDef(Box<MacroDefId>),466}467468impl RibKind {469    /// This rib forbids referring to labels defined in upwards ribs.470    fn is_label_barrier(&self) -> bool {471        match self {472            RibKind::Normal(..) | RibKind::MacroDef(_) => false,473            RibKind::Closure | RibKind::Constant => true,474        }475    }476}477478#[derive(PartialEq, Eq, Debug, Copy, Clone)]479enum Awaitable {480    Yes,481    No(&'static str),482}483484enum TryBlock {485    // `try { ... }`486    Homogeneous { label: LabelId },487    // `try bikeshed Ty { ... }`488    Heterogeneous { label: LabelId },489}490491#[derive(Debug, Default)]492struct BindingList {493    map: FxHashMap<(Name, HygieneId), BindingId>,494    is_used: FxHashMap<BindingId, bool>,495    reject_new: bool,496}497498impl BindingList {499    fn find(500        &mut self,501        ec: &mut ExprCollector<'_>,502        name: Name,503        hygiene: HygieneId,504        mode: BindingAnnotation,505    ) -> BindingId {506        let id = *self507            .map508            .entry((name, hygiene))509            .or_insert_with_key(|(name, hygiene)| ec.alloc_binding(name.clone(), mode, *hygiene));510        if ec.store.bindings[id].mode != mode {511            ec.store.bindings[id].problems = Some(BindingProblems::BoundInconsistently);512        }513        self.check_is_used(ec, id);514        id515    }516517    fn check_is_used(&mut self, ec: &mut ExprCollector<'_>, id: BindingId) {518        match self.is_used.get(&id) {519            None => {520                if self.reject_new {521                    ec.store.bindings[id].problems = Some(BindingProblems::NotBoundAcrossAll);522                }523            }524            Some(true) => {525                ec.store.bindings[id].problems = Some(BindingProblems::BoundMoreThanOnce);526            }527            Some(false) => {}528        }529        self.is_used.insert(id, true);530    }531}532533impl<'db> ExprCollector<'db> {534    /// Creates a collector for a signature store, this will populate `const_expr_origins` to any535    /// top level const arg roots.536    pub fn signature(537        db: &dyn DefDatabase,538        module: ModuleId,539        current_file_id: HirFileId,540    ) -> ExprCollector<'_> {541        let mut this = Self::body(db, module, current_file_id);542        this.store.inference_roots = Some(Default::default());543        this544    }545546    /// Creates a collector for a bidy store.547    pub fn body(548        db: &dyn DefDatabase,549        module: ModuleId,550        current_file_id: HirFileId,551    ) -> ExprCollector<'_> {552        let (def_map, local_def_map) = module.local_def_map(db);553        let expander = Expander::new(db, current_file_id, def_map);554        let krate = module.krate(db);555        ExprCollector {556            db,557            cfg_options: krate.cfg_options(db),558            module,559            def_map,560            local_def_map,561            lang_items: OnceCell::new(),562            store: ExpressionStoreBuilder::default(),563            expander,564            current_try_block: None,565            is_lowering_coroutine: false,566            label_ribs: Vec::new(),567            unowned_bindings: Vec::new(),568            awaitable_context: None,569            current_block_legacy_macro_defs_count: FxHashMap::default(),570            outer_impl_trait: false,571            krate,572            name_generator_index: 0,573        }574    }575576    fn generate_new_name(&mut self) -> Name {577        let index = self.name_generator_index;578        self.name_generator_index += 1;579        Name::generate_new_name(index)580    }581582    #[inline]583    pub(crate) fn lang_items(&self) -> &'db LangItems {584        self.lang_items.get_or_init(|| crate::lang_item::lang_items(self.db, self.def_map.krate()))585    }586587    #[inline]588    pub(crate) fn span_map(&self) -> SpanMapRef<'_> {589        self.expander.span_map()590    }591592    pub(in crate::expr_store) fn lower_lifetime_ref(593        &mut self,594        lifetime: ast::Lifetime,595    ) -> LifetimeRefId {596        // FIXME: Keyword check?597        let lifetime_ref = match &*lifetime.text() {598            "" | "'" => LifetimeRef::Error,599            "'static" => LifetimeRef::Static,600            "'_" => LifetimeRef::Placeholder,601            text => LifetimeRef::Named(Name::new_lifetime(text)),602        };603        self.alloc_lifetime_ref(lifetime_ref, AstPtr::new(&lifetime))604    }605606    pub(in crate::expr_store) fn lower_lifetime_ref_opt(607        &mut self,608        lifetime: Option<ast::Lifetime>,609    ) -> LifetimeRefId {610        match lifetime {611            Some(lifetime) => self.lower_lifetime_ref(lifetime),612            None => self.alloc_lifetime_ref_desugared(LifetimeRef::Placeholder),613        }614    }615616    /// Converts an `ast::TypeRef` to a `hir::TypeRef`.617    pub(in crate::expr_store) fn lower_type_ref(618        &mut self,619        node: ast::Type,620        impl_trait_lower_fn: ImplTraitLowerFn<'_>,621    ) -> TypeRefId {622        let ty = match &node {623            ast::Type::ParenType(inner) => {624                return self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);625            }626            ast::Type::TupleType(inner) => TypeRef::Tuple(ThinVec::from_iter(Vec::from_iter(627                inner.fields().map(|it| self.lower_type_ref(it, impl_trait_lower_fn)),628            ))),629            ast::Type::NeverType(..) => TypeRef::Never,630            ast::Type::PathType(inner) => inner631                .path()632                .and_then(|it| self.lower_path(it, impl_trait_lower_fn))633                .map(TypeRef::Path)634                .unwrap_or(TypeRef::Error),635            ast::Type::PtrType(inner) => {636                let inner_ty = self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);637                let mutability = Mutability::from_mutable(inner.mut_token().is_some());638                TypeRef::RawPtr(inner_ty, mutability)639            }640            ast::Type::ArrayType(inner) => {641                let len = self.lower_const_arg_opt(inner.const_arg());642                if let Some(const_expr_origins) = &mut self.store.inference_roots {643                    const_expr_origins.push((len.expr, RootExprOrigin::ArrayLength));644                }645                TypeRef::Array(ArrayType {646                    ty: self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn),647                    len,648                })649            }650            ast::Type::SliceType(inner) => {651                TypeRef::Slice(self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn))652            }653            ast::Type::RefType(inner) => {654                let inner_ty = self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);655                let lifetime = inner.lifetime().map(|lt| self.lower_lifetime_ref(lt));656                let mutability = Mutability::from_mutable(inner.mut_token().is_some());657                TypeRef::Reference(Box::new(RefType { ty: inner_ty, lifetime, mutability }))658            }659            ast::Type::InferType(_inner) => TypeRef::Placeholder,660            ast::Type::FnPtrType(inner) => {661                let ret_ty = inner662                    .ret_type()663                    .and_then(|rt| rt.ty())664                    .map(|it| self.lower_type_ref(it, impl_trait_lower_fn))665                    .unwrap_or_else(|| self.alloc_type_ref_desugared(TypeRef::unit()));666                let mut is_varargs = false;667                let mut params = if let Some(pl) = inner.param_list() {668                    if let Some(param) = pl.params().last() {669                        is_varargs = param.dotdotdot_token().is_some();670                    }671672                    pl.params()673                        .map(|it| {674                            let type_ref = self.lower_type_ref_opt(it.ty(), impl_trait_lower_fn);675                            let name = match it.pat() {676                                Some(ast::Pat::IdentPat(it)) => Some(677                                    it.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing),678                                ),679                                _ => None,680                            };681                            (name, type_ref)682                        })683                        .collect()684                } else {685                    Vec::with_capacity(1)686                };687                fn lower_abi(abi: ast::Abi) -> Symbol {688                    match abi.abi_string() {689                        Some(tok) => Symbol::intern(tok.text_without_quotes()),690                        // `extern` default to be `extern "C"`.691                        _ => sym::C,692                    }693                }694695                let abi = inner.abi().map(lower_abi);696                params.push((None, ret_ty));697                TypeRef::Fn(Box::new(FnType {698                    is_varargs,699                    is_unsafe: inner.unsafe_token().is_some(),700                    abi,701                    params: params.into_boxed_slice(),702                }))703            }704            // for types are close enough for our purposes to the inner type for now...705            ast::Type::ForType(inner) => {706                return self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn);707            }708            ast::Type::ImplTraitType(inner) => {709                if self.outer_impl_trait {710                    // Disallow nested impl traits711                    TypeRef::Error712                } else {713                    return self.with_outer_impl_trait_scope(true, |this| {714                        let type_bounds =715                            this.type_bounds_from_ast(inner.type_bound_list(), impl_trait_lower_fn);716                        impl_trait_lower_fn(this, AstPtr::new(&node), type_bounds)717                    });718                }719            }720            ast::Type::DynTraitType(inner) => TypeRef::DynTrait(721                self.type_bounds_from_ast(inner.type_bound_list(), impl_trait_lower_fn),722            ),723            ast::Type::MacroType(mt) => match mt.macro_call() {724                Some(mcall) => {725                    let macro_ptr = AstPtr::new(&mcall);726                    let src = self.expander.in_file(AstPtr::new(&node));727                    let id = self.collect_macro_call(mcall, macro_ptr, true, |this, expansion| {728                        this.lower_type_ref_opt(expansion, impl_trait_lower_fn)729                    });730                    self.store.types_map.insert(src, id);731                    return id;732                }733                None => TypeRef::Error,734            },735        };736        self.alloc_type_ref(ty, AstPtr::new(&node))737    }738739    pub(crate) fn lower_type_ref_disallow_impl_trait(&mut self, node: ast::Type) -> TypeRefId {740        self.lower_type_ref(node, &mut Self::impl_trait_error_allocator)741    }742743    pub(crate) fn lower_type_ref_opt(744        &mut self,745        node: Option<ast::Type>,746        impl_trait_lower_fn: ImplTraitLowerFn<'_>,747    ) -> TypeRefId {748        match node {749            Some(node) => self.lower_type_ref(node, impl_trait_lower_fn),750            None => self.alloc_error_type(),751        }752    }753754    pub(crate) fn lower_type_ref_opt_disallow_impl_trait(755        &mut self,756        node: Option<ast::Type>,757    ) -> TypeRefId {758        self.lower_type_ref_opt(node, &mut Self::impl_trait_error_allocator)759    }760761    fn alloc_type_ref(&mut self, type_ref: TypeRef, node: TypePtr) -> TypeRefId {762        let id = self.store.types.alloc(type_ref);763        let ptr = self.expander.in_file(node);764        self.store.types_map_back.insert(id, ptr);765        self.store.types_map.insert(ptr, id);766        id767    }768769    fn alloc_lifetime_ref(770        &mut self,771        lifetime_ref: LifetimeRef,772        node: LifetimePtr,773    ) -> LifetimeRefId {774        let id = self.store.lifetimes.alloc(lifetime_ref);775        let ptr = self.expander.in_file(node);776        self.store.lifetime_map_back.insert(id, ptr);777        self.store.lifetime_map.insert(ptr, id);778        id779    }780781    fn alloc_type_ref_desugared(&mut self, type_ref: TypeRef) -> TypeRefId {782        self.store.types.alloc(type_ref)783    }784785    fn alloc_lifetime_ref_desugared(&mut self, lifetime_ref: LifetimeRef) -> LifetimeRefId {786        self.store.lifetimes.alloc(lifetime_ref)787    }788789    fn alloc_error_type(&mut self) -> TypeRefId {790        self.store.types.alloc(TypeRef::Error)791    }792793    pub fn lower_path(794        &mut self,795        ast: ast::Path,796        impl_trait_lower_fn: ImplTraitLowerFn<'_>,797    ) -> Option<Path> {798        super::lower::path::lower_path(self, ast, impl_trait_lower_fn)799    }800801    fn with_outer_impl_trait_scope<R>(802        &mut self,803        impl_trait: bool,804        f: impl FnOnce(&mut Self) -> R,805    ) -> R {806        let old = mem::replace(&mut self.outer_impl_trait, impl_trait);807        let result = f(self);808        self.outer_impl_trait = old;809        result810    }811812    pub fn impl_trait_error_allocator(813        ec: &mut ExprCollector<'_>,814        ptr: TypePtr,815        _: ThinVec<TypeBound>,816    ) -> TypeRefId {817        ec.alloc_type_ref(TypeRef::Error, ptr)818    }819820    fn impl_trait_allocator(821        ec: &mut ExprCollector<'_>,822        ptr: TypePtr,823        bounds: ThinVec<TypeBound>,824    ) -> TypeRefId {825        ec.alloc_type_ref(TypeRef::ImplTrait(bounds), ptr)826    }827828    fn alloc_path(&mut self, path: Path, node: TypePtr) -> PathId {829        PathId::from_type_ref_unchecked(self.alloc_type_ref(TypeRef::Path(path), node))830    }831832    /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)833    /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).834    pub(in crate::expr_store) fn lower_generic_args_from_fn_path(835        &mut self,836        args: Option<ast::ParenthesizedArgList>,837        ret_type: Option<ast::RetType>,838        impl_trait_lower_fn: ImplTraitLowerFn<'_>,839    ) -> Option<GenericArgs> {840        let params = args?;841        let mut param_types = Vec::new();842        for param in params.type_args() {843            let type_ref = self.lower_type_ref_opt(param.ty(), impl_trait_lower_fn);844            param_types.push(type_ref);845        }846        let args = Box::new([GenericArg::Type(847            self.alloc_type_ref_desugared(TypeRef::Tuple(ThinVec::from_iter(param_types))),848        )]);849        let bindings = if let Some(ret_type) = ret_type {850            let type_ref = self.lower_type_ref_opt(ret_type.ty(), impl_trait_lower_fn);851            Box::new([AssociatedTypeBinding {852                name: Name::new_symbol_root(sym::Output),853                args: None,854                type_ref: Some(type_ref),855                bounds: Box::default(),856            }])857        } else {858            // -> ()859            let type_ref = self.alloc_type_ref_desugared(TypeRef::unit());860            Box::new([AssociatedTypeBinding {861                name: Name::new_symbol_root(sym::Output),862                args: None,863                type_ref: Some(type_ref),864                bounds: Box::default(),865            }])866        };867        Some(GenericArgs {868            args,869            has_self_type: false,870            bindings,871            parenthesized: GenericArgsParentheses::ParenSugar,872        })873    }874875    pub(super) fn lower_generic_args(876        &mut self,877        node: ast::GenericArgList,878        impl_trait_lower_fn: ImplTraitLowerFn<'_>,879    ) -> Option<GenericArgs> {880        // This needs to be kept in sync with `hir_generic_arg_to_ast()`.881        let mut args = Vec::new();882        let mut bindings = Vec::new();883        for generic_arg in node.generic_args() {884            match generic_arg {885                ast::GenericArg::TypeArg(type_arg) => {886                    let type_ref = self.lower_type_ref_opt(type_arg.ty(), impl_trait_lower_fn);887                    args.push(GenericArg::Type(type_ref));888                }889                ast::GenericArg::AssocTypeArg(assoc_type_arg) => {890                    // This needs to be kept in sync with `hir_assoc_type_binding_to_ast()`.891                    if assoc_type_arg.param_list().is_some() {892                        // We currently ignore associated return type bounds.893                        continue;894                    }895                    if let Some(name_ref) = assoc_type_arg.name_ref() {896                        // Nested impl traits like `impl Foo<Assoc = impl Bar>` are allowed897                        self.with_outer_impl_trait_scope(false, |this| {898                            let name = name_ref.as_name();899                            let args = assoc_type_arg900                                .generic_arg_list()901                                .and_then(|args| this.lower_generic_args(args, impl_trait_lower_fn))902                                .or_else(|| {903                                    assoc_type_arg904                                        .return_type_syntax()905                                        .map(|_| GenericArgs::return_type_notation())906                                });907                            let type_ref = assoc_type_arg908                                .ty()909                                .map(|it| this.lower_type_ref(it, impl_trait_lower_fn));910                            let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {911                                l.bounds()912                                    .map(|it| this.lower_type_bound(it, impl_trait_lower_fn))913                                    .collect()914                            } else {915                                Box::default()916                            };917                            bindings.push(AssociatedTypeBinding { name, args, type_ref, bounds });918                        });919                    }920                }921                ast::GenericArg::LifetimeArg(lifetime_arg) => {922                    if let Some(lifetime) = lifetime_arg.lifetime() {923                        let lifetime_ref = self.lower_lifetime_ref(lifetime);924                        args.push(GenericArg::Lifetime(lifetime_ref))925                    }926                }927                ast::GenericArg::ConstArg(arg) => {928                    let arg = self.lower_const_arg(arg);929                    if let Some(const_expr_origins) = &mut self.store.inference_roots {930                        const_expr_origins.push((arg.expr, RootExprOrigin::GenericArgsPath));931                    }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_async_block_with_moved_arguments(953        &mut self,954        params: &mut [PatId],955        body: ExprId,956        coroutine_source: CoroutineSource,957    ) -> ExprId {958        let mut statements = Vec::new();959        for param in params {960            let (name, hygiene) = match self.store.pats[*param] {961                Pat::Bind { id, .. }962                    if matches!(963                        self.store.bindings[id].mode,964                        BindingAnnotation::Unannotated | BindingAnnotation::Mutable965                    ) =>966                {967                    // If this is a direct binding, we can leave it as-is, as it'll always be captured anyway.968                    continue;969                }970                Pat::Bind { id, .. } => {971                    // If this is a `ref` binding, we can't leave it as is but we can at least reuse the name, for better display.972                    (self.store.bindings[id].name.clone(), self.store.bindings[id].hygiene)973                }974                _ => (self.generate_new_name(), HygieneId::ROOT),975            };976            let binding_id = self.alloc_binding(name.clone(), BindingAnnotation::Mutable, hygiene);977            let pat_id = self.alloc_pat_desugared(Pat::Bind { id: binding_id, subpat: None });978            let expr = self.alloc_expr_desugared(Expr::Path(name.into()));979            if !hygiene.is_root() {980                self.store.ident_hygiene.insert(expr.into(), hygiene);981            }982            statements.push(Statement::Let {983                pat: *param,984                type_ref: None,985                initializer: Some(expr),986                else_branch: None,987            });988            *param = pat_id;989        }990991        let async_ = self.async_block(992            coroutine_source,993            // The default capture mode here is by-ref. Later on during upvar analysis,994            // we will force the captured arguments to by-move, but for async closures,995            // we want to make sure that we avoid unnecessarily moving captures, or else996            // all async closures would default to `FnOnce` as their calling mode.997            CaptureBy::Ref,998            None,999            statements.into_boxed_slice(),1000            Some(body),1001        );1002        // It's important that this comes last, see the lowering of async closures for why.1003        self.alloc_expr_desugared(async_)1004    }10051006    fn async_block(1007        &mut self,1008        source: CoroutineSource,1009        capture_by: CaptureBy,1010        id: Option<BlockId>,1011        statements: Box<[Statement]>,1012        tail: Option<ExprId>,1013    ) -> Expr {1014        let block = self.alloc_expr_desugared(Expr::Block { label: None, id, statements, tail });1015        Expr::Closure {1016            args: Box::default(),1017            arg_types: Box::default(),1018            ret_type: None,1019            body: block,1020            closure_kind: ClosureKind::AsyncBlock { source },1021            capture_by,1022        }1023    }10241025    fn collect(1026        &mut self,1027        params: &mut [PatId],1028        expr: Option<ast::Expr>,1029        awaitable: Awaitable,1030    ) -> ExprId {1031        self.awaitable_context.replace(awaitable);1032        self.with_label_rib(RibKind::Closure, |this| {1033            let body = this.collect_expr_opt(expr);1034            if awaitable == Awaitable::Yes {1035                this.lower_async_block_with_moved_arguments(params, body, CoroutineSource::Fn)1036            } else {1037                body1038            }1039        })1040    }10411042    fn type_bounds_from_ast(1043        &mut self,1044        type_bounds_opt: Option<ast::TypeBoundList>,1045        impl_trait_lower_fn: ImplTraitLowerFn<'_>,1046    ) -> ThinVec<TypeBound> {1047        if let Some(type_bounds) = type_bounds_opt {1048            ThinVec::from_iter(Vec::from_iter(1049                type_bounds.bounds().map(|it| self.lower_type_bound(it, impl_trait_lower_fn)),1050            ))1051        } else {1052            ThinVec::from_iter([])1053        }1054    }10551056    fn lower_path_type(1057        &mut self,1058        path_type: &ast::PathType,1059        impl_trait_lower_fn: ImplTraitLowerFn<'_>,1060    ) -> Option<Path> {1061        let path = self.lower_path(path_type.path()?, impl_trait_lower_fn)?;1062        Some(path)1063    }10641065    fn lower_type_bound(1066        &mut self,1067        node: ast::TypeBound,1068        impl_trait_lower_fn: ImplTraitLowerFn<'_>,1069    ) -> TypeBound {1070        let Some(kind) = node.kind() else { return TypeBound::Error };1071        match kind {1072            ast::TypeBoundKind::PathType(binder, path_type) => {1073                let binder = match binder.and_then(|it| it.generic_param_list()) {1074                    Some(gpl) => gpl1075                        .lifetime_params()1076                        .flat_map(|lp| lp.lifetime().map(|lt| Name::new_lifetime(&lt.text())))1077                        .collect(),1078                    None => ThinVec::default(),1079                };1080                let m = match node.question_mark_token() {1081                    Some(_) => TraitBoundModifier::Maybe,1082                    None => TraitBoundModifier::None,1083                };1084                self.lower_path_type(&path_type, impl_trait_lower_fn)1085                    .map(|p| {1086                        let path = self.alloc_path(p, AstPtr::new(&path_type).upcast());1087                        if binder.is_empty() {1088                            TypeBound::Path(path, m)1089                        } else {1090                            TypeBound::ForLifetime(binder, path)1091                        }1092                    })1093                    .unwrap_or(TypeBound::Error)1094            }1095            ast::TypeBoundKind::Use(gal) => TypeBound::Use(1096                gal.use_bound_generic_args()1097                    .map(|p| match p {1098                        ast::UseBoundGenericArg::Lifetime(l) => {1099                            UseArgRef::Lifetime(self.lower_lifetime_ref(l))1100                        }1101                        ast::UseBoundGenericArg::NameRef(n) => UseArgRef::Name(n.as_name()),1102                    })1103                    .collect(),1104            ),1105            ast::TypeBoundKind::Lifetime(lifetime) => {1106                TypeBound::Lifetime(self.lower_lifetime_ref(lifetime))1107            }1108        }1109    }11101111    fn lower_const_arg_opt(&mut self, arg: Option<ast::ConstArg>) -> ConstRef {1112        let const_expr_origins = self.store.inference_roots.take();1113        let r = ConstRef { expr: self.collect_expr_opt(arg.and_then(|it| it.expr())) };1114        self.store.inference_roots = const_expr_origins;1115        r1116    }11171118    pub fn lower_const_arg(&mut self, arg: ast::ConstArg) -> ConstRef {1119        let const_expr_origins = self.store.inference_roots.take();1120        let r = ConstRef { expr: self.collect_expr_opt(arg.expr()) };1121        self.store.inference_roots = const_expr_origins;1122        r1123    }11241125    fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {1126        self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr())1127    }11281129    pub(in crate::expr_store) fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {1130        match expr {1131            Some(expr) => self.collect_expr(expr),1132            None => self.missing_expr(),1133        }1134    }11351136    /// Returns `None` if and only if the expression is `#[cfg]`d out.1137    fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {1138        let syntax_ptr = AstPtr::new(&expr);1139        if !self.check_cfg(&expr) {1140            return None;1141        }11421143        // FIXME: Move some of these arms out into separate methods for clarity1144        Some(match expr {1145            ast::Expr::IfExpr(e) => {1146                let then_branch = self.collect_block_opt(e.then_branch());11471148                let else_branch = e.else_branch().map(|b| match b {1149                    ast::ElseBranch::Block(it) => self.collect_block(it),1150                    ast::ElseBranch::IfExpr(elif) => {1151                        let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();1152                        self.collect_expr(expr)1153                    }1154                });11551156                let condition = self.collect_expr_opt(e.condition());11571158                self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)1159            }1160            ast::Expr::LetExpr(e) => {1161                let pat = self.collect_pat_top(e.pat());1162                let expr = self.collect_expr_opt(e.expr());1163                self.alloc_expr(Expr::Let { pat, expr }, syntax_ptr)1164            }1165            ast::Expr::BlockExpr(e) => match e.modifier() {1166                Some(ast::BlockModifier::Try { try_token: _, bikeshed_token: _, result_type }) => {1167                    self.desugar_try_block(e, result_type)1168                }1169                Some(ast::BlockModifier::Unsafe(_)) => {1170                    self.collect_block_(e, |_, id, statements, tail| Expr::Unsafe {1171                        id,1172                        statements,1173                        tail,1174                    })1175                }1176                Some(ast::BlockModifier::Label(label)) => {1177                    let label_hygiene = self.hygiene_id_for(label.syntax().text_range());1178                    let label_id = self.collect_label(label);1179                    self.with_labeled_rib(label_id, label_hygiene, |this| {1180                        this.collect_block_(e, |_, id, statements, tail| Expr::Block {1181                            id,1182                            statements,1183                            tail,1184                            label: Some(label_id),1185                        })1186                    })1187                }1188                Some(ast::BlockModifier::Async(_)) => {1189                    let capture_by =1190                        if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };1191                    self.with_label_rib(RibKind::Closure, |this| {1192                        this.with_awaitable_block(Awaitable::Yes, |this| {1193                            this.collect_block_(e, |this, id, statements, tail| {1194                                this.async_block(1195                                    CoroutineSource::Block,1196                                    capture_by,1197                                    id,1198                                    statements,1199                                    tail,1200                                )1201                            })1202                        })1203                    })1204                }1205                Some(ast::BlockModifier::Const(_)) => {1206                    self.with_label_rib(RibKind::Constant, |this| {1207                        this.with_awaitable_block(Awaitable::No("constant block"), |this| {1208                            this.with_binding_owner(|this| {1209                                let inner_expr = this.collect_block(e);1210                                this.alloc_expr(Expr::Const(inner_expr), syntax_ptr)1211                            })1212                        })1213                    })1214                }1215                // FIXME1216                Some(ast::BlockModifier::AsyncGen(_)) => {1217                    self.with_awaitable_block(Awaitable::Yes, |this| this.collect_block(e))1218                }1219                Some(ast::BlockModifier::Gen(_)) => self1220                    .with_awaitable_block(Awaitable::No("non-async gen block"), |this| {1221                        this.collect_block(e)1222                    }),1223                None => self.collect_block(e),1224            },1225            ast::Expr::LoopExpr(e) => {1226                let label = e.label().map(|label| {1227                    (self.hygiene_id_for(label.syntax().text_range()), self.collect_label(label))1228                });1229                let body = self.collect_labelled_block_opt(label, e.loop_body());1230                self.alloc_expr(Expr::Loop { body, label: label.map(|it| it.1) }, syntax_ptr)1231            }1232            ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e),1233            ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e),1234            ast::Expr::CallExpr(e) => {1235                // FIXME(MINIMUM_SUPPORTED_TOOLCHAIN_VERSION): Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c1236                let is_rustc_box = {1237                    let attrs = e.attrs();1238                    attrs.filter_map(|it| it.as_simple_atom()).any(|it| it == "rustc_box")1239                };1240                if is_rustc_box {1241                    let expr = self.collect_expr_opt(e.arg_list().and_then(|it| it.args().next()));1242                    self.alloc_expr(Expr::Box { expr }, syntax_ptr)1243                } else {1244                    let callee = self.collect_expr_opt(e.expr());1245                    let args = if let Some(arg_list) = e.arg_list() {1246                        arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()1247                    } else {1248                        Box::default()1249                    };1250                    self.alloc_expr(Expr::Call { callee, args }, syntax_ptr)1251                }1252            }1253            ast::Expr::MethodCallExpr(e) => {1254                let receiver = self.collect_expr_opt(e.receiver());1255                let args = if let Some(arg_list) = e.arg_list() {1256                    arg_list.args().filter_map(|e| self.maybe_collect_expr(e)).collect()1257                } else {1258                    Box::default()1259                };1260                let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);1261                let generic_args = e1262                    .generic_arg_list()1263                    .and_then(|it| {1264                        self.lower_generic_args(it, &mut Self::impl_trait_error_allocator)1265                    })1266                    .map(Box::new);1267                self.alloc_expr(1268                    Expr::MethodCall { receiver, method_name, args, generic_args },1269                    syntax_ptr,1270                )1271            }1272            ast::Expr::MatchExpr(e) => {1273                let expr = self.collect_expr_opt(e.expr());1274                let arms = if let Some(match_arm_list) = e.match_arm_list() {1275                    match_arm_list1276                        .arms()1277                        .filter_map(|arm| {1278                            if self.check_cfg(&arm) {1279                                Some(MatchArm {1280                                    pat: self.collect_pat_top(arm.pat()),1281                                    expr: self.collect_expr_opt(arm.expr()),1282                                    guard: arm1283                                        .guard()1284                                        .map(|guard| self.collect_expr_opt(guard.condition())),1285                                })1286                            } else {1287                                None1288                            }1289                        })1290                        .collect()1291                } else {1292                    Box::default()1293                };1294                self.alloc_expr(Expr::Match { expr, arms }, syntax_ptr)1295            }1296            ast::Expr::PathExpr(e) => {1297                let (path, hygiene) = self1298                    .collect_expr_path(e)1299                    .map(|(path, hygiene)| (Expr::Path(path), hygiene))1300                    .unwrap_or((Expr::Missing, HygieneId::ROOT));1301                let expr_id = self.alloc_expr(path, syntax_ptr);1302                if !hygiene.is_root() {1303                    self.store.ident_hygiene.insert(expr_id.into(), hygiene);1304                }1305                expr_id1306            }1307            ast::Expr::ContinueExpr(e) => {1308                let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {1309                    self.store.diagnostics.push(e);1310                    None1311                });1312                self.alloc_expr(Expr::Continue { label }, syntax_ptr)1313            }1314            ast::Expr::BreakExpr(e) => {1315                let label = self.resolve_label(e.lifetime()).unwrap_or_else(|e| {1316                    self.store.diagnostics.push(e);1317                    None1318                });1319                let expr = e.expr().map(|e| self.collect_expr(e));1320                self.alloc_expr(Expr::Break { expr, label }, syntax_ptr)1321            }1322            ast::Expr::ParenExpr(e) => {1323                let inner = self.collect_expr_opt(e.expr());1324                // make the paren expr point to the inner expression as well for IDE resolution1325                let src = self.expander.in_file(syntax_ptr);1326                self.store.expr_map.insert(src, inner.into());1327                inner1328            }1329            ast::Expr::ReturnExpr(e) => {1330                let expr = e.expr().map(|e| self.collect_expr(e));1331                self.alloc_expr(Expr::Return { expr }, syntax_ptr)1332            }1333            ast::Expr::BecomeExpr(e) => {1334                let expr =1335                    e.expr().map(|e| self.collect_expr(e)).unwrap_or_else(|| self.missing_expr());1336                self.alloc_expr(Expr::Become { expr }, syntax_ptr)1337            }1338            ast::Expr::YieldExpr(e) => {1339                self.is_lowering_coroutine = true;1340                let expr = e.expr().map(|e| self.collect_expr(e));1341                self.alloc_expr(Expr::Yield { expr }, syntax_ptr)1342            }1343            ast::Expr::YeetExpr(e) => {1344                let expr = e.expr().map(|e| self.collect_expr(e));1345                self.alloc_expr(Expr::Yeet { expr }, syntax_ptr)1346            }1347            ast::Expr::RecordExpr(e) => {1348                let path = e1349                    .path()1350                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator))1351                    .map(Box::new);1352                let record_lit = if let Some(nfl) = e.record_expr_field_list() {1353                    let fields = nfl1354                        .fields()1355                        .filter_map(|field| {1356                            if !self.check_cfg(&field) {1357                                return None;1358                            }13591360                            let name = field.field_name()?.as_name();13611362                            let expr = match field.expr() {1363                                Some(e) => self.collect_expr(e),1364                                None => self.missing_expr(),1365                            };1366                            let src = self.expander.in_file(AstPtr::new(&field));1367                            self.store.field_map_back.insert(expr, src);1368                            Some(RecordLitField { name, expr })1369                        })1370                        .collect();1371                    let spread_expr = nfl.spread().map(|s| self.collect_expr(s));1372                    let has_spread_syntax = nfl.dotdot_token().is_some();1373                    let spread = match (spread_expr, has_spread_syntax) {1374                        (None, false) => RecordSpread::None,1375                        (None, true) => RecordSpread::FieldDefaults,1376                        (Some(expr), _) => RecordSpread::Expr(expr),1377                    };1378                    Expr::RecordLit { path, fields, spread }1379                } else {1380                    Expr::RecordLit { path, fields: Box::default(), spread: RecordSpread::None }1381                };13821383                self.alloc_expr(record_lit, syntax_ptr)1384            }1385            ast::Expr::FieldExpr(e) => {1386                let expr = self.collect_expr_opt(e.expr());1387                let name = match e.field_access() {1388                    Some(kind) => kind.as_name(),1389                    _ => Name::missing(),1390                };1391                self.alloc_expr(Expr::Field { expr, name }, syntax_ptr)1392            }1393            ast::Expr::AwaitExpr(e) => {1394                let expr = self.collect_expr_opt(e.expr());1395                if let Awaitable::No(location) = self.is_lowering_awaitable_block() {1396                    self.store.diagnostics.push(ExpressionStoreDiagnostics::AwaitOutsideOfAsync {1397                        node: self.expander.in_file(AstPtr::new(&e)),1398                        location: location.to_string(),1399                    });1400                }1401                self.alloc_expr(Expr::Await { expr }, syntax_ptr)1402            }1403            ast::Expr::TryExpr(e) => self.collect_try_operator(syntax_ptr, e),1404            ast::Expr::CastExpr(e) => {1405                let expr = self.collect_expr_opt(e.expr());1406                let type_ref = self.lower_type_ref_opt_disallow_impl_trait(e.ty());1407                self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)1408            }1409            ast::Expr::RefExpr(e) => {1410                let expr = self.collect_expr_opt(e.expr());1411                let raw_tok = e.raw_token().is_some();1412                let mutability = if raw_tok {1413                    if e.mut_token().is_some() { Mutability::Mut } else { Mutability::Shared }1414                } else {1415                    Mutability::from_mutable(e.mut_token().is_some())1416                };1417                let rawness = Rawness::from_raw(raw_tok);1418                self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr)1419            }1420            ast::Expr::PrefixExpr(e) => {1421                let expr = self.collect_expr_opt(e.expr());1422                match e.op_kind() {1423                    Some(op) => self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr),1424                    None => self.alloc_expr(Expr::Missing, syntax_ptr),1425                }1426            }1427            ast::Expr::ClosureExpr(e) => self.with_label_rib(RibKind::Closure, |this| {1428                this.with_binding_owner_and_return(|this| {1429                    let mut args = Vec::new();1430                    let mut arg_types = Vec::new();1431                    // For coroutine closures, the body, aka. the coroutine is the bindings owner, and not the closure.1432                    let mut body_is_bindings_owner = false;1433                    if let Some(pl) = e.param_list() {1434                        let num_params = pl.params().count();1435                        args.reserve_exact(num_params);1436                        arg_types.reserve_exact(num_params);1437                        for param in pl.params() {1438                            let pat = this.collect_pat_top(param.pat());1439                            let type_ref =1440                                param.ty().map(|it| this.lower_type_ref_disallow_impl_trait(it));1441                            args.push(pat);1442                            arg_types.push(type_ref);1443                        }1444                    }1445                    let ret_type = e1446                        .ret_type()1447                        .and_then(|r| r.ty())1448                        .map(|it| this.lower_type_ref_disallow_impl_trait(it));14491450                    let prev_is_lowering_coroutine = mem::take(&mut this.is_lowering_coroutine);1451                    let prev_try_block = this.current_try_block.take();14521453                    let awaitable = if e.async_token().is_some() {1454                        Awaitable::Yes1455                    } else {1456                        Awaitable::No("non-async closure")1457                    };1458                    let mut body = this1459                        .with_awaitable_block(awaitable, |this| this.collect_expr_opt(e.body()));14601461                    let closure_kind = if this.is_lowering_coroutine {1462                        let movability = if e.static_token().is_some() {1463                            Movability::Static1464                        } else {1465                            Movability::Movable1466                        };1467                        ClosureKind::Coroutine(movability)1468                    } else if e.async_token().is_some() {1469                        // It's important that this expr is allocated immediately before the closure.1470                        // We rely on it for `coroutine_for_closure()`.1471                        body = this.lower_async_block_with_moved_arguments(1472                            &mut args,1473                            body,1474                            CoroutineSource::Closure,1475                        );1476                        body_is_bindings_owner = true;14771478                        ClosureKind::AsyncClosure1479                    } else {1480                        ClosureKind::Closure1481                    };1482                    let capture_by =1483                        if e.move_token().is_some() { CaptureBy::Value } else { CaptureBy::Ref };1484                    this.is_lowering_coroutine = prev_is_lowering_coroutine;1485                    this.current_try_block = prev_try_block;1486                    let closure = this.alloc_expr(1487                        Expr::Closure {1488                            args: args.into(),1489                            arg_types: arg_types.into(),1490                            ret_type,1491                            body,1492                            closure_kind,1493                            capture_by,1494                        },1495                        syntax_ptr,1496                    );14971498                    (if body_is_bindings_owner { body } else { closure }, closure)1499                })1500            }),1501            ast::Expr::BinExpr(e) => {1502                let op = e.op_kind();1503                if let Some(ast::BinaryOp::Assignment { op: None }) = op {1504                    let target = self.collect_expr_as_pat_opt(e.lhs());1505                    let value = self.collect_expr_opt(e.rhs());1506                    self.alloc_expr(Expr::Assignment { target, value }, syntax_ptr)1507                } else {1508                    let lhs = self.collect_expr_opt(e.lhs());1509                    let rhs = self.collect_expr_opt(e.rhs());1510                    self.alloc_expr(Expr::BinaryOp { lhs, rhs, op }, syntax_ptr)1511                }1512            }1513            ast::Expr::TupleExpr(e) => {1514                let mut exprs: Vec<_> = e.fields().map(|expr| self.collect_expr(expr)).collect();1515                // if there is a leading comma, the user is most likely to type out a leading expression1516                // so we insert a missing expression at the beginning for IDE features1517                if comma_follows_token(e.l_paren_token()) {1518                    exprs.insert(0, self.missing_expr());1519                }15201521                self.alloc_expr(Expr::Tuple { exprs: exprs.into_boxed_slice() }, syntax_ptr)1522            }1523            ast::Expr::ArrayExpr(e) => {1524                let kind = e.kind();15251526                match kind {1527                    ArrayExprKind::ElementList(e) => {1528                        let elements = e1529                            .filter_map(|expr| {1530                                if self.check_cfg(&expr) {1531                                    Some(self.collect_expr(expr))1532                                } else {1533                                    None1534                                }1535                            })1536                            .collect();1537                        self.alloc_expr(Expr::Array(Array::ElementList { elements }), syntax_ptr)1538                    }1539                    ArrayExprKind::Repeat { initializer, repeat } => {1540                        let initializer = self.collect_expr_opt(initializer);1541                        let repeat = self.with_label_rib(RibKind::Constant, |this| {1542                            if let Some(repeat) = repeat {1543                                this.with_binding_owner(|this| this.collect_expr(repeat))1544                            } else {1545                                this.missing_expr()1546                            }1547                        });1548                        self.alloc_expr(1549                            Expr::Array(Array::Repeat { initializer, repeat }),1550                            syntax_ptr,1551                        )1552                    }1553                }1554            }15551556            ast::Expr::Literal(e) => self.alloc_expr(Expr::Literal(e.kind().into()), syntax_ptr),1557            ast::Expr::IndexExpr(e) => {1558                let base = self.collect_expr_opt(e.base());1559                let index = self.collect_expr_opt(e.index());1560                self.alloc_expr(Expr::Index { base, index }, syntax_ptr)1561            }1562            ast::Expr::RangeExpr(e) => {1563                let lhs = e.start().map(|lhs| self.collect_expr(lhs));1564                let rhs = e.end().map(|rhs| self.collect_expr(rhs));1565                match e.op_kind() {1566                    Some(range_type) => {1567                        self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)1568                    }1569                    None => self.alloc_expr(Expr::Missing, syntax_ptr),1570                }1571            }1572            ast::Expr::MacroExpr(e) => {1573                let e = e.macro_call()?;1574                let macro_ptr = AstPtr::new(&e);1575                let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {1576                    expansion.map(|it| this.collect_expr(it))1577                });1578                match id {1579                    Some(id) => {1580                        // Make the macro-call point to its expanded expression so we can query1581                        // semantics on syntax pointers to the macro1582                        let src = self.expander.in_file(syntax_ptr);1583                        self.store.expr_map.insert(src, id.into());1584                        id1585                    }1586                    None => self.alloc_expr(Expr::Missing, syntax_ptr),1587                }1588            }1589            ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),1590            ast::Expr::AsmExpr(e) => self.lower_inline_asm(e, syntax_ptr),1591            ast::Expr::OffsetOfExpr(e) => {1592                let container = self.lower_type_ref_opt_disallow_impl_trait(e.ty());1593                let fields = e.fields().map(|it| it.as_name()).collect();1594                self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)1595            }1596            ast::Expr::FormatArgsExpr(f) => self.collect_format_args(f, syntax_ptr),1597        })1598    }15991600    fn collect_expr_path(&mut self, e: ast::PathExpr) -> Option<(Path, HygieneId)> {1601        e.path().and_then(|path| {1602            let path = self.lower_path(path, &mut Self::impl_trait_error_allocator)?;1603            // Need to enable `mod_path.len() < 1` for `self`.1604            let may_be_variable = matches!(&path, Path::BarePath(mod_path) if mod_path.len() <= 1);1605            let hygiene = if may_be_variable {1606                self.hygiene_id_for(e.syntax().text_range())1607            } else {1608                HygieneId::ROOT1609            };1610            Some((path, hygiene))1611        })1612    }16131614    fn collect_expr_as_pat_opt(&mut self, expr: Option<ast::Expr>) -> PatId {1615        match expr {1616            Some(expr) => self.collect_expr_as_pat(expr),1617            _ => self.missing_pat(),1618        }1619    }16201621    fn collect_expr_as_pat(&mut self, expr: ast::Expr) -> PatId {1622        self.maybe_collect_expr_as_pat(&expr).unwrap_or_else(|| {1623            let src = self.expander.in_file(AstPtr::new(&expr).wrap_left());1624            let expr = self.collect_expr(expr);1625            // Do not use `alloc_pat_from_expr()` here, it will override the entry in `expr_map`.1626            let id = self.store.pats.alloc(Pat::Expr(expr));1627            self.store.pat_map_back.insert(id, src);1628            id1629        })1630    }16311632    fn maybe_collect_expr_as_pat(&mut self, expr: &ast::Expr) -> Option<PatId> {1633        if !self.check_cfg(expr) {1634            return None;1635        }1636        let syntax_ptr = AstPtr::new(expr);16371638        let result = match expr {1639            ast::Expr::UnderscoreExpr(_) => self.alloc_pat_from_expr(Pat::Wild, syntax_ptr),1640            ast::Expr::ParenExpr(e) => {1641                // We special-case `(..)` for consistency with patterns.1642                if let Some(ast::Expr::RangeExpr(range)) = e.expr()1643                    && range.is_range_full()1644                {1645                    return Some(self.alloc_pat_from_expr(1646                        Pat::Tuple { args: Box::default(), ellipsis: Some(0) },1647                        syntax_ptr,1648                    ));1649                }1650                return e.expr().and_then(|expr| self.maybe_collect_expr_as_pat(&expr));1651            }1652            ast::Expr::TupleExpr(e) => {1653                let (ellipsis, args) = collect_tuple(self, e.fields());1654                self.alloc_pat_from_expr(Pat::Tuple { args, ellipsis }, syntax_ptr)1655            }1656            ast::Expr::ArrayExpr(e) => {1657                if e.semicolon_token().is_some() {1658                    return None;1659                }16601661                let mut elements = e.exprs();1662                let prefix = elements1663                    .by_ref()1664                    .map_while(|elem| collect_possibly_rest(self, elem).left())1665                    .collect();1666                let suffix = elements.map(|elem| self.collect_expr_as_pat(elem)).collect();1667                self.alloc_pat_from_expr(Pat::Slice { prefix, slice: None, suffix }, syntax_ptr)1668            }1669            ast::Expr::CallExpr(e) => {1670                let path = collect_path(self, e.expr()?)?;1671                let path = path1672                    .path()1673                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator))1674                    .map(Box::new);1675                let (ellipsis, args) = collect_tuple(self, e.arg_list()?.args());1676                self.alloc_pat_from_expr(Pat::TupleStruct { path, args, ellipsis }, syntax_ptr)1677            }1678            ast::Expr::PathExpr(e) => {1679                let (path, hygiene) = self1680                    .collect_expr_path(e.clone())1681                    .map(|(path, hygiene)| (Pat::Path(path), hygiene))1682                    .unwrap_or((Pat::Missing, HygieneId::ROOT));1683                let pat_id = self.alloc_pat_from_expr(path, syntax_ptr);1684                if !hygiene.is_root() {1685                    self.store.ident_hygiene.insert(pat_id.into(), hygiene);1686                }1687                pat_id1688            }1689            ast::Expr::MacroExpr(e) => {1690                let e = e.macro_call()?;1691                let macro_ptr = AstPtr::new(&e);1692                let src = self.expander.in_file(AstPtr::new(expr));1693                let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {1694                    this.collect_expr_as_pat_opt(expansion)1695                });1696                self.store.expr_map.insert(src, id.into());1697                id1698            }1699            ast::Expr::RecordExpr(e) => {1700                let path = e1701                    .path()1702                    .and_then(|path| self.lower_path(path, &mut Self::impl_trait_error_allocator))1703                    .map(Box::new);1704                let record_field_list = e.record_expr_field_list()?;1705                let ellipsis = record_field_list.dotdot_token().is_some();1706                // FIXME: Report an error here if `record_field_list.spread().is_some()`.1707                let args = record_field_list1708                    .fields()1709                    .filter_map(|f| {1710                        if !self.check_cfg(&f) {1711                            return None;1712                        }1713                        let field_expr = f.expr()?;1714                        let pat = self.collect_expr_as_pat(field_expr);1715                        let name = f.field_name()?.as_name();1716                        let src = self.expander.in_file(AstPtr::new(&f).wrap_left());1717                        self.store.pat_field_map_back.insert(pat, src);1718                        Some(RecordFieldPat { name, pat })1719                    })1720                    .collect();1721                self.alloc_pat_from_expr(Pat::Record { path, args, ellipsis }, syntax_ptr)1722            }1723            _ => return None,1724        };1725        return Some(result);17261727        fn collect_path(this: &mut ExprCollector<'_>, expr: ast::Expr) -> Option<ast::PathExpr> {1728            match expr {1729                ast::Expr::PathExpr(e) => Some(e),1730                ast::Expr::MacroExpr(mac) => {1731                    let call = mac.macro_call()?;1732                    {1733                        let macro_ptr = AstPtr::new(&call);1734                        this.collect_macro_call(call, macro_ptr, true, |this, expanded_path| {1735                            collect_path(this, expanded_path?)1736                        })1737                    }1738                }1739                _ => None,1740            }1741        }17421743        fn collect_possibly_rest(1744            this: &mut ExprCollector<'_>,1745            expr: ast::Expr,1746        ) -> Either<PatId, ()> {1747            match &expr {1748                ast::Expr::RangeExpr(e) if e.is_range_full() => Either::Right(()),1749                ast::Expr::MacroExpr(mac) => match mac.macro_call() {1750                    Some(call) => {1751                        let macro_ptr = AstPtr::new(&call);1752                        let pat = this.collect_macro_call(1753                            call,1754                            macro_ptr,1755                            true,1756                            |this, expanded_expr| match expanded_expr {1757                                Some(expanded_pat) => collect_possibly_rest(this, expanded_pat),1758                                None => Either::Left(this.missing_pat()),1759                            },1760                        );1761                        if let Either::Left(pat) = pat {1762                            let src = this.expander.in_file(AstPtr::new(&expr).wrap_left());1763                            this.store.pat_map_back.insert(pat, src);1764                        }1765                        pat1766                    }1767                    None => {1768                        let ptr = AstPtr::new(&expr);1769                        Either::Left(this.alloc_pat_from_expr(Pat::Missing, ptr))1770                    }1771                },1772                _ => Either::Left(this.collect_expr_as_pat(expr)),1773            }1774        }17751776        fn collect_tuple(1777            this: &mut ExprCollector<'_>,1778            fields: ast::AstChildren<ast::Expr>,1779        ) -> (Option<u32>, Box<[la_arena::Idx<Pat>]>) {1780            let mut ellipsis = None;1781            let args = fields1782                .enumerate()1783                .filter_map(|(idx, elem)| {1784                    match collect_possibly_rest(this, elem) {1785                        Either::Left(pat) => Some(pat),1786                        Either::Right(()) => {1787                            if ellipsis.is_none() {1788                                ellipsis = Some(idx as u32);1789                            }1790                            // FIXME: Report an error here otherwise.1791                            None1792                        }1793                    }1794                })1795                .collect();1796            (ellipsis, args)1797        }1798    }17991800    /// The callback should return two exprs: the first is the bindings owner, the second is the expr to return.1801    fn with_binding_owner_and_return(1802        &mut self,1803        create_expr: impl FnOnce(&mut Self) -> (ExprId, ExprId),1804    ) -> ExprId {1805        let prev_unowned_bindings_len = self.unowned_bindings.len();1806        let (bindings_owner, expr_to_return) = create_expr(self);1807        for binding in self.unowned_bindings.drain(prev_unowned_bindings_len..) {1808            self.store.binding_owners.insert(binding, bindings_owner);1809        }1810        expr_to_return1811    }18121813    fn with_binding_owner(&mut self, create_expr: impl FnOnce(&mut Self) -> ExprId) -> ExprId {1814        self.with_binding_owner_and_return(move |this| {1815            let expr = create_expr(this);1816            (expr, expr)1817        })1818    }18191820    /// Desugar `try { <stmts>; <expr> }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(<expr>) }`,1821    /// `try { <stmts>; }` into `'<new_label>: { <stmts>; ::std::ops::Try::from_output(()) }`1822    /// and save the `<new_label>` to use it as a break target for desugaring of the `?` operator.1823    fn desugar_try_block(&mut self, e: BlockExpr, result_type: Option<ast::Type>) -> ExprId {1824        let try_from_output = self.lang_path(self.lang_items().TryTraitFromOutput);1825        let label = self.generate_new_name();1826        let label = self.alloc_label_desugared(Label { name: label }, AstPtr::new(&e).wrap_right());1827        let try_block_info = match result_type {1828            Some(_) => TryBlock::Heterogeneous { label },1829            None => TryBlock::Homogeneous { label },1830        };1831        let old_try_block = self.current_try_block.replace(try_block_info);18321833        let ptr = AstPtr::new(&e).upcast();1834        let (btail, expr_id) = self.with_labeled_rib(label, HygieneId::ROOT, |this| {1835            let mut btail = None;1836            let block = this.collect_block_(e, |_, id, statements, tail| {1837                btail = tail;1838                Expr::Block { id, statements, tail, label: Some(label) }1839            });1840            (btail, block)1841        });18421843        let callee = self1844            .alloc_expr_desugared_with_ptr(try_from_output.map_or(Expr::Missing, Expr::Path), ptr);1845        let next_tail = match btail {1846            Some(tail) => self1847                .alloc_expr_desugared_with_ptr(Expr::Call { callee, args: Box::new([tail]) }, ptr),1848            None => {1849                let unit =1850                    self.alloc_expr_desugared_with_ptr(Expr::Tuple { exprs: Box::new([]) }, ptr);1851                self.alloc_expr_desugared_with_ptr(1852                    Expr::Call { callee, args: Box::new([unit]) },1853                    ptr,1854                )1855            }1856        };1857        let Expr::Block { tail, .. } = &mut self.store.exprs[expr_id] else {1858            unreachable!("block was lowered to non-block");1859        };1860        *tail = Some(next_tail);1861        self.current_try_block = old_try_block;1862        match result_type {1863            Some(ty) => {1864                // `{ let <name>: <ty> = <expr>; <name> }`1865                let name = self.generate_new_name();1866                let type_ref = self.lower_type_ref_disallow_impl_trait(ty);1867                let binding = self.alloc_binding(1868                    name.clone(),1869                    BindingAnnotation::Unannotated,1870                    HygieneId::ROOT,1871                );1872                let pat = self.alloc_pat_desugared(Pat::Bind { id: binding, subpat: None });1873                self.add_definition_to_binding(binding, pat);1874                let tail_expr =1875                    self.alloc_expr_desugared_with_ptr(Expr::Path(Path::from(name)), ptr);1876                self.alloc_expr_desugared_with_ptr(1877                    Expr::Block {1878                        id: None,1879                        statements: Box::new([Statement::Let {1880                            pat,1881                            type_ref: Some(type_ref),1882                            initializer: Some(expr_id),1883                            else_branch: None,1884                        }]),1885                        tail: Some(tail_expr),1886                        label: None,1887                    },1888                    ptr,1889                )1890            }1891            None => expr_id,1892        }1893    }18941895    /// Desugar `ast::WhileExpr` from: `[opt_ident]: while <cond> <body>` into:1896    /// ```ignore (pseudo-rust)1897    /// [opt_ident]: loop {1898    ///   if <cond> {1899    ///     <body>1900    ///   }1901    ///   else {1902    ///     break;1903    ///   }1904    /// }1905    /// ```1906    /// FIXME: Rustc wraps the condition in a construct equivalent to `{ let _t = <cond>; _t }`1907    /// to preserve drop semantics. We should probably do the same in future.1908    fn collect_while_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::WhileExpr) -> ExprId {1909        let label = e.label().map(|label| {1910            (self.hygiene_id_for(label.syntax().text_range()), self.collect_label(label))1911        });1912        let body = self.collect_labelled_block_opt(label, e.loop_body());19131914        // Labels can also be used in the condition expression, like this:1915        // ```1916        // fn main() {1917        //     let mut optional = Some(0);1918        //     'my_label: while let Some(a) = match optional {1919        //         None => break 'my_label,1920        //         Some(val) => Some(val),1921        //     } {1922        //         println!("{}", a);1923        //         optional = None;1924        //     }1925        // }1926        // ```1927        let condition = match label {1928            Some((label_hygiene, label)) => self.with_labeled_rib(label, label_hygiene, |this| {1929                this.collect_expr_opt(e.condition())1930            }),1931            None => self.collect_expr_opt(e.condition()),1932        };19331934        let break_expr = self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr);1935        let if_expr = self.alloc_expr(1936            Expr::If { condition, then_branch: body, else_branch: Some(break_expr) },1937            syntax_ptr,1938        );1939        self.alloc_expr(Expr::Loop { body: if_expr, label: label.map(|it| it.1) }, syntax_ptr)1940    }19411942    /// Desugar `ast::ForExpr` from: `[opt_ident]: for <pat> in <head> <body>` into:1943    /// ```ignore (pseudo-rust)1944    /// match IntoIterator::into_iter(<head>) {1945    ///     mut iter => {1946    ///         [opt_ident]: loop {1947    ///             match Iterator::next(&mut iter) {1948    ///                 None => break,1949    ///                 Some(<pat>) => <body>,1950    ///             };1951    ///         }1952    ///     }1953    /// }1954    /// ```1955    fn collect_for_loop(&mut self, syntax_ptr: AstPtr<ast::Expr>, e: ast::ForExpr) -> ExprId {1956        let lang_items = self.lang_items();1957        let into_iter_fn = self.lang_path(lang_items.IntoIterIntoIter);1958        let iter_next_fn = self.lang_path(lang_items.IteratorNext);1959        let option_some = self.lang_path(lang_items.OptionSome);1960        let option_none = self.lang_path(lang_items.OptionNone);1961        let head = self.collect_expr_opt(e.iterable());1962        let into_iter_fn_expr =1963            self.alloc_expr(into_iter_fn.map_or(Expr::Missing, Expr::Path), syntax_ptr);1964        let iterator = self.alloc_expr(1965            Expr::Call { callee: into_iter_fn_expr, args: Box::new([head]) },1966            syntax_ptr,1967        );1968        let none_arm = MatchArm {1969            pat: self.alloc_pat_desugared(option_none.map_or(Pat::Missing, Pat::Path)),1970            guard: None,1971            expr: self.alloc_expr(Expr::Break { expr: None, label: None }, syntax_ptr),1972        };1973        let some_pat = Pat::TupleStruct {1974            path: option_some.map(Box::new),1975            args: Box::new([self.collect_pat_top(e.pat())]),1976            ellipsis: None,1977        };1978        let label = e.label().map(|label| {1979            (self.hygiene_id_for(label.syntax().text_range()), self.collect_label(label))1980        });1981        let some_arm = MatchArm {1982            pat: self.alloc_pat_desugared(some_pat),1983            guard: None,1984            expr: self.with_opt_labeled_rib(label, |this| {1985                this.collect_expr_opt(e.loop_body().map(|it| it.into()))1986            }),1987        };1988        let iter_name = self.generate_new_name();1989        let iter_expr = self.alloc_expr(Expr::Path(Path::from(iter_name.clone())), syntax_ptr);1990        let iter_expr_mut = self.alloc_expr(1991            Expr::Ref { expr: iter_expr, rawness: Rawness::Ref, mutability: Mutability::Mut },1992            syntax_ptr,1993        );1994        let iter_next_fn_expr =1995            self.alloc_expr(iter_next_fn.map_or(Expr::Missing, Expr::Path), syntax_ptr);1996        let iter_next_expr = self.alloc_expr(1997            Expr::Call { callee: iter_next_fn_expr, args: Box::new([iter_expr_mut]) },1998            syntax_ptr,1999        );2000        let loop_inner = self.alloc_expr(

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.