From f164e84d02613e413cace0188d9d296ccdbe16d0 Mon Sep 17 00:00:00 2001 From: dfireBird Date: Sun, 19 Apr 2026 07:00:23 +0530 Subject: [PATCH] feat: early late classification of lifetimes --- crates/hir-def/src/expr_store/lower.rs | 241 ++++++++++++++---- .../hir-def/src/expr_store/lower/generics.rs | 57 ++++- crates/hir-def/src/expr_store/lower/path.rs | 23 +- crates/hir-def/src/hir/generics.rs | 39 ++- crates/hir-ty/src/consteval.rs | 2 + crates/hir-ty/src/display.rs | 8 +- crates/hir-ty/src/dyn_compatibility.rs | 7 +- crates/hir-ty/src/generics.rs | 36 ++- crates/hir-ty/src/infer.rs | 5 +- crates/hir-ty/src/infer/diagnostics.rs | 11 +- crates/hir-ty/src/infer/path.rs | 3 +- crates/hir-ty/src/lib.rs | 6 +- crates/hir-ty/src/lower.rs | 166 +++++++++--- crates/hir-ty/src/lower/path.rs | 24 +- crates/hir-ty/src/mir/lower.rs | 10 +- crates/hir-ty/src/next_solver/fold.rs | 18 +- crates/hir-ty/src/next_solver/region.rs | 9 + .../hir-ty/src/tests/display_source_code.rs | 2 +- crates/hir-ty/src/tests/simple.rs | 12 +- crates/hir-ty/src/tests/traits.rs | 12 +- crates/hir/src/lib.rs | 2 +- crates/hir/src/source_analyzer.rs | 28 +- .../src/handlers/extract_type_alias.rs | 3 +- crates/ide-completion/src/tests/special.rs | 5 +- crates/ide/src/inlay_hints/bind_pat.rs | 19 +- 25 files changed, 575 insertions(+), 173 deletions(-) diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index a82046149ae3..eee42172879a 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -12,7 +12,7 @@ use base_db::FxIndexSet; use cfg::CfgOptions; use either::Either; use hir_expand::{ - HirFileId, InFile, MacroDefId, + HirFileId, InFile, Lookup, MacroDefId, mod_path::ModPath, name::{AsName, Name}, span_map::SpanMap, @@ -33,8 +33,8 @@ use thin_vec::ThinVec; use tt::TextRange; use crate::{ - AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, ItemContainerId, - MacroId, ModuleDefId, ModuleId, TraitId, TypeAliasId, UnresolvedMacro, + AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, HasModule, ImplId, + ItemContainerId, MacroId, ModuleDefId, ModuleId, TraitId, TypeAliasId, UnresolvedMacro, attrs::AttrFlags, db::DefDatabase, expr_store::{ @@ -56,6 +56,7 @@ use crate::{ lang_item::{LangItemTarget, LangItems}, nameres::{DefMap, LocalDefMap, MacroSubNs, block_def_map}, signatures::StructSignature, + src::HasSource, type_ref::{ ArrayType, ConstRef, FnType, LifetimeRef, LifetimeRefId, Mutability, PathId, Rawness, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, UseArgRef, @@ -323,61 +324,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::>(); + 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::>(); - 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) = @@ -436,6 +443,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`. @@ -542,6 +550,38 @@ impl BindingList { } } +#[derive(Debug, Default)] +pub struct NamedLifetimeStore { + lifetime_bound_scope: Option, + lifetimes_in_where_clause: FxIndexSet, + lifetimes_constraint_by_input: FxIndexSet, + lifetimes_in_output: FxIndexSet, +} + +#[derive(Debug)] +enum LifetimeBoundScope { + Argument, + Return, + WhereClause, +} + +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_constraint_by_input.insert(lifetime) + } + Some(LifetimeBoundScope::Return) => self.lifetimes_in_output.insert(lifetime), + Some(LifetimeBoundScope::WhereClause) => { + self.lifetimes_in_where_clause.insert(lifetime) + } + _ => false, + }; + } +} + impl<'db> ExprCollector<'db> { /// Creates a collector for a signature store, this will populate `const_expr_origins` to any /// top level const arg roots. @@ -582,6 +622,7 @@ impl<'db> ExprCollector<'db> { outer_impl_trait: false, krate, name_generator_index: 0, + named_lifetime_store: NamedLifetimeStore::default(), } } @@ -783,6 +824,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); @@ -3177,6 +3222,98 @@ impl ExprCollector<'_> { fn hygiene_id_for(&self, range: TextRange) -> HygieneId { self.expander.hygiene_for_range(self.db, range) } + + fn with_lifetime_bound_scope( + &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(&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) { + self.named_lifetime_store.lifetimes_constraint_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, + path: &ast::Path, + ) -> Option> { + let mod_path = ModPath::from_src(self.db, path.clone(), &mut |range| { + self.span_map().span_for_range(range).ctx + })?; + + 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 { + Some(get_constrained_lifetimes(self.db, id)) + } else { + None + }; + return res; + + #[salsa::tracked(returns(clone), cycle_result = get_constrained_lifetimes_cycle_result)] + fn get_constrained_lifetimes( + db: &dyn DefDatabase, + type_alias_id: TypeAliasId, + ) -> FxIndexSet { + let loc = type_alias_id.lookup(db); + let module = loc.container.module(db); + let alias = loc.source(db); + + let mut expr_collector = ExprCollector::signature(db, module, alias.file_id); + alias.value.ty().map(|ty| { + // Note: This is specific for function lowering, re-using it for type alias because rustc + // determines lifetimes by visiting the type itself + expr_collector.with_lifetime_bound_scope( + LifetimeBoundScope::Argument, + |expr_collector| { + expr_collector.lower_type_ref(ty, &mut ExprCollector::impl_trait_allocator) + }, + ) + }); + expr_collector.named_lifetime_store.lifetimes_constraint_by_input + } + + fn get_constrained_lifetimes_cycle_result( + _db: &dyn DefDatabase, + _: salsa::Id, + _id: TypeAliasId, + ) -> FxIndexSet { + FxIndexSet::default() + } + } } fn comma_follows_token(t: Option) -> bool { diff --git a/crates/hir-def/src/expr_store/lower/generics.rs b/crates/hir-def/src/expr_store/lower/generics.rs index 5ffc4f5851d3..91c67b05007b 100644 --- a/crates/hir-def/src/expr_store/lower/generics.rs +++ b/crates/hir-def/src/expr_store/lower/generics.rs @@ -12,10 +12,13 @@ use thin_vec::ThinVec; use crate::{ GenericDefId, TypeOrConstParamId, TypeParamId, - expr_store::{TypePtr, lower::ExprCollector}, + expr_store::{ + TypePtr, + lower::{ExprCollector, LifetimeBoundScope, NamedLifetimeStore}, + }, hir::generics::{ - ConstParamData, GenericParams, LifetimeParamData, TypeOrConstParamData, TypeParamData, - TypeParamProvenance, WherePredicate, + ConstParamData, GenericParams, LifetimeBoundType, LifetimeParamData, TypeOrConstParamData, + TypeParamData, TypeParamProvenance, WherePredicate, }, type_ref::{LifetimeRef, LifetimeRefId, TypeBound, TypeRef, TypeRefId}, }; @@ -62,7 +65,9 @@ impl GenericParamsCollector { self.lower_param_list(ec, params) } if let Some(where_clause) = where_clause { - self.lower_where_predicates(ec, where_clause); + ec.with_lifetime_bound_scope(LifetimeBoundScope::WhereClause, |ec| { + self.lower_where_predicates(ec, where_clause) + }); } } @@ -118,7 +123,9 @@ impl GenericParamsCollector { local_id: idx, })); let type_ref = ec.alloc_type_ref_desugared(type_ref); - self.lower_bounds(ec, type_param.type_bound_list(), Either::Left(type_ref)); + ec.with_lifetime_bound_scope(LifetimeBoundScope::WhereClause, |ec| { + self.lower_bounds(ec, type_param.type_bound_list(), Either::Left(type_ref)) + }); } ast::GenericParam::ConstParam(const_param) => { let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); @@ -141,13 +148,18 @@ impl GenericParamsCollector { ast::GenericParam::LifetimeParam(lifetime_param) => { let lifetime = ec.lower_lifetime_ref_opt(lifetime_param.lifetime()); if let LifetimeRef::Named(name) = &ec.store.lifetimes[lifetime] { - let param = LifetimeParamData { name: name.clone() }; + let param = LifetimeParamData { + name: name.clone(), + bound_type: LifetimeBoundType::EarlyBound, + }; let _idx = self.lifetimes.alloc(param); - self.lower_bounds( - ec, - lifetime_param.type_bound_list(), - Either::Right(lifetime), - ); + ec.with_lifetime_bound_scope(LifetimeBoundScope::WhereClause, |ec| { + self.lower_bounds( + ec, + lifetime_param.type_bound_list(), + Either::Right(lifetime), + ) + }); } } } @@ -229,6 +241,9 @@ impl GenericParamsCollector { } (Either::Right(_), TypeBound::ForLifetime(..) | TypeBound::Path(..)) => return, }; + if let WherePredicate::Lifetime { target, .. } = predicate { + ec.push_named_target_lifetime(target); + } self.where_predicates.push(predicate); } @@ -277,4 +292,24 @@ impl GenericParamsCollector { self.lower_bounds(ec, Some(bounds), Either::Left(self_)); } } + + pub(crate) fn update_to_late_bound_lifetimes( + &mut self, + named_lifetime_store: &NamedLifetimeStore, + ) { + for (_param_id, lifetime) in self.lifetimes.iter_mut() { + let lifetime_name = &lifetime.name; + if named_lifetime_store.lifetimes_in_where_clause.contains(lifetime_name) { + continue; + } + + if !named_lifetime_store.lifetimes_constraint_by_input.contains(lifetime_name) + && named_lifetime_store.lifetimes_in_output.contains(lifetime_name) + { + continue; + } + + lifetime.bound_type = LifetimeBoundType::LateBound + } + } } diff --git a/crates/hir-def/src/expr_store/lower/path.rs b/crates/hir-def/src/expr_store/lower/path.rs index 579465e10f93..2acb08f4291d 100644 --- a/crates/hir-def/src/expr_store/lower/path.rs +++ b/crates/hir-def/src/expr_store/lower/path.rs @@ -54,6 +54,17 @@ pub(super) fn lower_path( ast_segments.push(_segment.clone()); segments.push(name); }; + + let type_alias_constrained_lifetimes = collector.get_constrained_lifetimes_if_type_alias(&path); + let mut old_lifetime_bound_scope = None; + if collector.is_argument_lt_bound_scope() + && let Some(lifetimes) = type_alias_constrained_lifetimes + { + collector.extend_type_alias_lifetime(lifetimes.into_iter()); + // we are disabling lifetime bound collector for the entire path + old_lifetime_bound_scope = collector.named_lifetime_store.lifetime_bound_scope.take(); + } + loop { let Some(segment) = path.segment() else { segments.push(Name::missing()); @@ -112,7 +123,10 @@ pub(super) fn lower_path( ast::PathSegmentKind::Type { type_ref, trait_ref } => { debug_assert!(path.qualifier().is_none()); // this can only occur at the first segment - let self_type = collector.lower_type_ref(type_ref?, impl_trait_lower_fn); + let type_ref = type_ref?; + let self_type = collector.for_path_type_projection(|collector| { + collector.lower_type_ref(type_ref, impl_trait_lower_fn) + }); match trait_ref { // ::foo @@ -122,7 +136,9 @@ pub(super) fn lower_path( } // >::Foo desugars to Trait::Foo Some(trait_ref) => { - let path = collector.lower_path(trait_ref.path()?, impl_trait_lower_fn)?; + let path = collector.for_path_type_projection(|collector| { + collector.lower_path(trait_ref.path()?, impl_trait_lower_fn) + })?; // FIXME: Unnecessary clone collector.alloc_type_ref( TypeRef::Path(path.clone()), @@ -196,6 +212,9 @@ pub(super) fn lower_path( None => break, }; } + if let Some(old_scope) = old_lifetime_bound_scope { + collector.named_lifetime_store.lifetime_bound_scope = Some(old_scope) + } segments.reverse(); if !generic_args.is_empty() || type_anchor.is_some() { generic_args.resize(segments.len(), None); diff --git a/crates/hir-def/src/hir/generics.rs b/crates/hir-def/src/hir/generics.rs index 43dd7d1c54cd..b1c11a64f9c6 100644 --- a/crates/hir-def/src/hir/generics.rs +++ b/crates/hir-def/src/hir/generics.rs @@ -33,6 +33,13 @@ pub struct TypeParamData { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct LifetimeParamData { pub name: Name, + pub bound_type: LifetimeBoundType, +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum LifetimeBoundType { + EarlyBound, + LateBound, } /// Data about a generic const parameter (to a function, struct, impl, ...). @@ -288,7 +295,12 @@ impl GenericParams { #[inline] pub fn len_lifetimes(&self) -> usize { - self.lifetimes.len() + self.lifetimes.len() - self.len_late_bound_lifetimes() + } + + #[inline] + pub fn len_late_bound_lifetimes(&self) -> usize { + self.lifetimes.iter().filter(|(_, p)| p.bound_type == LifetimeBoundType::LateBound).count() } #[inline] @@ -324,7 +336,21 @@ impl GenericParams { pub fn iter_lt( &self, ) -> impl DoubleEndedIterator { - self.lifetimes.iter() + self.iter_early_bound_lt().chain(self.iter_late_bound_lt()) + } + + #[inline] + pub fn iter_early_bound_lt( + &self, + ) -> impl DoubleEndedIterator { + self.lifetimes.iter().filter(|(_, p)| p.bound_type == LifetimeBoundType::EarlyBound) + } + + #[inline] + pub fn iter_late_bound_lt( + &self, + ) -> impl DoubleEndedIterator { + self.lifetimes.iter().filter(|(_, p)| p.bound_type == LifetimeBoundType::LateBound) } pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option { @@ -371,4 +397,13 @@ impl GenericParams { if &p.name == name { Some(LifetimeParamId { local_id: id, parent }) } else { None } }) } + + pub fn late_bound_lifetime_idx( + &self, + lifetime_param_id: &LocalLifetimeParamId, + ) -> Option { + self.iter_late_bound_lt().position(|(id, data)| { + data.bound_type == LifetimeBoundType::LateBound && id == *lifetime_param_id + }) + } } diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 0fdd3ff1d928..826aa9dd65c9 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -22,6 +22,7 @@ use crate::{ db::HirDatabase, display::DisplayTarget, infer::InferenceContext, + lower::LifetimeLoweringMode, mir::{MirEvalError, MirLowerError, pad16}, next_solver::{ Allocation, Const, ConstKind, Consts, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, @@ -291,6 +292,7 @@ pub(crate) fn eval_to_const<'db>(expr: ExprId, ctx: &mut InferenceContext<'_, 'd ctx.store, ctx.generic_def, LifetimeElisionKind::Infer, + LifetimeLoweringMode::Bound, ); if let Some(c) = ctx.path_to_const(p) { return c; diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index f7d333f94c38..645f8a74f516 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -2300,10 +2300,10 @@ impl<'db> HirDisplay<'db> for Region<'db> { Ok(()) } RegionKind::ReBound(BoundVarIndexKind::Bound(db), idx) => { - write!(f, "?{}.{}", db.as_u32(), idx.var.as_u32()) + write!(f, "'?{}.{}", db.as_u32(), idx.var.as_u32()) } RegionKind::ReBound(BoundVarIndexKind::Canonical, idx) => { - write!(f, "?c.{}", idx.var.as_u32()) + write!(f, "'?c.{}", idx.var.as_u32()) } RegionKind::ReVar(_) => write!(f, "_"), RegionKind::ReStatic => write!(f, "'static"), @@ -2315,8 +2315,8 @@ impl<'db> HirDisplay<'db> for Region<'db> { } } RegionKind::ReErased => write!(f, "'"), - RegionKind::RePlaceholder(_) => write!(f, ""), - RegionKind::ReLateParam(_) => write!(f, ""), + RegionKind::RePlaceholder(_) => write!(f, "'"), + RegionKind::ReLateParam(_) => write!(f, "'"), } } } diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs index 0cf7f650f0d9..bf5491fe21cb 100644 --- a/crates/hir-ty/src/dyn_compatibility.rs +++ b/crates/hir-ty/src/dyn_compatibility.rs @@ -399,7 +399,7 @@ where } fn receiver_is_dispatchable<'db>( - db: &dyn HirDatabase, + db: &'db dyn HirDatabase, trait_: TraitId, func: FunctionId, sig: &EarlyBinder<'db, Binder<'db, rustc_type_ir::FnSig>>>, @@ -421,9 +421,8 @@ fn receiver_is_dispatchable<'db>( return true; } - let Some(&receiver_ty) = sig.inputs().skip_binder().first() else { - return false; - }; + // FIXME: sig.input(0) has unwrap and might panic + let receiver_ty = interner.liberate_late_bound_regions(func.into(), sig.input(0)); let lang_items = interner.lang_items(); let traits = (lang_items.Unsize, lang_items.DispatchFromDyn); diff --git a/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs index 32482ca94b71..32712072720f 100644 --- a/crates/hir-ty/src/generics.rs +++ b/crates/hir-ty/src/generics.rs @@ -79,7 +79,7 @@ impl<'db> SingleGenerics<'db> { fn iter_lifetimes(&self) -> impl Iterator { let parent = self.def; self.params - .iter_lt() + .iter_early_bound_lt() .map(move |(local_id, data)| (LifetimeParamId { parent, local_id }, data)) } @@ -136,6 +136,19 @@ impl<'db> SingleGenerics<'db> { pub(crate) fn iter_id(&self) -> impl Iterator { self.iter().map(|(id, _)| id) } + + pub(crate) fn iter_late_bound( + &self, + ) -> impl Iterator)> { + // we don't handle late bound types or const now, so it is ignored for now + let parent = self.def; + self.params.iter_late_bound_lt().map(move |(local_id, data)| { + ( + GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id }), + GenericParamDataRef::LifetimeParamData(data), + ) + }) + } } impl<'db> Generics<'db> { @@ -178,6 +191,12 @@ impl<'db> Generics<'db> { self.owner().iter_with_idx() } + pub(crate) fn iter_self_late_bound( + &self, + ) -> impl Iterator)> { + self.owner().iter_late_bound() + } + pub(crate) fn iter_parent_id(&self) -> impl Iterator { self.parent().into_iter().flat_map(|parent| parent.iter_id()) } @@ -275,12 +294,19 @@ impl<'db> Generics<'db> { } } - pub(crate) fn lifetime_param_idx(&self, param: LifetimeParamId) -> u32 { + // Rename this? + pub(crate) fn lifetime_param_idx(&self, param: LifetimeParamId) -> (u32, bool) { let owner = self.find_owner(param.parent); + if let Some(late_bound_idx) = owner.params.late_bound_lifetime_idx(¶m.local_id) { + return (late_bound_idx as u32, true); + } let has_trait_self = matches!(owner.def, GenericDefId::TraitId(_)); - owner.preceding_params_len - + u32::from(has_trait_self) - + param.local_id.into_raw().into_u32() + ( + owner.preceding_params_len + + u32::from(has_trait_self) + + param.local_id.into_raw().into_u32(), + false, + ) } } diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index d28ee4ab443b..fbdc28b8e93a 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -80,7 +80,8 @@ use crate::{ unify::resolve_completely::WriteBackCtxt, }, lower::{ - ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, diagnostics::TyLoweringDiagnostic, + ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, LifetimeLoweringMode, + diagnostics::TyLoweringDiagnostic, }, method_resolution::CandidateId, next_solver::{ @@ -1761,6 +1762,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { types_source, self.generic_def, lifetime_elision, + LifetimeLoweringMode::LateParam, ); f(&mut ctx) } @@ -2076,6 +2078,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { InferenceTyDiagnosticSource::Body, self.generic_def, LifetimeElisionKind::Infer, + LifetimeLoweringMode::LateParam, ); if let Some(type_anchor) = path.type_anchor() { diff --git a/crates/hir-ty/src/infer/diagnostics.rs b/crates/hir-ty/src/infer/diagnostics.rs index 2bdc6f9491dc..e823042e081f 100644 --- a/crates/hir-ty/src/infer/diagnostics.rs +++ b/crates/hir-ty/src/infer/diagnostics.rs @@ -13,6 +13,7 @@ use hir_def::{hir::ExprOrPatId, resolver::Resolver}; use la_arena::{Idx, RawIdx}; use thin_vec::ThinVec; +use crate::lower::LifetimeLoweringMode; use crate::{ InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic, db::HirDatabase, @@ -68,9 +69,17 @@ impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { source: InferenceTyDiagnosticSource, generic_def: GenericDefId, lifetime_elision: LifetimeElisionKind<'db>, + lifetime_lowering_mode: LifetimeLoweringMode, ) -> Self { Self { - ctx: TyLoweringContext::new(db, resolver, store, generic_def, lifetime_elision), + ctx: TyLoweringContext::new( + db, + resolver, + store, + generic_def, + lifetime_elision, + lifetime_lowering_mode, + ), diagnostics, source, } diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index 4df38e96ee00..577466227df5 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -13,7 +13,7 @@ use stdx::never; use crate::{ InferenceDiagnostic, Span, ValueTyDefId, infer::diagnostics::InferenceTyLoweringContext as TyLoweringContext, - lower::{GenericPredicates, LifetimeElisionKind}, + lower::{GenericPredicates, LifetimeElisionKind, LifetimeLoweringMode}, method_resolution::{self, CandidateId, MethodError}, next_solver::{ GenericArg, GenericArgs, TraitRef, Ty, infer::traits::ObligationCause, @@ -147,6 +147,7 @@ impl<'db> InferenceContext<'_, 'db> { InferenceTyDiagnosticSource::Body, self.generic_def, LifetimeElisionKind::Infer, + LifetimeLoweringMode::LateParam, ); let mut path_ctx = if no_diagnostics { ctx.at_path_forget_diagnostics(path) diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 5cb2a3d804d6..abe6abd9dfaf 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -106,8 +106,8 @@ pub use infer::{ could_unify, could_unify_deeply, infer_query_with_inspect, }; pub use lower::{ - GenericPredicates, ImplTraits, LifetimeElisionKind, TyDefId, TyLoweringContext, ValueTyDefId, - diagnostics::*, + GenericPredicates, ImplTraits, LifetimeElisionKind, LifetimeLoweringMode, TyDefId, + TyLoweringContext, ValueTyDefId, diagnostics::*, }; pub use next_solver::interner::{attach_db, attach_db_allow_change, with_attached_db}; pub use target_feature::TargetFeatures; @@ -216,7 +216,7 @@ pub fn type_or_const_param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> } pub fn lifetime_param_idx(db: &dyn HirDatabase, id: LifetimeParamId) -> u32 { - generics::generics(db, id.parent).lifetime_param_idx(id) + generics::generics(db, id.parent).lifetime_param_idx(id).0 } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index d3db2a90579e..c4dc5822bcde 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -40,9 +40,10 @@ use path::{PathDiagnosticCallback, PathLoweringContext}; use rustc_ast_ir::Mutability; use rustc_hash::FxHashSet; use rustc_type_ir::{ - AliasTyKind, BoundVarIndexKind, ConstKind, DebruijnIndex, ExistentialPredicate, - ExistentialProjection, ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind, - TyKind, TypeFoldable, TypeVisitableExt, Upcast, UpcastFrom, elaborate, + AliasTyKind, BoundRegion, BoundRegionKind, BoundTyKind, BoundVar, BoundVarIndexKind, + BoundVariableKind, ConstKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection, + ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind, TyKind, TypeFoldable, + TypeVisitableExt, Upcast, UpcastFrom, elaborate, inherent::{Clause as _, GenericArgs as _, IntoKind as _, Region as _, Ty as _}, }; use smallvec::SmallVec; @@ -56,8 +57,8 @@ use crate::{ db::{HirDatabase, InternedOpaqueTyId}, generics::{Generics, SingleGenerics, generics}, next_solver::{ - AliasTy, Binder, BoundExistentialPredicates, Clause, ClauseKind, Clauses, Const, - DbInterner, EarlyBinder, EarlyParamRegion, ErrorGuaranteed, FxIndexMap, GenericArg, + AliasTy, Binder, BoundExistentialPredicates, BoundVarKinds, Clause, ClauseKind, Clauses, + Const, DbInterner, EarlyBinder, EarlyParamRegion, ErrorGuaranteed, FxIndexMap, GenericArg, GenericArgs, ParamConst, ParamEnv, PolyFnSig, Predicate, Region, SolverDefId, StoredClauses, StoredEarlyBinder, StoredGenericArg, StoredGenericArgs, StoredPolyFnSig, StoredTy, TraitPredicate, TraitRef, Ty, Tys, UnevaluatedConst, abi::Safety, @@ -190,6 +191,9 @@ pub struct TyLoweringContext<'db, 'a> { /// When lowering the defaults for generic params, this contains the index of the currently lowered param. /// We disallow referring to later params, or to ADT's `Self`. lowering_param_default: Option, + /// Bounds Vars in current context + bound_vars: Vec>, // FIXME: HRTB and other for lifetime doesn't change it now + lifetime_lowering_mode: LifetimeLoweringMode, } impl<'db, 'a> TyLoweringContext<'db, 'a> { @@ -199,10 +203,12 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { store: &'a ExpressionStore, def: GenericDefId, lifetime_elision: LifetimeElisionKind<'db>, + lifetime_lowering_mode: LifetimeLoweringMode, ) -> Self { let impl_trait_mode = ImplTraitLoweringState::new(ImplTraitLoweringMode::Disallowed); let in_binders = DebruijnIndex::ZERO; let interner = DbInterner::new_with(db, resolver.krate()); + let bound_vars = Vec::from(&[Self::bound_vars(db, interner, def)]); Self { db, // Can provide no block since we don't use it for trait solving. @@ -219,6 +225,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { diagnostics: Vec::new(), lifetime_elision, lowering_param_default: None, + bound_vars, + lifetime_lowering_mode, } } @@ -261,6 +269,27 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { pub(crate) fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) { self.diagnostics.push(TyLoweringDiagnostic { source: type_ref, kind }); } + + fn bound_vars( + db: &'db dyn HirDatabase, + interner: DbInterner<'db>, + def: GenericDefId, + ) -> BoundVarKinds<'db> { + let generics = generics(db, def); + let def_id = def.into(); + + let args = generics.iter_self_late_bound().map(|(_, data)| match data { + GenericParamDataRef::TypeParamData(..) => { + BoundVariableKind::Ty(BoundTyKind::Param(def_id)) + } + GenericParamDataRef::ConstParamData(..) => BoundVariableKind::Const, + GenericParamDataRef::LifetimeParamData(..) => { + BoundVariableKind::Region(BoundRegionKind::Named(def_id)) + } + }); + + BoundVarKinds::new_from_iter(interner, args) + } } #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] @@ -275,6 +304,16 @@ pub(crate) enum ImplTraitLoweringMode { Disallowed, } +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum LifetimeLoweringMode { + /// Lowers the late bound lifetimes to `ReBound`, used in cases when lowering + /// from outside of function. + Bound, + /// Lowers the late bound lifetimes to `ReLateParam`, used in cases when lowering + /// inside the function itself + LateParam, +} + impl<'db, 'a> TyLoweringContext<'db, 'a> { pub fn lower_ty(&mut self, type_ref: TypeRefId) -> Ty<'db> { self.lower_ty_ext(type_ref).0 @@ -423,12 +462,37 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } - fn region_param(&mut self, id: LifetimeParamId, index: u32) -> Region<'db> { + fn region_param( + &mut self, + id: LifetimeParamId, + index: u32, + is_late_bound: bool, + ) -> Region<'db> { if self.param_index_is_disallowed(index) { // FIXME: Report an error. Region::error(self.interner) } else { - Region::new_early_param(self.interner, EarlyParamRegion { id, index }) + if is_late_bound { + if self.lifetime_lowering_mode == LifetimeLoweringMode::Bound { + Region::new_bound( + self.interner, + self.in_binders, + BoundRegion { + var: BoundVar::from_u32(index), + kind: BoundRegionKind::Named(id.parent.into()), + }, + ) + } else { + let solver_def_id = id.parent.into(); + Region::new_late_param( + self.interner, + solver_def_id, + BoundRegionKind::Named(solver_def_id), + ) + } + } else { + Region::new_early_param(self.interner, EarlyParamRegion { id, index }) + } } } @@ -556,14 +620,19 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { args.push(ctx.lower_ty(ret_ty)); }); self.lifetime_elision = old_lifetime_elision; + + let binder = BoundVarKinds::new_from_slice(self.bound_vars.last().unwrap().as_slice()); Ty::new_fn_ptr( interner, - Binder::dummy(FnSig { - abi: fn_.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol), - safety: if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe }, - c_variadic: fn_.is_varargs, - inputs_and_output: Tys::new_from_slice(&args), - }), + Binder::bind_with_vars( + FnSig { + abi: fn_.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol), + safety: if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe }, + c_variadic: fn_.is_varargs, + inputs_and_output: Tys::new_from_slice(&args), + }, + binder, + ), ) } @@ -699,6 +768,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { let mut clause = None; match bound { &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => { + let binder = + BoundVarKinds::new_from_slice(self.bound_vars.last().unwrap().as_slice()); // FIXME Don't silently drop the hrtb lifetimes here if let Some((trait_ref, mut ctx)) = self.lower_trait_ref_from_path(path, self_ty) { // FIXME(sized-hierarchy): Remove this bound modifications once we have implemented @@ -714,12 +785,15 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } clause = Some(Clause(Predicate::new( interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Trait(TraitPredicate { - trait_ref, - polarity: rustc_type_ir::PredicatePolarity::Positive, - }), - )), + Binder::bind_with_vars( + rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Trait(TraitPredicate { + trait_ref, + polarity: rustc_type_ir::PredicatePolarity::Positive, + }), + ), + binder, + ), ))); } } @@ -738,13 +812,18 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } &TypeBound::Lifetime(l) => { let lifetime = self.lower_lifetime(l); + let binder = + BoundVarKinds::new_from_slice(self.bound_vars.last().unwrap().as_slice()); clause = Some(Clause(Predicate::new( self.interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::TypeOutlives(OutlivesPredicate( - self_ty, lifetime, - )), - )), + Binder::bind_with_vars( + rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::TypeOutlives(OutlivesPredicate( + self_ty, lifetime, + )), + ), + binder, + ), ))); } TypeBound::Use(_) | TypeBound::Error => {} @@ -1008,7 +1087,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { rustc_type_ir::RegionKind::ReBound(BoundVarIndexKind::Bound(db), var) => { Region::new_bound( self.interner, - db.shifted_out_to_binder(DebruijnIndex::from_u32(2)), + db.shifted_out_to_binder(DebruijnIndex::from_u32(1)), var, ) } @@ -1082,8 +1161,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { Some(resolution) => match resolution { LifetimeNs::Static => Region::new_static(self.interner), LifetimeNs::LifetimeParam(id) => { - let idx = self.generics().lifetime_param_idx(id); - self.region_param(id, idx) + let (idx, is_late_bound) = self.generics().lifetime_param_idx(id); + self.region_param(id, idx, is_late_bound) } }, None => Region::error(self.interner), @@ -1165,6 +1244,7 @@ pub(crate) fn impl_trait_with_diagnostics<'db>( &impl_data.store, impl_id.into(), LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, + LifetimeLoweringMode::Bound, ); let self_ty = db.impl_self_ty(impl_id).skip_binder(); let target_trait = impl_data.target_trait.as_ref()?; @@ -1250,6 +1330,7 @@ impl ImplTraits { &data.store, def.into(), LifetimeElisionKind::Infer, + LifetimeLoweringMode::Bound, ) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); if let Some(ret_type) = data.ret_type { @@ -1278,6 +1359,7 @@ impl ImplTraits { &data.store, def.into(), LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); if let Some(type_ref) = data.ty { @@ -1368,6 +1450,7 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> StoredEarlyBinder StoredEarlyBinder( &type_alias_data.store, t.into(), LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); let res = StoredEarlyBinder::bind( @@ -1538,6 +1623,7 @@ pub(crate) fn impl_self_ty_with_diagnostics<'db>( &impl_data.store, impl_id.into(), LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, + LifetimeLoweringMode::Bound, ); let ty = ctx.lower_ty(impl_data.self_ty); assert!(!ty.has_escaping_bound_vars()); @@ -1587,6 +1673,7 @@ pub(crate) fn const_param_ty_with_diagnostics<'db>( store, def.parent(), LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ); let ty = match data { TypeOrConstParamData::TypeParamData(_) => { @@ -1640,6 +1727,7 @@ pub(crate) fn field_types_with_diagnostics_query( &var_data.store, def, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ); for (field_id, field_data) in var_data.fields().iter() { res.insert(field_id, StoredEarlyBinder::bind(ctx.lower_ty(field_data.type_ref).store())); @@ -1768,6 +1856,7 @@ fn resolve_type_param_assoc_type_shorthand( generics.store(), def, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ); let interner = ctx.interner; let param_ty = Ty::new_param(interner, param, generics.type_or_const_param_idx(param.into())); @@ -1952,6 +2041,7 @@ fn type_alias_bounds_with_diagnostics<'db>( &type_alias_data.store, type_alias.into(), LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ); let interner = ctx.interner; let def_id = type_alias.into(); @@ -2181,6 +2271,7 @@ fn generic_predicates(db: &dyn HirDatabase, def: GenericDefId) -> (GenericPredic generics.store(), def, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ); let sized_trait = ctx.lang_items.Sized; @@ -2382,6 +2473,7 @@ pub(crate) fn generic_defaults_with_diagnostics_query( store_for_self, def, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ) .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed); let mut has_any_default = false; @@ -2474,6 +2566,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> StoredEarlyBinder StoredEarlyBinder StoredEarlyBinder StoredEarlyBinder { @@ -2560,6 +2657,7 @@ pub(crate) fn associated_ty_item_bounds<'db>( &type_alias_data.store, type_alias.into(), LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ); // FIXME: we should never create non-existential predicates in the first place // For now, use an error type so we don't run into dummy binder issues diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs index 2a23e07a037a..4fe8046559f0 100644 --- a/crates/hir-ty/src/lower/path.rs +++ b/crates/hir-ty/src/lower/path.rs @@ -34,8 +34,8 @@ use crate::{ PathDiagnosticCallbackData, }, next_solver::{ - Binder, Clause, Const, DbInterner, EarlyBinder, ErrorGuaranteed, GenericArg, GenericArgs, - Predicate, ProjectionPredicate, Region, TraitRef, Ty, + Binder, BoundVarKinds, Clause, Const, DbInterner, EarlyBinder, ErrorGuaranteed, GenericArg, + GenericArgs, Predicate, ProjectionPredicate, Region, TraitRef, Ty, }, }; @@ -919,16 +919,22 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque, ) => { let ty = this.ctx.lower_ty(type_ref); + let bound_vars = BoundVarKinds::new_from_slice( + this.ctx.bound_vars.last().unwrap().as_slice(), + ); let pred = Clause(Predicate::new( interner, - Binder::dummy(rustc_type_ir::PredicateKind::Clause( - rustc_type_ir::ClauseKind::Projection( - ProjectionPredicate { - projection_term, - term: ty.into(), - }, + Binder::bind_with_vars( + rustc_type_ir::PredicateKind::Clause( + rustc_type_ir::ClauseKind::Projection( + ProjectionPredicate { + projection_term, + term: ty.into(), + }, + ), ), - )), + bound_vars, + ), )); predicates.push((pred, GenericPredicateSource::SelfOnly)); } diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 8f8f557716d2..4a97232a7829 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -2352,8 +2352,14 @@ pub fn lower_body_to_mir<'db>( let is_root = root_expr == body.root_expr(); // Extract params and self_param only when lowering the body's root expression for a function. if is_root && let DefWithBodyId::FunctionId(fid) = owner { - let callable_sig = - db.callable_item_signature(fid.into()).instantiate_identity().skip_binder(); + let callable_sig = { + let resolver = owner.resolver(db); + let interner = DbInterner::new_with(db, resolver.krate()); + interner.liberate_late_bound_regions( + fid.into(), + db.callable_item_signature(fid.into()).instantiate_identity(), + ) + }; let mut param_tys = callable_sig.inputs().iter().copied(); let self_param = body.self_param.and_then(|id| Some((id, param_tys.next()?))); diff --git a/crates/hir-ty/src/next_solver/fold.rs b/crates/hir-ty/src/next_solver/fold.rs index af823aa005d0..7db7b447279c 100644 --- a/crates/hir-ty/src/next_solver/fold.rs +++ b/crates/hir-ty/src/next_solver/fold.rs @@ -8,7 +8,8 @@ use rustc_type_ir::{ use crate::next_solver::{BoundConst, FxIndexMap}; use super::{ - Binder, BoundRegion, BoundTy, Const, ConstKind, DbInterner, Predicate, Region, Ty, TyKind, + Binder, BoundRegion, BoundTy, Const, ConstKind, DbInterner, Predicate, Region, SolverDefId, Ty, + TyKind, }; /// A delegate used when instantiating bound vars. @@ -219,4 +220,19 @@ impl<'db> DbInterner<'db> { { self.instantiate_bound_regions(value, |_| Region::new_erased(self)).0 } + + /// Replaces any late-bound regions bound in `value` with + /// free variants attached to `all_outlive_scope`. + pub fn liberate_late_bound_regions( + self, + all_outlive_scope: SolverDefId, + value: Binder<'db, T>, + ) -> T + where + T: TypeFoldable>, + { + self.instantiate_bound_regions_uncached(value, |br| { + Region::new_late_param(self, all_outlive_scope, br.kind) + }) + } } diff --git a/crates/hir-ty/src/next_solver/region.rs b/crates/hir-ty/src/next_solver/region.rs index 7acbcbf4aafa..133534b6795b 100644 --- a/crates/hir-ty/src/next_solver/region.rs +++ b/crates/hir-ty/src/next_solver/region.rs @@ -74,6 +74,15 @@ impl<'db> Region<'db> { Region::new(interner, RegionKind::ReBound(BoundVarIndexKind::Bound(index), bound)) } + pub fn new_late_param( + interner: DbInterner<'db>, + scope: SolverDefId, + bound_region: BoundRegionKind<'db>, + ) -> Region<'db> { + let late_bound_region = LateParamRegion { scope, bound_region }; + Region::new(interner, RegionKind::ReLateParam(late_bound_region)) + } + pub fn is_placeholder(&self) -> bool { matches!(self.inner(), RegionKind::RePlaceholder(..)) } diff --git a/crates/hir-ty/src/tests/display_source_code.rs b/crates/hir-ty/src/tests/display_source_code.rs index 37da7fc87563..5a4a6562ad3e 100644 --- a/crates/hir-ty/src/tests/display_source_code.rs +++ b/crates/hir-ty/src/tests/display_source_code.rs @@ -69,7 +69,7 @@ fn test<'a>( _: &(dyn A + Send), //^ &(dyn A + Send + 'static) _: &'a (dyn Send + A), - //^ &'a (dyn A + Send + 'static) + //^ &(dyn A + Send + 'static) _: &dyn B, //^ &(dyn B + 'static) ) {} diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index fbe7c3bd37a4..ebe7cc52065e 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -3253,10 +3253,10 @@ fn main() { "#, expect![[r#" 104..108 'self': &'? Box - 188..192 'self': &'a Box> - 218..220 '{}': &'a T - 242..246 'self': &'a Box> - 275..277 '{}': &'a Foo + 188..192 'self': &' Box> + 218..220 '{}': &' T + 242..246 'self': &' Box> + 275..277 '{}': &' Foo 297..301 'self': Box> 322..324 '{}': Foo 338..559 '{ ...r(); }': () @@ -3270,7 +3270,7 @@ fn main() { 389..394 'boxed': Box> 389..406 'boxed....nner()': &'? i32 416..421 'good1': &'? i32 - 424..438 'Foo::get_inner': fn get_inner(&'? Box>) -> &'? i32 + 424..438 'Foo::get_inner': fn get_inner(&'?0.0 Box>) -> &'?0.0 i32 424..446 'Foo::g...boxed)': &'? i32 439..445 '&boxed': &'? Box> 440..445 'boxed': Box> @@ -3278,7 +3278,7 @@ fn main() { 464..469 'boxed': Box> 464..480 'boxed....self()': &'? Foo 490..495 'good2': &'? Foo - 498..511 'Foo::get_self': fn get_self(&'? Box>) -> &'? Foo + 498..511 'Foo::get_self': fn get_self(&'?0.0 Box>) -> &'?0.0 Foo 498..519 'Foo::g...boxed)': &'? Foo 512..518 '&boxed': &'? Box> 513..518 'boxed': Box> diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 18e4a5b41d1c..66b70c30906e 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -1635,10 +1635,10 @@ fn test<'lifetime>( ) {} "#, expect![[r#" - 39..40 'a': impl Trait + 'lifetime - 70..71 'b': impl 'lifetime + 39..40 'a': impl Trait + '?0.0 + 70..71 'b': impl '?0.0 93..94 'c': impl Trait - 114..115 'd': impl 'lifetime + 114..115 'd': impl '?0.0 139..140 'e': impl ?Sized 159..160 'f': impl Trait + ?Sized 184..186 '{}': () @@ -4323,9 +4323,9 @@ fn f<'a>(v: &dyn Trait = &'a i32>) { "#, expect![[r#" 90..94 'self': &'? Self - 127..128 'v': &'? (dyn Trait = &'a i32> + 'static) + 127..128 'v': &'? (dyn Trait = &' i32> + 'static) 164..195 '{ ...f(); }': () - 170..171 'v': &'? (dyn Trait = &'a i32> + 'static) + 170..171 'v': &'? (dyn Trait = &' i32> + 'static) 170..184 'v.get::()': <{unknown} as Trait>::Assoc 170..192 'v.get:...eref()': {unknown} "#]], @@ -4881,7 +4881,7 @@ fn allowed3(baz: impl Baz>) {} 431..433 '{}': () 447..450 'baz': impl Baz 480..482 '{}': () - 500..503 'baz': impl Baz + 500..503 'baz': impl Baz 544..546 '{}': () 560..563 'baz': impl Baz> 598..600 '{}': () diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 7ab9bca697b3..a7c370040123 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1927,7 +1927,7 @@ impl Adt { resolver .generic_params() .and_then(|gp| { - gp.iter_lt() + gp.iter_early_bound_lt() // there should only be a single lifetime // but `Arena` requires to use an iterator .nth(0) diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 783faa9ac86f..5e838a9dd949 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -29,7 +29,8 @@ use hir_expand::{ name::{AsName, Name}, }; use hir_ty::{ - Adjustment, InferenceResult, LifetimeElisionKind, ParamEnvAndCrate, TyLoweringContext, + Adjustment, InferenceResult, LifetimeElisionKind, LifetimeLoweringMode, ParamEnvAndCrate, + TyLoweringContext, diagnostics::{ InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields, unsafe_operations, @@ -348,6 +349,7 @@ impl<'db> SourceAnalyzer<'db> { // (this can impact the lifetimes generated, e.g. in `const` they won't be `'static`, but this seems like a // small problem). LifetimeElisionKind::Infer, + LifetimeLoweringMode::LateParam, ) .lower_ty(type_ref); @@ -1725,9 +1727,15 @@ fn resolve_hir_path_( let types = || { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => resolver.generic_def().and_then(|def| { - let (_, res) = - TyLoweringContext::new(db, resolver, store?, def, LifetimeElisionKind::Infer) - .lower_ty_ext(type_ref); + let (_, res) = TyLoweringContext::new( + db, + resolver, + store?, + def, + LifetimeElisionKind::Infer, + LifetimeLoweringMode::LateParam, + ) + .lower_ty_ext(type_ref); res.map(|ty_ns| (ty_ns, path.segments().first())) }), None => { @@ -1874,9 +1882,15 @@ fn resolve_hir_path_qualifier( (|| { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => resolver.generic_def().and_then(|def| { - let (_, res) = - TyLoweringContext::new(db, resolver, store, def, LifetimeElisionKind::Infer) - .lower_ty_ext(type_ref); + let (_, res) = TyLoweringContext::new( + db, + resolver, + store, + def, + LifetimeElisionKind::Infer, + LifetimeLoweringMode::LateParam, + ) + .lower_ty_ext(type_ref); res.map(|ty_ns| (ty_ns, path.segments().first())) }), None => { diff --git a/crates/ide-assists/src/handlers/extract_type_alias.rs b/crates/ide-assists/src/handlers/extract_type_alias.rs index ecb031e42d7e..cb7e908864ea 100644 --- a/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -358,6 +358,7 @@ mod m { ); } + // FIXME: This assists lost some information with early and late boud and this should be fixed(?) #[test] fn generics() { check_assist( @@ -370,7 +371,7 @@ impl<'outer, Outer, const OUTER: usize> () { "#, r#" struct Struct; -type $0Type<'inner, 'outer, Outer, Inner, const INNER: usize, const OUTER: usize> = &(Struct, Struct, Outer, &'inner (), Inner, &'outer ()); +type $0Type<'inner, 'outer, Outer, Inner, const INNER: usize, const OUTER: usize> = &(Struct, Struct, Outer, &(), Inner, &'outer ()); impl<'outer, Outer, const OUTER: usize> () { fn func<'inner, Inner, const INNER: usize>(_: Type<'inner, 'outer, Outer, Inner, INNER, OUTER>) {} diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs index 55059a4035e7..af896d189205 100644 --- a/crates/ide-completion/src/tests/special.rs +++ b/crates/ide-completion/src/tests/special.rs @@ -1573,6 +1573,7 @@ fn check_signatures(src: &str, kind: CompletionItemKind, reduced: Expect, full: full.assert_eq(completion[0].detail.as_ref().unwrap()); } +// FIXME: This assists lost some information with early and late boud and this should be fixed(?) #[test] fn respects_full_function_signatures() { check_signatures( @@ -1581,7 +1582,7 @@ pub fn foo<'x, T>(x: &'x mut T) -> u8 where T: Clone, { 0u8 } fn main() { fo$0 } "#, CompletionItemKind::SymbolKind(ide_db::SymbolKind::Function), - expect!("fn(&'x mut T) -> u8"), + expect!("fn(&mut T) -> u8"), expect!("pub fn foo<'x, T>(x: &'x mut T) -> u8 where T: Clone,"), ); @@ -1614,7 +1615,7 @@ fn main() { } "#, CompletionItemKind::SymbolKind(SymbolKind::Method), - expect!("const fn(&'foo mut self, &'foo Foo) -> !"), + expect!("const fn(&'foo mut self, &Foo) -> !"), expect!("pub const fn baz<'foo>(&'foo mut self, x: &'foo Foo) -> !"), ); } diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs index 57b723cbd872..9228532823c8 100644 --- a/crates/ide/src/inlay_hints/bind_pat.rs +++ b/crates/ide/src/inlay_hints/bind_pat.rs @@ -433,7 +433,7 @@ fn f<'a>() { let y = S::<'_>(loop {}); //^ S<'_> let z = S::<'a>(loop {}); - //^ S<'a> + //^ S<'> } "#, @@ -1446,22 +1446,7 @@ fn f<'a>() { ), tooltip: "", }, - "<", - InlayHintLabelPart { - text: "'a", - linked_location: Some( - Computed( - FileRangeWrapper { - file_id: FileId( - 0, - ), - range: 35..37, - }, - ), - ), - tooltip: "", - }, - ">", + "<'>", ], ), ]