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.rs299
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(&param);
- 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(&param);
+ 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 {