Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/expr_store/lower.rs')
| -rw-r--r-- | crates/hir-def/src/expr_store/lower.rs | 299 |
1 files changed, 246 insertions, 53 deletions
diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 0a1c23c2cc..f3cf2f7d81 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -41,7 +41,7 @@ use crate::{ expr_store::{ Body, BodySourceMap, ExprPtr, ExprRoot, ExpressionStore, ExpressionStoreBuilder, ExpressionStoreDiagnostics, ExpressionStoreSourceMap, HygieneId, LabelPtr, LifetimePtr, - PatPtr, TypePtr, + PatPtr, StoreVisitor, TypePtr, body::Param, expander::Expander, lower::generics::ImplTraitLowerFn, @@ -57,7 +57,7 @@ use crate::{ item_tree::FieldsShape, lang_item::{LangItemTarget, LangItems}, nameres::{DefMap, LocalDefMap, MacroSubNs, block_def_map}, - signatures::StructSignature, + signatures::{StructSignature, TypeAliasSignature}, type_ref::{ ArrayType, ConstRef, FnType, LifetimeRef, LifetimeRefId, Mutability, PathId, Rawness, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, UseArgRef, @@ -332,61 +332,67 @@ pub(crate) fn lower_function( let mut has_self_param = false; let mut has_variadic = false; collector.collect_impl_trait(&mut expr_collector, |collector, mut impl_trait_lower_fn| { - if let Some(param_list) = fn_.value.param_list() { - if let Some(param) = param_list.self_param() { - let enabled = collector.check_cfg(¶m); - if enabled { - has_self_param = true; - params.push(match param.ty() { - Some(ty) => collector.lower_type_ref(ty, &mut impl_trait_lower_fn), - None => { - let self_type = collector.alloc_type_ref_desugared(TypeRef::Path( - Name::new_symbol_root(sym::Self_).into(), - )); - let lifetime = param - .lifetime() - .map(|lifetime| collector.lower_lifetime_ref(lifetime)); - match param.kind() { - ast::SelfParamKind::Owned => self_type, - ast::SelfParamKind::Ref => collector.alloc_type_ref_desugared( - TypeRef::Reference(Box::new(RefType { - ty: self_type, - lifetime, - mutability: Mutability::Shared, - })), - ), - ast::SelfParamKind::MutRef => collector.alloc_type_ref_desugared( - TypeRef::Reference(Box::new(RefType { - ty: self_type, - lifetime, - mutability: Mutability::Mut, - })), - ), + collector.with_lifetime_bound_scope(LifetimeBoundScope::Argument, |collector| { + if let Some(param_list) = fn_.value.param_list() { + if let Some(param) = param_list.self_param() { + let enabled = collector.check_cfg(¶m); + if enabled { + has_self_param = true; + params.push(match param.ty() { + Some(ty) => collector.lower_type_ref(ty, &mut impl_trait_lower_fn), + None => { + let self_type = collector.alloc_type_ref_desugared(TypeRef::Path( + Name::new_symbol_root(sym::Self_).into(), + )); + let lifetime = param + .lifetime() + .map(|lifetime| collector.lower_lifetime_ref(lifetime)); + match param.kind() { + ast::SelfParamKind::Owned => self_type, + ast::SelfParamKind::Ref => collector.alloc_type_ref_desugared( + TypeRef::Reference(Box::new(RefType { + ty: self_type, + lifetime, + mutability: Mutability::Shared, + })), + ), + ast::SelfParamKind::MutRef => collector + .alloc_type_ref_desugared(TypeRef::Reference(Box::new( + RefType { + ty: self_type, + lifetime, + mutability: Mutability::Mut, + }, + ))), + } } - } - }); + }); + } + } + let p = param_list + .params() + .filter(|param| collector.check_cfg(param)) + .filter(|param| { + let is_variadic = param.dotdotdot_token().is_some(); + has_variadic |= is_variadic; + !is_variadic + }) + .map(|param| param.ty()) + // FIXME + .collect::<Vec<_>>(); + for p in p { + params.push(collector.lower_type_ref_opt(p, &mut impl_trait_lower_fn)); } } - let p = param_list - .params() - .filter(|param| collector.check_cfg(param)) - .filter(|param| { - let is_variadic = param.dotdotdot_token().is_some(); - has_variadic |= is_variadic; - !is_variadic - }) - .map(|param| param.ty()) - // FIXME - .collect::<Vec<_>>(); - for p in p { - params.push(collector.lower_type_ref_opt(p, &mut impl_trait_lower_fn)); - } - } + }) }); - let generics = collector.finish(); let return_type = fn_.value.ret_type().map(|ret_type| { - expr_collector.lower_type_ref_opt(ret_type.ty(), &mut ExprCollector::impl_trait_allocator) + expr_collector.with_lifetime_bound_scope(LifetimeBoundScope::Return, |this| { + this.lower_type_ref_opt(ret_type.ty(), &mut ExprCollector::impl_trait_allocator) + }) }); + collector.update_to_late_bound_lifetimes(&expr_collector.named_lifetime_store); + let generics = collector.finish(); let return_type = if fn_.value.async_token().is_some() || fn_.value.gen_token().is_some() { let (path, assoc_name) = @@ -445,6 +451,7 @@ pub struct ExprCollector<'db> { module: ModuleId, lang_items: OnceCell<&'db LangItems>, pub store: ExpressionStoreBuilder, + pub named_lifetime_store: NamedLifetimeStore, // state stuff // Prevent nested impl traits like `impl Foo<impl Bar>`. @@ -551,6 +558,48 @@ impl BindingList { } } +#[derive(Debug, Default)] +pub struct NamedLifetimeStore { + lifetime_bound_scope: Option<LifetimeBoundScope>, + lifetimes_in_where_clause: FxIndexSet<Name>, + lifetimes_constrained_by_input: FxIndexSet<Name>, + lifetimes_in_output: FxIndexSet<Name>, +} + +#[derive(Debug)] +enum LifetimeBoundScope { + Argument, + Return, + WhereClause, + ImplTrait { is_argument_scope: bool }, +} + +impl NamedLifetimeStore { + /// Adds in the lifetime one of three lists fields if + /// `lifetime_bound_context` is `Some` and based on enum variant. + pub(crate) fn push_named_lifetime(&mut self, lifetime: Name) { + match self.lifetime_bound_scope { + Some(LifetimeBoundScope::Argument) => { + self.lifetimes_constrained_by_input.insert(lifetime); + } + Some(LifetimeBoundScope::Return) => { + self.lifetimes_in_output.insert(lifetime); + } + Some(LifetimeBoundScope::WhereClause) => { + self.lifetimes_in_where_clause.insert(lifetime); + } + Some(LifetimeBoundScope::ImplTrait { is_argument_scope }) => { + if is_argument_scope { + self.lifetimes_in_where_clause.insert(lifetime); + } else { + self.lifetimes_in_output.insert(lifetime); + } + } + None => (), + }; + } +} + impl<'db> ExprCollector<'db> { pub fn new( db: &dyn SourceDatabase, @@ -578,6 +627,7 @@ impl<'db> ExprCollector<'db> { outer_impl_trait: false, krate, name_generator_index: 0, + named_lifetime_store: NamedLifetimeStore::default(), }; result.store.inference_roots = Some(SmallVec::new()); result @@ -717,8 +767,16 @@ impl<'db> ExprCollector<'db> { TypeRef::Error } else { return self.with_outer_impl_trait_scope(true, |this| { - let type_bounds = - this.type_bounds_from_ast(inner.type_bound_list(), impl_trait_lower_fn); + let is_argument_scope = this.is_argument_lt_bound_scope(); + let type_bounds = this.with_lifetime_bound_scope( + LifetimeBoundScope::ImplTrait { is_argument_scope }, + |this| { + this.type_bounds_from_ast( + inner.type_bound_list(), + impl_trait_lower_fn, + ) + }, + ); impl_trait_lower_fn(this, AstPtr::new(&node), type_bounds) }); } @@ -781,6 +839,10 @@ impl<'db> ExprCollector<'db> { lifetime_ref: LifetimeRef, node: LifetimePtr, ) -> LifetimeRefId { + if let LifetimeRef::Named(name) = &lifetime_ref { + self.named_lifetime_store.push_named_lifetime(name.clone()); + } + let id = self.store.lifetimes.alloc(lifetime_ref); let ptr = self.expander.in_file(node); self.store.lifetime_map_back.insert(id, ptr); @@ -3359,6 +3421,137 @@ impl ExprCollector<'_> { fn hygiene_id_for(&self, range: TextRange) -> HygieneId { self.expander.hygiene_for_range(self.db, range) } + + fn with_lifetime_bound_scope<T>( + &mut self, + bound_scope: LifetimeBoundScope, + f: impl FnOnce(&mut Self) -> T, + ) -> T { + let old = self.named_lifetime_store.lifetime_bound_scope.replace(bound_scope); + let res = f(self); + self.named_lifetime_store.lifetime_bound_scope = old; + res + } + + fn for_path_type_projection<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { + if self.is_argument_lt_bound_scope() { + let old = self.named_lifetime_store.lifetime_bound_scope.take(); + let res = f(self); + self.named_lifetime_store.lifetime_bound_scope = old; + res + } else { + f(self) + } + } + + fn push_named_target_lifetime(&mut self, id: LifetimeRefId) { + if let LifetimeRef::Named(name) = &self.store.lifetimes[id] { + self.named_lifetime_store.push_named_lifetime(name.clone()); + } + } + + fn extend_type_alias_lifetime(&mut self, lifetimes: impl Iterator<Item = Name>) { + self.named_lifetime_store.lifetimes_constrained_by_input.extend(lifetimes); + } + + fn is_argument_lt_bound_scope(&mut self) -> bool { + matches!(self.named_lifetime_store.lifetime_bound_scope, Some(LifetimeBoundScope::Argument)) + } + + fn get_constrained_lifetimes_if_type_alias( + &mut self, + mod_path: &intern::Interned<ModPath>, + generic_args: Option<&GenericArgs>, + ) -> Option<FxIndexSet<Name>> { + let r_path = self.def_map.resolve_path( + self.local_def_map, + self.db, + self.module, + mod_path, + BuiltinShadowMode::Module, + None, + ); + let def_id = r_path.0.types.map(|item| item.def)?; + let res = if let crate::ModuleDefId::TypeAliasId(id) = def_id { + let Some(generic_args) = generic_args else { return Some(FxIndexSet::default()) }; + + let constrained_lt_indices = get_constrained_lifetimes(self.db, id); + let res = constrained_lt_indices + .iter() + .filter_map(|&idx| { + let lt_ref = generic_args + .args + .iter() + .filter_map(|arg| match arg { + &GenericArg::Lifetime(lt_ref) => Some(lt_ref), + GenericArg::Type(_) | GenericArg::Const(_) => None, + }) + .nth(idx as usize)?; + match &self.store.lifetimes[lt_ref] { + LifetimeRef::Named(name) => Some(name.clone()), + _ => None, + } + }) + .collect(); + Some(res) + } else { + None + }; + return res; + + #[salsa::tracked(returns(deref), cycle_result = get_constrained_lifetimes_cycle_result)] + fn get_constrained_lifetimes( + db: &dyn SourceDatabase, + type_alias_id: TypeAliasId, + ) -> Box<[u32]> { + let TypeAliasSignature { generic_params, store, ty, .. } = + TypeAliasSignature::of(db, type_alias_id); + let &Some(ty) = ty else { return Default::default() }; + + let mut visitor = Visitor { + store, + generic_params, + parent: type_alias_id, + constrained_lt_indices: Vec::new(), + }; + store.visit_type_ref_children(ty, &mut visitor); + + return visitor.constrained_lt_indices.into_boxed_slice(); + + struct Visitor<'a> { + store: &'a ExpressionStore, + generic_params: &'a GenericParams, + parent: TypeAliasId, + constrained_lt_indices: Vec<u32>, + } + + impl StoreVisitor for Visitor<'_> { + fn on_lifetime(&mut self, lifetime: LifetimeRefId) { + if let LifetimeRef::Named(lifetime_name) = &self.store[lifetime] + && let Some(param_id) = self + .generic_params + .find_lifetime_by_name(lifetime_name, self.parent.into()) + { + self.constrained_lt_indices.push(param_id.local_id.into_raw().into_u32()); + } + } + + fn on_generic_args(&mut self, args: &GenericArgs) { + if !args.has_self_type { + crate::expr_store::visit_generic_args(self, args); + } + } + } + } + + fn get_constrained_lifetimes_cycle_result( + _db: &dyn SourceDatabase, + _: salsa::Id, + _id: TypeAliasId, + ) -> Box<[u32]> { + Default::default() + } + } } fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool { |