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(¶m) {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(¶m);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(<.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.