diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 76503ac97c1a..0749f5cc2ec6 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -13,7 +13,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, @@ -35,8 +35,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::{ @@ -58,6 +58,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, @@ -326,61 +327,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) = @@ -439,6 +446,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`. @@ -545,6 +553,50 @@ 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, + opaque_captured_lifetimes: FxIndexSet, +} + +#[derive(Debug)] +enum LifetimeBoundScope { + Argument, + Return, + WhereClause, + ImplTrait(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_constraint_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.opaque_captured_lifetimes.insert(lifetime.clone()); + self.lifetimes_in_output.insert(lifetime); + } + } + _ => (), + }; + } +} + impl<'db> ExprCollector<'db> { pub fn new( db: &dyn DefDatabase, @@ -572,6 +624,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 @@ -710,8 +763,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_lt_bound_scope = this.is_argument_lt_bound_scope(); + let type_bounds = this.with_lifetime_bound_scope( + LifetimeBoundScope::ImplTrait(is_argument_lt_bound_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) }); } @@ -774,6 +835,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); @@ -3220,6 +3285,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::new(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 7ef9c80de1ae..a047424d8748 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()); @@ -133,13 +140,19 @@ 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, + is_opaque_captured: false, + }; 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), + ) + }); } } } @@ -221,6 +234,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); } @@ -269,4 +285,28 @@ 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.opaque_captured_lifetimes.contains(lifetime_name) { + lifetime.is_opaque_captured = true; + } + + 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 236255c404f8..6b09583d65dc 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 04ccc7bf90cf..b2de6e3ea59c 100644 --- a/crates/hir-def/src/hir/generics.rs +++ b/crates/hir-def/src/hir/generics.rs @@ -33,6 +33,20 @@ pub struct TypeParamData { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct LifetimeParamData { pub name: Name, + pub bound_type: LifetimeBoundType, + pub is_opaque_captured: bool, +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum LifetimeBoundType { + EarlyBound, + LateBound, +} + +impl LifetimeParamData { + pub fn is_late_bound(&self) -> bool { + self.bound_type == LifetimeBoundType::LateBound + } } /// Data about a generic const parameter (to a function, struct, impl, ...). @@ -293,7 +307,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] @@ -332,6 +351,20 @@ impl GenericParams { self.lifetimes.iter() } + #[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 { self.type_or_consts.iter().find_map(|(id, p)| { if p.name().as_ref() == Some(&name) && p.type_param().is_some() { @@ -376,4 +409,22 @@ 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 + }) + } + + pub fn early_bound_lifetime_idx( + &self, + lifetime_param_id: &LocalLifetimeParamId, + ) -> Option { + self.iter_early_bound_lt().position(|(id, data)| { + data.bound_type == LifetimeBoundType::EarlyBound && id == *lifetime_param_id + }) + } } diff --git a/crates/hir-ty/src/builtin_derive.rs b/crates/hir-ty/src/builtin_derive.rs index 928e3da6e8c9..a3d40a94611f 100644 --- a/crates/hir-ty/src/builtin_derive.rs +++ b/crates/hir-ty/src/builtin_derive.rs @@ -69,14 +69,16 @@ pub(crate) fn generics_of<'db>( | BuiltinDeriveImplTrait::Ord | BuiltinDeriveImplTrait::PartialOrd | BuiltinDeriveImplTrait::Eq - | BuiltinDeriveImplTrait::PartialEq => Generics::from_generic_def(db, loc.adt.into()), + | BuiltinDeriveImplTrait::PartialEq => { + Generics::from_generic_def(db, loc.adt.into(), false) + } BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => { let trait_id = loc .trait_ .get_id(interner.lang_items()) .expect("we don't pass the impl to the solver if we can't resolve the trait"); - let additional_param = coerce_pointee_new_type_param(trait_id).into(); - Generics::from_generic_def_plus_one(db, loc.adt.into(), additional_param) + let additional_param = coerce_pointee_new_type_param(trait_id); + Generics::from_generic_def_plus_one(db, loc.adt.into(), additional_param, false) } } } diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 0acf6e63d782..8cf805dbeb90 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -2301,10 +2301,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"), @@ -2316,8 +2316,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 34858212cb3e..10ca283b5c54 100644 --- a/crates/hir-ty/src/dyn_compatibility.rs +++ b/crates/hir-ty/src/dyn_compatibility.rs @@ -395,7 +395,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>>>, @@ -417,9 +417,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 c4321e8a61de..46e5a7c93df7 100644 --- a/crates/hir-ty/src/generics.rs +++ b/crates/hir-ty/src/generics.rs @@ -79,10 +79,20 @@ 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)) } + fn iter_late_bound_lifetimes( + &self, + consider_late_bound: bool, + ) -> impl Iterator { + let parent = self.def; + self.params.iter_late_bound_lt().filter_map(move |(local_id, data)| { + consider_late_bound.then_some((LifetimeParamId { parent, local_id }, data)) + }) + } + pub(crate) fn iter_type_or_consts( &self, ) -> impl Iterator { @@ -118,23 +128,58 @@ impl<'db> SingleGenerics<'db> { (trait_self, iter) } - pub(crate) fn iter(&self) -> impl Iterator)> { - let lifetimes = self.iter_lifetimes().map(|(id, data)| { + pub(crate) fn iter( + &self, + consider_late_bound: bool, + ) -> impl Iterator)> { + let lifetime_map = |(id, data)| { (GenericParamId::LifetimeParamId(id), GenericParamDataRef::LifetimeParamData(data)) - }); + }; + let lifetimes = self.iter_lifetimes().map(lifetime_map); + let late_bound_lifetimes = + self.iter_late_bound_lifetimes(consider_late_bound).map(lifetime_map); + let (trait_self, type_and_consts) = self.trait_self_and_others(); - trait_self.into_iter().chain(lifetimes).chain(type_and_consts) + trait_self.into_iter().chain(lifetimes).chain(type_and_consts).chain(late_bound_lifetimes) } pub(crate) fn iter_with_idx( &self, ) -> impl Iterator)> { - std::iter::zip(self.preceding_params_len.., self.iter()) + std::iter::zip(self.preceding_params_len.., self.iter(false)) .map(|(index, (id, data))| (index, id, data)) } - pub(crate) fn iter_id(&self) -> impl Iterator { - self.iter().map(|(id, _)| id) + pub(crate) fn iter_id( + &self, + consider_late_bound: bool, + ) -> impl Iterator { + self.iter(consider_late_bound).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), + ) + }) + } + + pub(crate) fn type_or_const_param(&self, param_id: TypeParamId) -> GenericParamDataRef<'db> { + let data = &self.params[param_id.local_id()]; + match data { + TypeOrConstParamData::TypeParamData(type_param_data) => { + GenericParamDataRef::TypeParamData(type_param_data) + } + TypeOrConstParamData::ConstParamData(const_param_data) => { + GenericParamDataRef::ConstParamData(const_param_data) + } + } } } @@ -169,7 +214,7 @@ impl<'db> Generics<'db> { pub(crate) fn iter_self( &self, ) -> impl Iterator)> { - self.owner().iter() + self.owner().iter(false) } pub(crate) fn iter_self_with_idx( @@ -178,8 +223,14 @@ 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()) + self.parent().into_iter().flat_map(move |parent| parent.iter_id(false)) } pub(crate) fn iter_self_type_or_consts( @@ -189,13 +240,18 @@ impl<'db> Generics<'db> { } /// Iterate over the parent params followed by self params. - #[cfg(test)] - pub(crate) fn iter(&self) -> impl Iterator)> { - self.iter_owners().flat_map(|owner| owner.iter()) + pub(crate) fn iter( + &self, + consider_late_bound: bool, + ) -> impl Iterator)> { + self.iter_owners().flat_map(move |owner| owner.iter(consider_late_bound)) } - pub(crate) fn iter_id(&self) -> impl Iterator { - self.iter_owners().flat_map(|owner| owner.iter_id()) + pub(crate) fn iter_id( + &self, + consider_late_bound: bool, + ) -> impl Iterator { + self.iter_owners().flat_map(move |owner| owner.iter_id(consider_late_bound)) } /// Returns total number of generic parameters in scope, including those from parent. @@ -275,12 +331,28 @@ 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, + is_lowering_impl_trait_bounds: bool, + ) -> (u32, bool) { let owner = self.find_owner(param.parent); + if is_lowering_impl_trait_bounds { + let idx = self.opaque_lifetime_idx(param); + return (owner.preceding_params_len + (idx as u32), false); + } + + 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() + match owner.params.early_bound_lifetime_idx(¶m.local_id) { + Some(idx) => { + (owner.preceding_params_len + u32::from(has_trait_self) + (idx as u32), false) + } + _ => unreachable!(), + } } #[deprecated = "don't use this; it's easy to expose an erroneous `Generics` with this"] @@ -294,6 +366,22 @@ impl<'db> Generics<'db> { }); Generics { chain } } + + pub(crate) fn type_or_const_param(&self, param_id: TypeParamId) -> GenericParamDataRef<'db> { + self.find_owner(param_id.parent()).type_or_const_param(param_id) + } + + fn opaque_lifetime_idx(&self, param: LifetimeParamId) -> usize { + self.find_owner(param.parent) + .iter_id(true) + .position(|id| { + let GenericParamId::LifetimeParamId(id) = id else { + return false; + }; + param == id + }) + .unwrap() + } } pub(crate) struct ProvenanceSplit { diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 3f90a78cc24f..d42b43de8ee5 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -91,7 +91,8 @@ use crate::{ unify::resolve_completely::WriteBackCtxt, }, lower::{ - ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, diagnostics::TyLoweringDiagnostic, + ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, LifetimeLoweringMode, + diagnostics::TyLoweringDiagnostic, }, method_resolution::CandidateId, next_solver::{ @@ -1869,6 +1870,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.allow_using_generic_params, infer_vars, &self.defined_anon_consts, + LifetimeLoweringMode::LateParam, ); f(&mut ctx) } @@ -2202,6 +2204,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.allow_using_generic_params, Some(&mut vars_ctx), &self.defined_anon_consts, + LifetimeLoweringMode::LateParam, ); if let Some(type_anchor) = path.type_anchor() { diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index ab111736d56a..2a5567dfae54 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -304,7 +304,7 @@ impl<'db> InferenceContext<'_, 'db> { }; // Now go through the argument patterns - for (arg_pat, arg_ty) in args.iter().zip(bound_sig.skip_binder().inputs()) { + for (arg_pat, arg_ty) in args.iter().zip(liberated_sig.inputs()) { self.infer_top_pat(*arg_pat, *arg_ty, PatOrigin::Param); } @@ -1148,8 +1148,9 @@ impl<'db> InferenceContext<'_, 'db> { } fn closure_sigs(&self, bound_sig: PolyFnSig<'db>) -> ClosureSignatures<'db> { - let liberated_sig = bound_sig.skip_binder(); - // FIXME: When we lower HRTB we'll need to actually liberate regions here. + // TODO: def id needs to be changed? + let liberated_sig = + self.interner().liberate_late_bound_regions(self.owner.into(), bound_sig); ClosureSignatures { bound_sig, liberated_sig } } } diff --git a/crates/hir-ty/src/infer/diagnostics.rs b/crates/hir-ty/src/infer/diagnostics.rs index dd0efea4d754..e871edd265c1 100644 --- a/crates/hir-ty/src/infer/diagnostics.rs +++ b/crates/hir-ty/src/infer/diagnostics.rs @@ -14,6 +14,7 @@ use la_arena::{Idx, RawIdx}; use rustc_hash::FxHashMap; use thin_vec::ThinVec; +use crate::lower::LifetimeLoweringMode; use crate::{ InferenceDiagnostic, InferenceTyDiagnosticSource, Span, TyLoweringDiagnostic, db::{AnonConstId, HirDatabase}, @@ -107,6 +108,7 @@ impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { allow_using_generic_params: bool, infer_vars: Option<&'a mut dyn TyLoweringInferVarsCtx<'db>>, defined_anon_consts: &'a RefCell>, + lifetime_lowering_mode: LifetimeLoweringMode, ) -> Self { let mut ctx = TyLoweringContext::new( db, @@ -116,6 +118,7 @@ impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { generic_def, generics, lifetime_elision, + lifetime_lowering_mode, ) .with_infer_vars_behavior(infer_vars); if !allow_using_generic_params { diff --git a/crates/hir-ty/src/infer/op.rs b/crates/hir-ty/src/infer/op.rs index 9119af9628eb..e18e1528c4db 100644 --- a/crates/hir-ty/src/infer/op.rs +++ b/crates/hir-ty/src/infer/op.rs @@ -333,7 +333,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { let args = GenericArgs::for_item( self.interner(), trait_did.into(), - |param_idx, param_id, _| match param_id { + |param_idx, (param_id, _), _| match param_id { GenericParamId::LifetimeParamId(_) | GenericParamId::ConstParamId(_) => { unreachable!("did not expect operand trait to have lifetime/const args") } diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index 704f15cc86cc..b1120a4f5e43 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -15,7 +15,7 @@ use crate::{ infer::{ InferenceTyLoweringVarsCtx, diagnostics::InferenceTyLoweringContext as TyLoweringContext, }, - lower::{GenericPredicates, LifetimeElisionKind}, + lower::{GenericPredicates, LifetimeElisionKind, LifetimeLoweringMode}, method_resolution::{self, CandidateId, MethodError}, next_solver::{ GenericArg, GenericArgs, TraitRef, Ty, Unnormalized, infer::traits::ObligationCause, @@ -158,6 +158,7 @@ impl<'db> InferenceContext<'_, 'db> { self.allow_using_generic_params, Some(&mut vars_ctx), &self.defined_anon_consts, + 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 91e3b85aa131..6a8f2bc51d1e 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -110,8 +110,8 @@ pub use infer::{ }; pub use lower::{ GenericDefaults, GenericDefaultsRef, GenericPredicates, ImplTraits, LifetimeElisionKind, - TyDefId, TyLoweringContext, TyLoweringInferVarsCtx, TyLoweringResult, ValueTyDefId, - diagnostics::*, + LifetimeLoweringMode, TyDefId, TyLoweringContext, TyLoweringInferVarsCtx, TyLoweringResult, + ValueTyDefId, diagnostics::*, }; pub use next_solver::interner::{attach_db, attach_db_allow_change, with_attached_db}; pub use target_feature::TargetFeatures; @@ -220,7 +220,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, false).0 } #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index ec42b8a3493b..88920d6229e2 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -44,7 +44,8 @@ use rustc_abi::ExternAbi; use rustc_ast_ir::Mutability; use rustc_hash::FxHashSet; use rustc_type_ir::{ - AliasTyKind, BoundVarIndexKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection, + AliasTyKind, BoundRegion, BoundRegionKind, BoundTyKind, BoundVar, BoundVarIndexKind, + BoundVariableKind, 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 _}, @@ -61,12 +62,12 @@ use crate::{ generics::{Generics, SingleGenerics, generics}, infer::unify::InferenceTable, next_solver::{ - AliasTy, Binder, BoundExistentialPredicates, Clause, ClauseKind, Clauses, Const, ConstKind, - DbInterner, DefaultAny, EarlyBinder, EarlyParamRegion, ErrorGuaranteed, FnSigKind, - FxIndexMap, GenericArg, GenericArgs, ParamConst, ParamEnv, Pattern, PolyFnSig, Predicate, - Region, StoredClauses, StoredEarlyBinder, StoredGenericArg, StoredGenericArgs, + AliasTy, Binder, BoundExistentialPredicates, BoundVarKinds, Clause, ClauseKind, Clauses, + Const, ConstKind, DbInterner, DefaultAny, EarlyBinder, EarlyParamRegion, ErrorGuaranteed, + FnSigKind, FxIndexMap, GenericArg, GenericArgs, ParamConst, ParamEnv, Pattern, PolyFnSig, + Predicate, Region, StoredClauses, StoredEarlyBinder, StoredGenericArg, StoredGenericArgs, StoredPolyFnSig, StoredTraitRef, StoredTy, TraitPredicate, TraitRef, Ty, Tys, Unnormalized, - abi::Safety, util::BottomUpFolder, + abi::Safety, mk_param, util::BottomUpFolder, }, }; @@ -219,6 +220,9 @@ pub struct TyLoweringContext<'db, 'a> { forbid_params_after_reason: ForbidParamsAfterReason, pub(crate) defined_anon_consts: ThinVec, infer_vars: Option<&'a mut dyn TyLoweringInferVarsCtx<'db>>, + is_lowering_impl_trait_bounds: bool, + bound_vars: Vec>, // FIXME: HRTB and other for lifetime doesn't change it now + lifetime_lowering_mode: LifetimeLoweringMode, } impl<'db, 'a> TyLoweringContext<'db, 'a> { @@ -230,10 +234,12 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { generic_def: GenericDefId, generics: &'a OnceCell>, 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, generic_def)]); Self { db, // Can provide no block since we don't use it for trait solving. @@ -254,6 +260,9 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { forbid_params_after_reason: ForbidParamsAfterReason::AnonConst, defined_anon_consts: ThinVec::new(), infer_vars: None, + is_lowering_impl_trait_bounds: false, + bound_vars, + lifetime_lowering_mode, } } @@ -340,6 +349,27 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } } + + 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)] @@ -354,6 +384,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 @@ -425,12 +465,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. self.types.regions.error } 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 }) + } } } @@ -522,8 +587,42 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { }); self.impl_trait_mode.opaque_type_data[idx] = actual_opaque_type_data; - let args = - GenericArgs::identity_for_item(self.interner, opaque_ty_id.into()); + let mut late_bound_index = 0; + let args = GenericArgs::for_item( + self.interner, + opaque_ty_id.into(), + |index, param @ (id, data), _| { + if let GenericParamDataRef::LifetimeParamData(lt) = data + && lt.is_late_bound() + && !self.is_lowering_impl_trait_bounds + { + let GenericParamId::LifetimeParamId(id) = id else { + unreachable!() + }; + let bound_region_kind = + BoundRegionKind::Named(id.parent.into()); + let region = match self.lifetime_lowering_mode { + LifetimeLoweringMode::Bound => Region::new_bound( + interner, + self.in_binders, + BoundRegion { + var: BoundVar::from_u32(late_bound_index), + kind: bound_region_kind, + }, + ), + LifetimeLoweringMode::LateParam => Region::new_late_param( + interner, + self.generic_def.into(), + bound_region_kind, + ), + }; + late_bound_index += 1; + return region.into(); + } + + mk_param(interner, index - late_bound_index, param) + }, + ); Ty::new_alias( self.interner, AliasTy::new_from_args( @@ -575,16 +674,21 @@ 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 { - fn_sig_kind: FnSigKind::new( - fn_.abi, - if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe }, - fn_.is_varargs, - ), - inputs_and_output: Tys::new_from_slice(&args), - }), + Binder::bind_with_vars( + FnSig { + fn_sig_kind: FnSigKind::new( + fn_.abi, + if fn_.is_unsafe { Safety::Unsafe } else { Safety::Safe }, + fn_.is_varargs, + ), + inputs_and_output: Tys::new_from_slice(&args), + }, + binder, + ), ) } @@ -728,6 +832,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 @@ -746,12 +852,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, + ), ))); } } @@ -770,13 +879,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 => {} @@ -1043,7 +1157,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, ) } @@ -1067,6 +1181,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { self.interner, AliasTy::new_from_args(interner, rustc_type_ir::Opaque { def_id: def_id.into() }, args), ); + let prev_is_lowering_impl_trait_bounds = + mem::replace(&mut self.is_lowering_impl_trait_bounds, true); let (predicates, assoc_ty_bounds_start) = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| { let mut predicates = Vec::new(); @@ -1088,14 +1204,18 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { trait_id.into(), GenericArgs::new_from_slice(&[self_ty.into()]), ); + let binder = BoundVarKinds::new_from_slice(ctx.bound_vars.last().unwrap()); 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, + ), )) }); predicates.extend(sized_clause); @@ -1106,6 +1226,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { (predicates, assoc_ty_bounds_start) }); + self.is_lowering_impl_trait_bounds = prev_is_lowering_impl_trait_bounds; ImplTrait { predicates: Clauses::new_from_slice(&predicates).store(), assoc_ty_bounds_start, @@ -1117,8 +1238,9 @@ 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.is_lowering_impl_trait_bounds); + self.region_param(id, idx, is_late_bound) } }, None => Region::error(self.interner), @@ -1236,6 +1358,7 @@ pub(crate) fn impl_trait_with_diagnostics( impl_id.into(), &generics, 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()?; @@ -1320,6 +1443,7 @@ impl ImplTraits { def.into(), &generics, LifetimeElisionKind::Infer, + LifetimeLoweringMode::Bound, ) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); if let Some(ret_type) = data.ret_type { @@ -1351,6 +1475,7 @@ impl ImplTraits { def.into(), &generics, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); if let Some(type_ref) = data.ty { @@ -1452,6 +1577,7 @@ pub(crate) fn type_for_const_with_diagnostics( def.into(), &generics, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ); ctx.set_lifetime_elision(LifetimeElisionKind::for_const(ctx.interner, parent)); let result = StoredEarlyBinder::bind(ctx.lower_ty(data.type_ref).store()); @@ -1482,6 +1608,7 @@ pub(crate) fn type_for_static_with_diagnostics( def.into(), &generics, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ); ctx.set_lifetime_elision(LifetimeElisionKind::Elided(Region::new_static(ctx.interner))); let result = StoredEarlyBinder::bind(ctx.lower_ty(data.type_ref).store()); @@ -1564,6 +1691,7 @@ pub(crate) fn type_for_type_alias_with_diagnostics( t.into(), &generics, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); let res = StoredEarlyBinder::bind( @@ -1610,6 +1738,7 @@ pub(crate) fn impl_self_ty_with_diagnostics( impl_id.into(), &generics, LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, + LifetimeLoweringMode::Bound, ); let ty = ctx.lower_ty(impl_data.self_ty); assert!(!ty.has_escaping_bound_vars()); @@ -1658,6 +1787,7 @@ pub(crate) fn const_param_types_with_diagnostics( def, &generics, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ); ctx.forbid_params_after(0, ForbidParamsAfterReason::ConstParamTy); for (local_id, param_data) in data.iter_type_or_consts() { @@ -1711,6 +1841,7 @@ pub(crate) fn field_types_with_diagnostics( generic_def, &generics, 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())); @@ -1843,6 +1974,7 @@ fn resolve_type_param_assoc_type_shorthand( def, generics, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ); let interner = ctx.interner; let generics = generics.get().unwrap(); @@ -2023,6 +2155,7 @@ pub(crate) fn type_alias_bounds_with_diagnostics( type_alias.into(), &generics, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ); let interner = ctx.interner; @@ -2266,6 +2399,7 @@ fn generic_predicates( def, generics, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ); let generics = generics.get().unwrap(); let sized_trait = ctx.lang_items.Sized; @@ -2483,6 +2617,7 @@ pub(crate) fn generic_defaults_with_diagnostics( def, generics, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ) .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed); let generics = generics.get().unwrap(); @@ -2572,6 +2707,7 @@ fn fn_sig_for_fn( def.into(), &generics, LifetimeElisionKind::for_fn_params(data), + LifetimeLoweringMode::Bound, ); let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr)); @@ -2583,6 +2719,7 @@ fn fn_sig_for_fn( def.into(), &generics, LifetimeElisionKind::for_fn_ret(interner), + LifetimeLoweringMode::Bound, ) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); let ret = match data.ret_type { @@ -2591,19 +2728,21 @@ fn fn_sig_for_fn( }; let inputs_and_output = Tys::new_from_iter(interner, params.chain(Some(ret))); - ctx_params.diagnostics.extend(ctx_ret.diagnostics); ctx_params.defined_anon_consts.extend(ctx_ret.defined_anon_consts); - // If/when we track late bound vars, we need to switch this to not be `dummy` - let result = StoredEarlyBinder::bind(StoredPolyFnSig::new(Binder::dummy(FnSig { - inputs_and_output, - fn_sig_kind: FnSigKind::new( - data.abi, - if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe }, - data.is_varargs(), - ), - }))); + let binder = BoundVarKinds::new_from_slice(ctx_params.bound_vars.last().unwrap().as_slice()); + let result = StoredEarlyBinder::bind(StoredPolyFnSig::new(Binder::bind_with_vars( + FnSig { + inputs_and_output, + fn_sig_kind: FnSigKind::new( + data.abi, + if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe }, + data.is_varargs(), + ), + }, + binder, + ))); TyLoweringResult::from_ctx(result, ctx_params) } @@ -2664,6 +2803,7 @@ pub(crate) fn associated_ty_item_bounds<'db>( type_alias.into(), &generics, 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 663321567987..f514e6b954c4 100644 --- a/crates/hir-ty/src/lower/path.rs +++ b/crates/hir-ty/src/lower/path.rs @@ -34,8 +34,9 @@ use crate::{ LifetimeElisionKind, PathDiagnosticCallbackData, const_param_ty, }, next_solver::{ - AliasTermKind, Binder, Clause, Const, DbInterner, EarlyBinder, ErrorGuaranteed, GenericArg, - GenericArgs, Predicate, ProjectionPredicate, Region, TraitRef, Ty, + AliasTermKind, Binder, BoundVarKinds, Clause, Const, DbInterner, EarlyBinder, + ErrorGuaranteed, GenericArg, GenericArgs, Predicate, ProjectionPredicate, Region, TraitRef, + Ty, }, }; @@ -956,16 +957,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/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 9e0188fd2604..73f2ed02b2ee 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -233,7 +233,7 @@ impl<'db> InferenceTable<'db> { let args = GenericArgs::for_item( self.interner(), trait_def_id.into(), - |param_idx, param_id, _| match param_id { + |param_idx, (param_id, _), _| match param_id { GenericParamId::LifetimeParamId(_) | GenericParamId::ConstParamId(_) => { unreachable!("did not expect operator trait to have lifetime/const") } diff --git a/crates/hir-ty/src/method_resolution/probe.rs b/crates/hir-ty/src/method_resolution/probe.rs index 4b2f0cfd7066..f27db8d58039 100644 --- a/crates/hir-ty/src/method_resolution/probe.rs +++ b/crates/hir-ty/src/method_resolution/probe.rs @@ -2036,7 +2036,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> { let args = GenericArgs::for_item( self.interner(), method.into(), - |param_index, param_id, _| { + |param_index, (param_id, _), _| { let i = param_index as usize; if i < args.len() { args[i] diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 025aff9307e1..1a89f8ade722 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -2365,8 +2365,14 @@ pub fn lower_body_to_mir<'db>( ) -> Result<'db, MirBody> { // Extract params and self_param only when lowering the body's root expression for a function. if let Some(fid) = owner.as_function() { - 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().skip_norm_wip(), + ) + }; let mut param_tys = callable_sig.inputs().iter().copied(); let self_param = 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/generic_arg.rs b/crates/hir-ty/src/next_solver/generic_arg.rs index 51f070cd64e8..82bfffdf21dc 100644 --- a/crates/hir-ty/src/next_solver/generic_arg.rs +++ b/crates/hir-ty/src/next_solver/generic_arg.rs @@ -9,7 +9,7 @@ use std::{hint::unreachable_unchecked, marker::PhantomData, ptr::NonNull}; use arrayvec::ArrayVec; -use hir_def::{GenericDefId, GenericParamId}; +use hir_def::{GenericDefId, GenericParamId, hir::generics::GenericParamDataRef}; use intern::InternedRef; use rustc_type_ir::{ ClosureArgs, ConstVid, CoroutineArgs, CoroutineClosureArgs, FallibleTypeFolder, @@ -518,10 +518,14 @@ impl<'db> GenericArgs<'db> { defs: &Generics<'db>, mut mk_kind: F, ) where - F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, + F: FnMut( + u32, + (GenericParamId, GenericParamDataRef<'db>), + &[GenericArg<'db>], + ) -> GenericArg<'db>, { - defs.iter_id().enumerate().for_each(|(idx, param_id)| { - let new_arg = mk_kind(idx as u32, param_id, args.as_ref()); + defs.iter().enumerate().for_each(|(idx, param)| { + let new_arg = mk_kind(idx as u32, param, args.as_ref()); args.push(new_arg); }); } @@ -529,7 +533,11 @@ impl<'db> GenericArgs<'db> { #[cold] fn fill_vec_builder(defs: &Generics<'db>, count: usize, mk_kind: F) -> GenericArgs<'db> where - F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, + F: FnMut( + u32, + (GenericParamId, GenericParamDataRef<'db>), + &[GenericArg<'db>], + ) -> GenericArg<'db>, { let mut args = Vec::with_capacity(count); Self::fill_builder(&mut args, defs, mk_kind); @@ -547,7 +555,11 @@ impl<'db> GenericArgs<'db> { mk_kind: F, ) -> GenericArgs<'db> where - F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, + F: FnMut( + u32, + (GenericParamId, GenericParamDataRef<'db>), + &[GenericArg<'db>], + ) -> GenericArg<'db>, { let defs = interner.generics_of(def_id); let count = defs.count(); @@ -565,7 +577,9 @@ impl<'db> GenericArgs<'db> { /// Creates an all-error `GenericArgs`. pub fn error_for_item(interner: DbInterner<'db>, def_id: SolverDefId) -> GenericArgs<'db> { - GenericArgs::for_item(interner, def_id, |_, id, _| GenericArg::error_from_id(interner, id)) + GenericArgs::for_item(interner, def_id, |_, (id, _), _| { + GenericArg::error_from_id(interner, id) + }) } /// Like `for_item`, but prefers the default of a parameter if it has any. @@ -578,9 +592,11 @@ impl<'db> GenericArgs<'db> { F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, { let defaults = interner.db.generic_defaults(def_id); - Self::for_item(interner, def_id.into(), |idx, id, prev| match defaults.get(idx as usize) { - Some(default) => default.instantiate(interner, prev).skip_norm_wip(), - None => fallback(idx, id, prev), + Self::for_item(interner, def_id.into(), |idx, (id, _), prev| { + match defaults.get(idx as usize) { + Some(default) => default.instantiate(interner, prev).skip_norm_wip(), + None => fallback(idx, id, prev), + } }) } @@ -595,7 +611,7 @@ impl<'db> GenericArgs<'db> { F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, { let mut iter = first.into_iter(); - Self::for_item(interner, def_id, |idx, id, prev| { + Self::for_item(interner, def_id, |idx, (id, _), prev| { iter.next().unwrap_or_else(|| fallback(idx, id, prev)) }) } @@ -684,7 +700,7 @@ impl<'db> rustc_type_ir::inherent::GenericArgs> for GenericArgs< def_id: as rustc_type_ir::Interner>::DefId, original_args: &[ as rustc_type_ir::Interner>::GenericArg], ) -> as rustc_type_ir::Interner>::GenericArgs { - Self::for_item(interner, def_id, |index, kind, _| { + Self::for_item(interner, def_id, |index, (kind, _), _| { if let Some(arg) = original_args.get(index as usize) { *arg } else { @@ -765,7 +781,11 @@ impl<'db> rustc_type_ir::inherent::GenericArgs> for GenericArgs< } } -pub fn mk_param<'db>(interner: DbInterner<'db>, index: u32, id: GenericParamId) -> GenericArg<'db> { +pub fn mk_param<'db>( + interner: DbInterner<'db>, + index: u32, + (id, _): (GenericParamId, GenericParamDataRef<'db>), +) -> GenericArg<'db> { match id { GenericParamId::LifetimeParamId(id) => { Region::new_early_param(interner, EarlyParamRegion { index, id }).into() diff --git a/crates/hir-ty/src/next_solver/generics.rs b/crates/hir-ty/src/next_solver/generics.rs index a798582cb989..58c96e56eb56 100644 --- a/crates/hir-ty/src/next_solver/generics.rs +++ b/crates/hir-ty/src/next_solver/generics.rs @@ -1,6 +1,6 @@ //! Things related to generics in the next-trait-solver. -use hir_def::{GenericDefId, GenericParamId}; +use hir_def::{GenericDefId, GenericParamId, TypeParamId, hir::generics::GenericParamDataRef}; use crate::db::HirDatabase; @@ -10,11 +10,13 @@ use super::DbInterner; pub(crate) fn generics(interner: DbInterner<'_>, def: SolverDefId) -> Generics<'_> { let db = interner.db; - let def = match (def.try_into(), def) { - (Ok(def), _) => def, + let (def, consider_late_bound) = match (def.try_into(), def) { + (Ok(def), _) => (def, false), (_, SolverDefId::InternedOpaqueTyId(id)) => match id.loc(db) { - crate::ImplTraitId::ReturnTypeImplTrait(function_id, _) => function_id.into(), - crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => type_alias_id.into(), + crate::ImplTraitId::ReturnTypeImplTrait(function_id, _) => (function_id.into(), true), + crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => { + (type_alias_id.into(), true) + } }, (_, SolverDefId::BuiltinDeriveImplId(id)) => { return crate::builtin_derive::generics_of(interner, id); @@ -23,7 +25,7 @@ pub(crate) fn generics(interner: DbInterner<'_>, def: SolverDefId) -> Generics<' let loc = id.loc(db); let generic_def = loc.owner.generic_def(db); return if loc.allow_using_generic_params { - Generics::from_generic_def(db, generic_def) + Generics::from_generic_def(db, generic_def, false) } else { #[expect( deprecated, @@ -33,40 +35,54 @@ pub(crate) fn generics(interner: DbInterner<'_>, def: SolverDefId) -> Generics<' Generics { generics: crate::generics::Generics::empty(generic_def), additional_param: None, + consider_late_bound: false, } }; } _ => panic!("No generics for {def:?}"), }; - Generics::from_generic_def(db, def) + Generics::from_generic_def(db, def, consider_late_bound) } #[derive(Debug)] pub struct Generics<'db> { generics: crate::generics::Generics<'db>, /// This is used for builtin derives, specifically `CoercePointee`. - additional_param: Option, + additional_param: Option<(GenericParamId, GenericParamDataRef<'db>)>, + consider_late_bound: bool, } impl<'db> Generics<'db> { - pub(crate) fn from_generic_def(db: &'db dyn HirDatabase, def: GenericDefId) -> Generics<'db> { - Generics { generics: crate::generics::generics(db, def), additional_param: None } + pub(crate) fn from_generic_def( + db: &'db dyn HirDatabase, + def: GenericDefId, + consider_late_bound: bool, + ) -> Generics<'db> { + Generics { + generics: crate::generics::generics(db, def), + additional_param: None, + consider_late_bound, + } } pub(crate) fn from_generic_def_plus_one( db: &'db dyn HirDatabase, def: GenericDefId, - additional_param: GenericParamId, + additional_param: TypeParamId, + consider_late_bound: bool, ) -> Generics<'db> { + let generics = crate::generics::generics(db, def); + let data_ref = generics.type_or_const_param(additional_param); Generics { - generics: crate::generics::generics(db, def), - additional_param: Some(additional_param), + generics, + additional_param: Some((additional_param.into(), data_ref)), + consider_late_bound, } } - pub(super) fn iter_id(&self) -> impl Iterator { - self.generics.iter_id().chain(self.additional_param) + pub(super) fn iter(&self) -> impl Iterator)> { + self.generics.iter(self.consider_late_bound).chain(self.additional_param) } } diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs index 6b6dd549b34e..28955fc5a1d2 100644 --- a/crates/hir-ty/src/next_solver/infer/mod.rs +++ b/crates/hir-ty/src/next_solver/infer/mod.rs @@ -840,7 +840,9 @@ impl<'db> InferCtxt<'db> { /// Given a set of generics defined on a type or impl, returns the generic parameters mapping /// each type/region parameter to a fresh inference variable. pub fn fresh_args_for_item(&self, span: Span, def_id: SolverDefId) -> GenericArgs<'db> { - GenericArgs::for_item(self.interner, def_id, |_index, kind, _| self.var_for_def(kind, span)) + GenericArgs::for_item(self.interner, def_id, |_index, (kind, _), _| { + self.var_for_def(kind, span) + }) } /// Like `fresh_args_for_item()`, but first uses the args from `first`. diff --git a/crates/hir-ty/src/next_solver/region.rs b/crates/hir-ty/src/next_solver/region.rs index 72a25f4df6da..317aaa9c575d 100644 --- a/crates/hir-ty/src/next_solver/region.rs +++ b/crates/hir-ty/src/next_solver/region.rs @@ -75,6 +75,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 c0b8d93b47e3..6a1287199d36 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 ea978cde58c1..d935b11797ab 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -4317,9 +4317,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} "#]], @@ -4883,6 +4883,23 @@ fn allowed3(baz: impl Baz>) {} ) } +#[test] +fn rpit_with_lifetimes() { + check_no_mismatches( + r#" +struct Event<'a> {}; +struct Range {} +trait Iterator { + type Item; +} + +struct Vec {} + +fn foo<'e>(events: &'e mut dyn Iterator, Range)>) -> impl Iterator> {} +"#, + ); +} + #[test] fn recursive_tail_sized() { check_infer( @@ -5260,3 +5277,65 @@ fn foo() { "#]], ); } + +#[test] +fn rpit_with_type_and_only_late_bound_lifetime() { + check_no_mismatches( + r#" +trait Trait<'a> {} +struct Foo {} + +impl<'a> Trait for () {} + +fn foo<'a, T>(t: &'a mut T) -> impl Trait<'a> {} + +fn bar() { + let mut f = Foo {}; + let p = foo(&mut f); +} +"#, + ); +} + +#[test] +fn rpit_with_type_and_both_lifetimes() { + check_no_mismatches( + r#" +trait Trait<'a> {} +struct Foo {} + +impl<'a> Trait for () {} + +fn foo<'a, 'b, T: 'b>(t: &'a mut T) -> impl Trait<'a> {} + +fn bar() { + let mut f = Foo {}; + let p = foo(&mut f); +} +"#, + ); +} + +#[test] +fn async_impl_trait() { + check_no_mismatches( + r#" +//- minicore: future +trait Reader {} + +struct Path {} +struct Result { v: T } + +impl Reader for () {} + +async fn read<'a>(path: &'a Path) -> Result { + Result { v: () } +} + +fn foo() { + let p = Path {}; + let v = read(&p); +} +"#, + ); +} diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs index 39d51dcee033..5801783ae41e 100644 --- a/crates/hir-ty/src/variance.rs +++ b/crates/hir-ty/src/variance.rs @@ -152,7 +152,7 @@ impl<'db> Context<'db> { // Const parameters are always invariant. // Make all const parameters invariant. - for (idx, param) in self.generics.iter_id().enumerate() { + for (idx, param) in self.generics.iter_id(false).enumerate() { if let GenericParamId::ConstParamId(_) = param { variances[idx] = Variance::Invariant; } @@ -922,7 +922,7 @@ struct FixedPoint(&'static FixedPoint<(), T, U>, V); res, "{name}[{}]\n", generics(&db, def) - .iter() + .iter(false) .map(|(_, param)| match param { GenericParamDataRef::TypeParamData(type_param_data) => { type_param_data.name.as_ref().unwrap() diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index b31fac3cd21c..0fb0c8492bfb 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1936,7 +1936,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) @@ -7413,7 +7413,7 @@ fn generic_args_from_tys<'db>( args: impl IntoIterator>, ) -> GenericArgs<'db> { let mut args = args.into_iter(); - GenericArgs::for_item(interner, def_id, |_, id, _| { + GenericArgs::for_item(interner, def_id, |_, (id, _), _| { if matches!(id, GenericParamId::TypeParamId(_)) && let Some(arg) = args.next() { diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index d0202c1054c5..4561a2ec83cd 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -1832,11 +1832,14 @@ impl<'db> SemanticsImpl<'db> { let AnyFunctionId::FunctionId(func) = func.id else { return Some(func) }; let interner = DbInterner::new_no_crate(self.db); let mut subst = subst.into_iter(); - let substs = - hir_ty::next_solver::GenericArgs::for_item(interner, trait_.id.into(), |_, id, _| { + let substs = hir_ty::next_solver::GenericArgs::for_item( + interner, + trait_.id.into(), + |_, (id, _), _| { assert!(matches!(id, hir_def::GenericParamId::TypeParamId(_)), "expected a type"); subst.next().expect("too few subst").ty.into() - }); + }, + ); assert!(subst.next().is_none(), "too many subst"); Some(match self.db.lookup_impl_method(env.env, func, substs).0 { Either::Left(it) => it.into(), diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index ba62cc11c3c0..955a0ea53e42 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -32,8 +32,8 @@ use hir_expand::{ name::{AsName, Name}, }; use hir_ty::{ - Adjustment, InferBodyId, InferenceResult, LifetimeElisionKind, ParamEnvAndCrate, - TyLoweringContext, TyLoweringInferVarsCtx, + Adjustment, InferBodyId, InferenceResult, LifetimeElisionKind, LifetimeLoweringMode, + ParamEnvAndCrate, TyLoweringContext, TyLoweringInferVarsCtx, diagnostics::{ InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields, unsafe_operations, @@ -391,6 +391,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, ) .with_infer_vars_behavior(Some(&mut vars_cts)) .lower_ty(type_ref); @@ -1770,6 +1771,7 @@ fn resolve_hir_path_( def, &generics, LifetimeElisionKind::Infer, + LifetimeLoweringMode::LateParam, ) .lower_ty_ext(type_ref); res.map(|ty_ns| (ty_ns, path.segments().first())) @@ -1928,6 +1930,7 @@ fn resolve_hir_path_qualifier( def, &generics, LifetimeElisionKind::Infer, + LifetimeLoweringMode::LateParam, ) .lower_ty_ext(type_ref); res.map(|ty_ns| (ty_ns, path.segments().first())) 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 0454f4e3504d..2dbe6a7f4fbe 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: "", - }, - ">", + "<'>", ], ), ]