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