Unnamed repository; edit this file 'description' to name the repository.
39 files changed, 1093 insertions, 294 deletions
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs index 6ec78235fe..dec911f716 100644 --- a/crates/hir-def/src/expr_store.rs +++ b/crates/hir-def/src/expr_store.rs @@ -947,7 +947,7 @@ impl ExpressionStore { } } -pub trait StoreVisitor { +pub trait StoreVisitor: Sized { fn on_expr(&mut self, expr: ExprId) { let _ = expr; } @@ -963,6 +963,26 @@ pub trait StoreVisitor { fn on_lifetime(&mut self, lifetime: LifetimeRefId) { let _ = lifetime; } + + fn on_generic_args(&mut self, args: &GenericArgs) { + visit_generic_args(self, args); + } +} + +pub(crate) fn visit_generic_args<V: StoreVisitor>(visitor: &mut V, args: &GenericArgs) { + let GenericArgs { args, bindings, parenthesized: _, has_self_type: _ } = args; + for arg in args { + match arg { + GenericArg::Type(arg) => visitor.on_type(*arg), + GenericArg::Const(ConstRef { expr }) => visitor.on_anon_const_expr(*expr), + GenericArg::Lifetime(arg) => visitor.on_lifetime(*arg), + } + } + for AssociatedTypeBinding { name: _, args, type_ref, bounds } in bindings { + visitor.on_generic_args_opt(args); + visitor.on_type_opt(*type_ref); + visitor.on_type_bounds(bounds); + } } impl<V: StoreVisitor> StoreVisitor for &mut V { @@ -981,25 +1001,13 @@ impl<V: StoreVisitor> StoreVisitor for &mut V { fn on_lifetime(&mut self, lifetime: LifetimeRefId) { V::on_lifetime(self, lifetime); } -} -trait StoreVisitorExt: StoreVisitor { fn on_generic_args(&mut self, args: &GenericArgs) { - let GenericArgs { args, bindings, parenthesized: _, has_self_type: _ } = args; - for arg in args { - match arg { - GenericArg::Type(arg) => self.on_type(*arg), - GenericArg::Const(ConstRef { expr }) => self.on_anon_const_expr(*expr), - GenericArg::Lifetime(arg) => self.on_lifetime(*arg), - } - } - for AssociatedTypeBinding { name: _, args, type_ref, bounds } in bindings { - self.on_generic_args_opt(args); - self.on_type_opt(*type_ref); - self.on_type_bounds(bounds); - } + V::on_generic_args(self, args); } +} +trait StoreVisitorExt: StoreVisitor { fn on_type_bound(&mut self, bound: &TypeBound) { match bound { TypeBound::Path(path_id, _) => self.on_type(path_id.type_ref()), diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 0a1c23c2cc..f3cf2f7d81 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -41,7 +41,7 @@ use crate::{ expr_store::{ Body, BodySourceMap, ExprPtr, ExprRoot, ExpressionStore, ExpressionStoreBuilder, ExpressionStoreDiagnostics, ExpressionStoreSourceMap, HygieneId, LabelPtr, LifetimePtr, - PatPtr, TypePtr, + PatPtr, StoreVisitor, TypePtr, body::Param, expander::Expander, lower::generics::ImplTraitLowerFn, @@ -57,7 +57,7 @@ use crate::{ item_tree::FieldsShape, lang_item::{LangItemTarget, LangItems}, nameres::{DefMap, LocalDefMap, MacroSubNs, block_def_map}, - signatures::StructSignature, + signatures::{StructSignature, TypeAliasSignature}, type_ref::{ ArrayType, ConstRef, FnType, LifetimeRef, LifetimeRefId, Mutability, PathId, Rawness, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, UseArgRef, @@ -332,61 +332,67 @@ pub(crate) fn lower_function( let mut has_self_param = false; let mut has_variadic = false; collector.collect_impl_trait(&mut expr_collector, |collector, mut impl_trait_lower_fn| { - if let Some(param_list) = fn_.value.param_list() { - if let Some(param) = param_list.self_param() { - let enabled = collector.check_cfg(¶m); - if enabled { - has_self_param = true; - params.push(match param.ty() { - Some(ty) => collector.lower_type_ref(ty, &mut impl_trait_lower_fn), - None => { - let self_type = collector.alloc_type_ref_desugared(TypeRef::Path( - Name::new_symbol_root(sym::Self_).into(), - )); - let lifetime = param - .lifetime() - .map(|lifetime| collector.lower_lifetime_ref(lifetime)); - match param.kind() { - ast::SelfParamKind::Owned => self_type, - ast::SelfParamKind::Ref => collector.alloc_type_ref_desugared( - TypeRef::Reference(Box::new(RefType { - ty: self_type, - lifetime, - mutability: Mutability::Shared, - })), - ), - ast::SelfParamKind::MutRef => collector.alloc_type_ref_desugared( - TypeRef::Reference(Box::new(RefType { - ty: self_type, - lifetime, - mutability: Mutability::Mut, - })), - ), + collector.with_lifetime_bound_scope(LifetimeBoundScope::Argument, |collector| { + if let Some(param_list) = fn_.value.param_list() { + if let Some(param) = param_list.self_param() { + let enabled = collector.check_cfg(¶m); + if enabled { + has_self_param = true; + params.push(match param.ty() { + Some(ty) => collector.lower_type_ref(ty, &mut impl_trait_lower_fn), + None => { + let self_type = collector.alloc_type_ref_desugared(TypeRef::Path( + Name::new_symbol_root(sym::Self_).into(), + )); + let lifetime = param + .lifetime() + .map(|lifetime| collector.lower_lifetime_ref(lifetime)); + match param.kind() { + ast::SelfParamKind::Owned => self_type, + ast::SelfParamKind::Ref => collector.alloc_type_ref_desugared( + TypeRef::Reference(Box::new(RefType { + ty: self_type, + lifetime, + mutability: Mutability::Shared, + })), + ), + ast::SelfParamKind::MutRef => collector + .alloc_type_ref_desugared(TypeRef::Reference(Box::new( + RefType { + ty: self_type, + lifetime, + mutability: Mutability::Mut, + }, + ))), + } } - } - }); + }); + } + } + let p = param_list + .params() + .filter(|param| collector.check_cfg(param)) + .filter(|param| { + let is_variadic = param.dotdotdot_token().is_some(); + has_variadic |= is_variadic; + !is_variadic + }) + .map(|param| param.ty()) + // FIXME + .collect::<Vec<_>>(); + for p in p { + params.push(collector.lower_type_ref_opt(p, &mut impl_trait_lower_fn)); } } - let p = param_list - .params() - .filter(|param| collector.check_cfg(param)) - .filter(|param| { - let is_variadic = param.dotdotdot_token().is_some(); - has_variadic |= is_variadic; - !is_variadic - }) - .map(|param| param.ty()) - // FIXME - .collect::<Vec<_>>(); - for p in p { - params.push(collector.lower_type_ref_opt(p, &mut impl_trait_lower_fn)); - } - } + }) }); - let generics = collector.finish(); let return_type = fn_.value.ret_type().map(|ret_type| { - expr_collector.lower_type_ref_opt(ret_type.ty(), &mut ExprCollector::impl_trait_allocator) + expr_collector.with_lifetime_bound_scope(LifetimeBoundScope::Return, |this| { + this.lower_type_ref_opt(ret_type.ty(), &mut ExprCollector::impl_trait_allocator) + }) }); + collector.update_to_late_bound_lifetimes(&expr_collector.named_lifetime_store); + let generics = collector.finish(); let return_type = if fn_.value.async_token().is_some() || fn_.value.gen_token().is_some() { let (path, assoc_name) = @@ -445,6 +451,7 @@ pub struct ExprCollector<'db> { module: ModuleId, lang_items: OnceCell<&'db LangItems>, pub store: ExpressionStoreBuilder, + pub named_lifetime_store: NamedLifetimeStore, // state stuff // Prevent nested impl traits like `impl Foo<impl Bar>`. @@ -551,6 +558,48 @@ impl BindingList { } } +#[derive(Debug, Default)] +pub struct NamedLifetimeStore { + lifetime_bound_scope: Option<LifetimeBoundScope>, + lifetimes_in_where_clause: FxIndexSet<Name>, + lifetimes_constrained_by_input: FxIndexSet<Name>, + lifetimes_in_output: FxIndexSet<Name>, +} + +#[derive(Debug)] +enum LifetimeBoundScope { + Argument, + Return, + WhereClause, + ImplTrait { is_argument_scope: bool }, +} + +impl NamedLifetimeStore { + /// Adds in the lifetime one of three lists fields if + /// `lifetime_bound_context` is `Some` and based on enum variant. + pub(crate) fn push_named_lifetime(&mut self, lifetime: Name) { + match self.lifetime_bound_scope { + Some(LifetimeBoundScope::Argument) => { + self.lifetimes_constrained_by_input.insert(lifetime); + } + Some(LifetimeBoundScope::Return) => { + self.lifetimes_in_output.insert(lifetime); + } + Some(LifetimeBoundScope::WhereClause) => { + self.lifetimes_in_where_clause.insert(lifetime); + } + Some(LifetimeBoundScope::ImplTrait { is_argument_scope }) => { + if is_argument_scope { + self.lifetimes_in_where_clause.insert(lifetime); + } else { + self.lifetimes_in_output.insert(lifetime); + } + } + None => (), + }; + } +} + impl<'db> ExprCollector<'db> { pub fn new( db: &dyn SourceDatabase, @@ -578,6 +627,7 @@ impl<'db> ExprCollector<'db> { outer_impl_trait: false, krate, name_generator_index: 0, + named_lifetime_store: NamedLifetimeStore::default(), }; result.store.inference_roots = Some(SmallVec::new()); result @@ -717,8 +767,16 @@ impl<'db> ExprCollector<'db> { TypeRef::Error } else { return self.with_outer_impl_trait_scope(true, |this| { - let type_bounds = - this.type_bounds_from_ast(inner.type_bound_list(), impl_trait_lower_fn); + let is_argument_scope = this.is_argument_lt_bound_scope(); + let type_bounds = this.with_lifetime_bound_scope( + LifetimeBoundScope::ImplTrait { is_argument_scope }, + |this| { + this.type_bounds_from_ast( + inner.type_bound_list(), + impl_trait_lower_fn, + ) + }, + ); impl_trait_lower_fn(this, AstPtr::new(&node), type_bounds) }); } @@ -781,6 +839,10 @@ impl<'db> ExprCollector<'db> { lifetime_ref: LifetimeRef, node: LifetimePtr, ) -> LifetimeRefId { + if let LifetimeRef::Named(name) = &lifetime_ref { + self.named_lifetime_store.push_named_lifetime(name.clone()); + } + let id = self.store.lifetimes.alloc(lifetime_ref); let ptr = self.expander.in_file(node); self.store.lifetime_map_back.insert(id, ptr); @@ -3359,6 +3421,137 @@ impl ExprCollector<'_> { fn hygiene_id_for(&self, range: TextRange) -> HygieneId { self.expander.hygiene_for_range(self.db, range) } + + fn with_lifetime_bound_scope<T>( + &mut self, + bound_scope: LifetimeBoundScope, + f: impl FnOnce(&mut Self) -> T, + ) -> T { + let old = self.named_lifetime_store.lifetime_bound_scope.replace(bound_scope); + let res = f(self); + self.named_lifetime_store.lifetime_bound_scope = old; + res + } + + fn for_path_type_projection<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T { + if self.is_argument_lt_bound_scope() { + let old = self.named_lifetime_store.lifetime_bound_scope.take(); + let res = f(self); + self.named_lifetime_store.lifetime_bound_scope = old; + res + } else { + f(self) + } + } + + fn push_named_target_lifetime(&mut self, id: LifetimeRefId) { + if let LifetimeRef::Named(name) = &self.store.lifetimes[id] { + self.named_lifetime_store.push_named_lifetime(name.clone()); + } + } + + fn extend_type_alias_lifetime(&mut self, lifetimes: impl Iterator<Item = Name>) { + self.named_lifetime_store.lifetimes_constrained_by_input.extend(lifetimes); + } + + fn is_argument_lt_bound_scope(&mut self) -> bool { + matches!(self.named_lifetime_store.lifetime_bound_scope, Some(LifetimeBoundScope::Argument)) + } + + fn get_constrained_lifetimes_if_type_alias( + &mut self, + mod_path: &intern::Interned<ModPath>, + generic_args: Option<&GenericArgs>, + ) -> Option<FxIndexSet<Name>> { + let r_path = self.def_map.resolve_path( + self.local_def_map, + self.db, + self.module, + mod_path, + BuiltinShadowMode::Module, + None, + ); + let def_id = r_path.0.types.map(|item| item.def)?; + let res = if let crate::ModuleDefId::TypeAliasId(id) = def_id { + let Some(generic_args) = generic_args else { return Some(FxIndexSet::default()) }; + + let constrained_lt_indices = get_constrained_lifetimes(self.db, id); + let res = constrained_lt_indices + .iter() + .filter_map(|&idx| { + let lt_ref = generic_args + .args + .iter() + .filter_map(|arg| match arg { + &GenericArg::Lifetime(lt_ref) => Some(lt_ref), + GenericArg::Type(_) | GenericArg::Const(_) => None, + }) + .nth(idx as usize)?; + match &self.store.lifetimes[lt_ref] { + LifetimeRef::Named(name) => Some(name.clone()), + _ => None, + } + }) + .collect(); + Some(res) + } else { + None + }; + return res; + + #[salsa::tracked(returns(deref), cycle_result = get_constrained_lifetimes_cycle_result)] + fn get_constrained_lifetimes( + db: &dyn SourceDatabase, + type_alias_id: TypeAliasId, + ) -> Box<[u32]> { + let TypeAliasSignature { generic_params, store, ty, .. } = + TypeAliasSignature::of(db, type_alias_id); + let &Some(ty) = ty else { return Default::default() }; + + let mut visitor = Visitor { + store, + generic_params, + parent: type_alias_id, + constrained_lt_indices: Vec::new(), + }; + store.visit_type_ref_children(ty, &mut visitor); + + return visitor.constrained_lt_indices.into_boxed_slice(); + + struct Visitor<'a> { + store: &'a ExpressionStore, + generic_params: &'a GenericParams, + parent: TypeAliasId, + constrained_lt_indices: Vec<u32>, + } + + impl StoreVisitor for Visitor<'_> { + fn on_lifetime(&mut self, lifetime: LifetimeRefId) { + if let LifetimeRef::Named(lifetime_name) = &self.store[lifetime] + && let Some(param_id) = self + .generic_params + .find_lifetime_by_name(lifetime_name, self.parent.into()) + { + self.constrained_lt_indices.push(param_id.local_id.into_raw().into_u32()); + } + } + + fn on_generic_args(&mut self, args: &GenericArgs) { + if !args.has_self_type { + crate::expr_store::visit_generic_args(self, args); + } + } + } + } + + fn get_constrained_lifetimes_cycle_result( + _db: &dyn SourceDatabase, + _: salsa::Id, + _id: TypeAliasId, + ) -> Box<[u32]> { + Default::default() + } + } } fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool { diff --git a/crates/hir-def/src/expr_store/lower/generics.rs b/crates/hir-def/src/expr_store/lower/generics.rs index 7ef9c80de1..2119f19c06 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,7 @@ impl GenericParamsCollector { self.lower_param_list(ec, params) } if let Some(where_clause) = where_clause { - self.lower_where_predicates(ec, where_clause); + self.lower_where_predicates(ec, where_clause) } } @@ -118,7 +121,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 +138,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), + ) + }); } } } @@ -151,33 +161,35 @@ impl GenericParamsCollector { ec: &mut ExprCollector<'_>, where_clause: ast::WhereClause, ) { - for pred in where_clause.predicates() { - let target = if let Some(type_ref) = pred.ty() { - Either::Left( - ec.lower_type_ref(type_ref, &mut ExprCollector::impl_trait_error_allocator), - ) - } else if let Some(lifetime) = pred.lifetime() { - Either::Right(ec.lower_lifetime_ref(lifetime)) - } else { - continue; - }; + ec.with_lifetime_bound_scope(LifetimeBoundScope::WhereClause, |ec| { + for pred in where_clause.predicates() { + let target = if let Some(type_ref) = pred.ty() { + Either::Left( + ec.lower_type_ref(type_ref, &mut ExprCollector::impl_trait_error_allocator), + ) + } else if let Some(lifetime) = pred.lifetime() { + Either::Right(ec.lower_lifetime_ref(lifetime)) + } else { + continue; + }; - let lifetimes: Option<Box<_>> = - pred.for_binder().and_then(|it| it.generic_param_list()).map(|param_list| { - // Higher-Ranked Trait Bounds - param_list - .lifetime_params() - .map(|lifetime_param| { - lifetime_param - .lifetime() - .map_or_else(Name::missing, |lt| Name::new_lifetime(<.text())) - }) - .collect() - }); - for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { - self.lower_type_bound_as_predicate(ec, bound, lifetimes.as_deref(), target); + let lifetimes: Option<Box<_>> = + pred.for_binder().and_then(|it| it.generic_param_list()).map(|param_list| { + // Higher-Ranked Trait Bounds + param_list + .lifetime_params() + .map(|lifetime_param| { + lifetime_param + .lifetime() + .map_or_else(Name::missing, |lt| Name::new_lifetime(<.text())) + }) + .collect() + }); + for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { + self.lower_type_bound_as_predicate(ec, bound, lifetimes.as_deref(), target); + } } - } + }); } fn lower_bounds( @@ -221,6 +233,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 +284,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_constrained_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 236255c404..5d45a4fe83 100644 --- a/crates/hir-def/src/expr_store/lower/path.rs +++ b/crates/hir-def/src/expr_store/lower/path.rs @@ -54,6 +54,13 @@ pub(super) fn lower_path( ast_segments.push(_segment.clone()); segments.push(name); }; + + let old_lifetimes_constrained_by_input = if collector.is_argument_lt_bound_scope() { + Some(std::mem::take(&mut collector.named_lifetime_store.lifetimes_constrained_by_input)) + } else { + None + }; + loop { let Some(segment) = path.segment() else { segments.push(Name::missing()); @@ -112,7 +119,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 { // <T>::foo @@ -122,7 +132,9 @@ pub(super) fn lower_path( } // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::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()), @@ -242,6 +254,24 @@ pub(super) fn lower_path( } let mod_path = Interned::new(ModPath::from_segments(kind, segments)); + + let type_alias_constrained_lifetimes = collector.get_constrained_lifetimes_if_type_alias( + &mod_path, + generic_args.last().and_then(|g| g.as_ref()), + ); + if let Some(old_lifetimes_constrained_by_input) = old_lifetimes_constrained_by_input { + if let Some(lifetimes) = type_alias_constrained_lifetimes { + collector.named_lifetime_store.lifetimes_constrained_by_input = + old_lifetimes_constrained_by_input; + collector.extend_type_alias_lifetime(lifetimes.into_iter()); + } else { + collector + .named_lifetime_store + .lifetimes_constrained_by_input + .extend(old_lifetimes_constrained_by_input); + } + } + if type_anchor.is_none() && generic_args.is_empty() { return Some(Path::BarePath(mod_path)); } else { diff --git a/crates/hir-def/src/expr_store/tests/signatures.rs b/crates/hir-def/src/expr_store/tests/signatures.rs index 24bdc6ece3..460ab6418d 100644 --- a/crates/hir-def/src/expr_store/tests/signatures.rs +++ b/crates/hir-def/src/expr_store/tests/signatures.rs @@ -200,6 +200,19 @@ fn allowed3(baz: impl Baz<Assoc = Qux<impl Foo>>) {} } #[test] +fn type_alias_constrained_lifetime_with_elided_lifetime_args() { + lower_and_print( + r#" +type Alias<'a, 'b, T> = &'b T; +fn f<T>(_: Alias<T>) {} +"#, + expect![[r#" + fn f<T>(Alias::<T>) {...} + "#]], + ); +} + +#[test] fn regression_21138() { lower_and_print( r#" diff --git a/crates/hir-def/src/hir/generics.rs b/crates/hir-def/src/hir/generics.rs index 36ae821d74..b6e9fc2820 100644 --- a/crates/hir-def/src/hir/generics.rs +++ b/crates/hir-def/src/hir/generics.rs @@ -33,6 +33,19 @@ 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, +} + +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 +306,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 +350,20 @@ impl GenericParams { self.lifetimes.iter() } + #[inline] + pub fn iter_early_bound_lt( + &self, + ) -> impl DoubleEndedIterator<Item = (LocalLifetimeParamId, &LifetimeParamData)> { + self.lifetimes.iter().filter(|(_, p)| p.bound_type == LifetimeBoundType::EarlyBound) + } + + #[inline] + pub fn iter_late_bound_lt( + &self, + ) -> impl DoubleEndedIterator<Item = (LocalLifetimeParamId, &LifetimeParamData)> { + self.lifetimes.iter().filter(|(_, p)| p.bound_type == LifetimeBoundType::LateBound) + } + pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> { self.type_or_consts.iter().find_map(|(id, p)| { if p.name().as_ref() == Some(&name) && p.type_param().is_some() { @@ -376,4 +408,22 @@ impl GenericParams { if &p.name == name { Some(LifetimeParamId { local_id: id, parent }) } else { None } }) } + + pub fn lifetime_param_idx( + &self, + lifetime_param_id: &LocalLifetimeParamId, + ) -> Option<(usize, bool)> { + let mut late_bound_idx = 0; + self.iter_lt().enumerate().find_map(|(idx, (param_id, param_data))| { + let idx = if param_data.is_late_bound() { + let prev = late_bound_idx; + late_bound_idx += 1; + prev + } else { + idx - late_bound_idx + }; + + (param_id == *lifetime_param_id).then(|| (idx, param_data.is_late_bound())) + }) + } } diff --git a/crates/hir-ty/src/builtin_derive.rs b/crates/hir-ty/src/builtin_derive.rs index 65a910555d..f82fc940ff 100644 --- a/crates/hir-ty/src/builtin_derive.rs +++ b/crates/hir-ty/src/builtin_derive.rs @@ -68,14 +68,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 5d0a010a7f..027fda0b4f 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -2304,10 +2304,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"), @@ -2319,8 +2319,8 @@ impl<'db> HirDisplay<'db> for Region<'db> { } } RegionKind::ReErased => write!(f, "'<erased>"), - RegionKind::RePlaceholder(_) => write!(f, "<placeholder>"), - RegionKind::ReLateParam(_) => write!(f, "<late-param>"), + RegionKind::RePlaceholder(_) => write!(f, "'<placeholder>"), + RegionKind::ReLateParam(_) => write!(f, "'_"), } } } diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs index 34858212cb..9ee39b3abe 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<DbInterner<'db>>>>, @@ -417,9 +417,7 @@ fn receiver_is_dispatchable<'db>( return true; } - let Some(&receiver_ty) = sig.inputs().skip_binder().first() else { - return false; - }; + 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); @@ -451,7 +449,7 @@ fn receiver_is_dispatchable<'db>( TraitRef::new(interner, unsize_did.into(), [self_param_ty, unsized_self_ty]); // U: Trait<Arg1, ..., ArgN> - let args = GenericArgs::for_item(interner, trait_.into(), |index, kind, _| { + let args = GenericArgs::for_item(interner, trait_.into(), |index, kind, _, _| { if index == 0 { unsized_self_ty.into() } else { mk_param(interner, index, kind) } }); let trait_predicate = TraitRef::new_from_args(interner, trait_.into(), args); @@ -487,9 +485,10 @@ fn receiver_for_self_ty<'db>( receiver_ty: Ty<'db>, self_ty: Ty<'db>, ) -> Ty<'db> { - let args = GenericArgs::for_item(interner, SolverDefId::FunctionId(func), |index, kind, _| { - if index == 0 { self_ty.into() } else { mk_param(interner, index, kind) } - }); + let args = + GenericArgs::for_item(interner, SolverDefId::FunctionId(func), |index, kind, _, _| { + if index == 0 { self_ty.into() } else { mk_param(interner, index, kind) } + }); EarlyBinder::bind(receiver_ty).instantiate(interner, args).skip_norm_wip() } diff --git a/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs index 1f98fcb466..f2ca060bb5 100644 --- a/crates/hir-ty/src/generics.rs +++ b/crates/hir-ty/src/generics.rs @@ -72,17 +72,31 @@ impl<'db> SingleGenerics<'db> { self.params.len_lifetimes() } - pub(crate) fn len(&self) -> usize { - self.params.len() + pub(crate) fn len(&self, consider_late_bound: bool) -> usize { + if consider_late_bound { + self.params.len() + } else { + self.params.len() - self.params.len_late_bound_lifetimes() + } } fn iter_lifetimes(&self) -> impl Iterator<Item = (LifetimeParamId, &'db LifetimeParamData)> { 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<Item = (LifetimeParamId, &'db LifetimeParamData)> { + 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<Item = (TypeOrConstParamId, &'db TypeOrConstParamData)> { @@ -118,23 +132,46 @@ impl<'db> SingleGenerics<'db> { (trait_self, iter) } - pub(crate) fn iter(&self) -> impl Iterator<Item = (GenericParamId, GenericParamDataRef<'db>)> { - let lifetimes = self.iter_lifetimes().map(|(id, data)| { + pub(crate) fn iter( + &self, + consider_late_bound: bool, + ) -> impl Iterator<Item = (GenericParamId, GenericParamDataRef<'db>)> { + 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<Item = (u32, GenericParamId, GenericParamDataRef<'db>)> { - 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<Item = GenericParamId> { - self.iter().map(|(id, _)| id) + pub(crate) fn iter_id( + &self, + consider_late_bound: bool, + ) -> impl Iterator<Item = GenericParamId> { + self.iter(consider_late_bound).map(|(id, _)| id) + } + + pub(crate) fn iter_late_bound( + &self, + ) -> impl Iterator<Item = (GenericParamId, GenericParamDataRef<'db>)> { + // 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), + ) + }) } } @@ -169,7 +206,7 @@ impl<'db> Generics<'db> { pub(crate) fn iter_self( &self, ) -> impl Iterator<Item = (GenericParamId, GenericParamDataRef<'db>)> { - self.owner().iter() + self.owner().iter(false) } pub(crate) fn iter_self_with_idx( @@ -178,8 +215,14 @@ impl<'db> Generics<'db> { self.owner().iter_with_idx() } + pub(crate) fn iter_self_late_bound( + &self, + ) -> impl Iterator<Item = (GenericParamId, GenericParamDataRef<'db>)> { + self.owner().iter_late_bound() + } + pub(crate) fn iter_parent_id(&self) -> impl Iterator<Item = GenericParamId> { - 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,27 +232,33 @@ impl<'db> Generics<'db> { } /// Iterate over the parent params followed by self params. - #[cfg(test)] - pub(crate) fn iter(&self) -> impl Iterator<Item = (GenericParamId, GenericParamDataRef<'_>)> { - self.iter_owners().flat_map(|owner| owner.iter()) + pub(crate) fn iter( + &self, + consider_late_bound: bool, + ) -> impl Iterator<Item = (GenericParamId, GenericParamDataRef<'db>)> { + self.iter_owners().flat_map(move |owner| owner.iter(consider_late_bound)) } - pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> { - self.iter_owners().flat_map(|owner| owner.iter_id()) + pub(crate) fn iter_id( + &self, + consider_late_bound: bool, + ) -> impl Iterator<Item = GenericParamId> { + 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. - pub(crate) fn len(&self) -> usize { + pub(crate) fn len(&self, consider_late_bound: bool) -> usize { match &*self.chain { - [parent, owner] => parent.len() + owner.len(), - [owner] => owner.len(), + [parent, owner] => parent.len(consider_late_bound) + owner.len(consider_late_bound), + [owner] => owner.len(consider_late_bound), _ => unreachable!(), } } #[inline] pub(crate) fn len_parent(&self) -> usize { - self.parent().map_or(0, SingleGenerics::len) + // add `consider_late_bound` arg if needed in future, currently it's not needed. + self.parent().map_or(0, |p| p.len(true)) } pub(crate) fn len_lifetimes_self(&self) -> usize { @@ -275,12 +324,30 @@ 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); + } + 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.lifetime_param_idx(¶m.local_id) { + Some((idx, is_late_bound)) => { + let idx = if is_late_bound { + idx as u32 + } else { + owner.preceding_params_len + u32::from(has_trait_self) + (idx as u32) + }; + (idx, is_late_bound) + } + _ => unreachable!(), + } } #[deprecated = "don't use this; it's easy to expose an erroneous `Generics` with this"] @@ -294,6 +361,18 @@ impl<'db> Generics<'db> { }); Generics { chain } } + + 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 ea1dbb7800..8c70461ff6 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -93,8 +93,8 @@ use crate::{ unify::resolve_completely::WriteBackCtxt, }, lower::{ - ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, LoweringMode, - diagnostics::TyLoweringDiagnostic, + ImplTraitIdx, ImplTraitLoweringMode, LifetimeElisionKind, LifetimeLoweringMode, + LoweringMode, diagnostics::TyLoweringDiagnostic, }, method_resolution::CandidateId, next_solver::{ @@ -1934,6 +1934,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.allow_using_generic_params, infer_vars, &self.defined_anon_consts, + LifetimeLoweringMode::LateParam, ); f(&mut ctx) } @@ -2268,6 +2269,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 ab111736d5..2a5567dfae 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 dd0efea4d7..e871edd265 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<ThinVec<AnonConstId>>, + 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 9119af9628..85801358d4 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 0ec72edc3d..ecc81f9de0 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, @@ -166,6 +166,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 964eb2abc3..778dbb0ff2 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -111,8 +111,8 @@ pub use infer::{ }; pub use lower::{ FieldType, GenericDefaults, GenericDefaultsRef, GenericPredicates, ImplTraits, - LifetimeElisionKind, LoweringMode, TyDefId, TyLoweringContext, TyLoweringInferVarsCtx, - TyLoweringResult, ValueTyDefId, diagnostics::*, + LifetimeElisionKind, LifetimeLoweringMode, LoweringMode, 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; @@ -221,7 +221,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 4f6943f695..656d39e5ad 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,13 @@ 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, PatList, Pattern, PolyFnSig, - Predicate, Region, StoredClauses, StoredConst, StoredEarlyBinder, StoredGenericArg, - StoredGenericArgs, StoredPolyFnSig, StoredTraitRef, StoredTy, TraitPredicate, TraitRef, Ty, - Tys, Unnormalized, abi::Safety, util::BottomUpFolder, + AliasTy, Binder, BoundExistentialPredicates, BoundVarKinds, Clause, ClauseKind, Clauses, + Const, ConstKind, DbInterner, DefaultAny, EarlyBinder, EarlyParamRegion, ErrorGuaranteed, + FnSigKind, FxIndexMap, GenericArg, GenericArgs, ParamConst, ParamEnv, PatList, Pattern, + PolyFnSig, Predicate, Region, StoredClauses, StoredConst, StoredEarlyBinder, + StoredGenericArg, StoredGenericArgs, StoredPolyFnSig, StoredTraitRef, StoredTy, + TraitPredicate, TraitRef, Ty, Tys, Unnormalized, abi::Safety, mk_param, + util::BottomUpFolder, }, }; @@ -247,6 +249,9 @@ pub struct TyLoweringContext<'db, 'a> { forbid_params_after_reason: ForbidParamsAfterReason, pub(crate) defined_anon_consts: ThinVec<AnonConstId>, infer_vars: Option<&'a mut dyn TyLoweringInferVarsCtx<'db>>, + is_lowering_impl_trait_bounds: bool, + bound_vars: Vec<BoundVarKinds<'db>>, // FIXME: HRTB and other for lifetime doesn't change it now + lifetime_lowering_mode: LifetimeLoweringMode, } impl<'db, 'a> TyLoweringContext<'db, 'a> { @@ -258,10 +263,12 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { generic_def: GenericDefId, generics: &'a OnceCell<Generics<'db>>, 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![BoundVarKinds::empty(interner)]; Self { db, // Can provide no block since we don't use it for trait solving. @@ -283,6 +290,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, } } @@ -385,6 +395,32 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } } + + fn peek_bound_vars(&self) -> BoundVarKinds<'db> { + *self.bound_vars.last().unwrap() + } + + fn bound_vars( + db: &'db dyn HirDatabase, + interner: DbInterner<'db>, + def: GenericDefId, + generic: &'a OnceCell<Generics<'db>>, + ) -> BoundVarKinds<'db> { + let def_id = def.into(); + + let generics = generic.get_or_init(|| generics(db, def)); + 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)] @@ -399,6 +435,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 @@ -471,12 +517,40 @@ 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, + BoundRegion { + var: BoundVar::from_u32(index), + kind: BoundRegionKind::Named(solver_def_id), + }, + ) + } + } else { + Region::new_early_param(self.interner, EarlyParamRegion { id, index }) + } } } @@ -568,8 +642,45 @@ 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, lt_param, _| { + if let Some(lt) = lt_param + && lt.is_late_bound() + && !self.is_lowering_impl_trait_bounds + { + let GenericParamId::LifetimeParamId(id) = param_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(), + BoundRegion { + var: BoundVar::from_u32(late_bound_index), + kind: bound_region_kind, + }, + ), + }; + late_bound_index += 1; + return region.into(); + } + + mk_param(interner, index - late_bound_index, param_id) + }, + ); Ty::new_alias( self.interner, AliasTy::new_from_args( @@ -635,17 +746,23 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { args.push(ctx.lower_ty(ret_ty)); }); self.lifetime_elision = old_lifetime_elision; + + // FIXME: When we don't drop HRTB lifetimes, use those here. + let binder = BoundVarKinds::empty(interner); 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, - // FIXME(splat): handle splatted arguments - ), - 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, + // FIXME(splat): handle splatted arguments + ), + inputs_and_output: Tys::new_from_slice(&args), + }, + binder, + ), ) } @@ -792,6 +909,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { let mut clause = None; match bound { &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => { + let binder = self.peek_bound_vars(); // 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 @@ -810,12 +928,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, + ), ))); } } @@ -834,13 +955,17 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } &TypeBound::Lifetime(l) => { let lifetime = self.lower_lifetime(l); + let binder = self.peek_bound_vars(); 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 => {} @@ -1107,7 +1232,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, ) } @@ -1131,6 +1256,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(); @@ -1170,6 +1297,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, @@ -1181,8 +1309,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), @@ -1300,6 +1429,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()?; @@ -1384,6 +1514,7 @@ impl ImplTraits { def.into(), &generics, LifetimeElisionKind::Infer, + LifetimeLoweringMode::Bound, ) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); if let Some(ret_type) = data.ret_type { @@ -1415,6 +1546,7 @@ impl ImplTraits { def.into(), &generics, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); if let Some(type_ref) = data.ty { @@ -1516,6 +1648,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()); @@ -1546,6 +1679,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()); @@ -1628,6 +1762,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( @@ -1674,6 +1809,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()); @@ -1722,6 +1858,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() { @@ -1793,6 +1930,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() { let ty = ctx.lower_ty(field_data.type_ref); @@ -1933,6 +2071,7 @@ fn resolve_type_param_assoc_type_shorthand( def, generics, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ); let interner = ctx.interner; let generics = generics.get().unwrap(); @@ -2113,6 +2252,7 @@ pub(crate) fn type_alias_bounds_with_diagnostics( type_alias.into(), &generics, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ); let interner = ctx.interner; @@ -2351,6 +2491,7 @@ fn generic_predicates( def, generics, LifetimeElisionKind::AnonymousReportError, + LifetimeLoweringMode::Bound, ); let generics = generics.get().unwrap(); let sized_trait = ctx.lang_items.Sized; @@ -2568,6 +2709,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(); @@ -2657,6 +2799,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)); @@ -2668,6 +2811,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 { @@ -2676,19 +2820,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 = TyLoweringContext::bound_vars(db, interner, def.into(), &generics); + 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) } @@ -2749,6 +2895,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 6633215679..27d52881c6 100644 --- a/crates/hir-ty/src/lower/path.rs +++ b/crates/hir-ty/src/lower/path.rs @@ -956,16 +956,20 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { ImplTraitLoweringMode::Disallowed | ImplTraitLoweringMode::Opaque, ) => { let ty = this.ctx.lower_ty(type_ref); + let bound_vars = this.ctx.peek_bound_vars(); 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)); } @@ -1187,7 +1191,7 @@ pub(crate) fn substs_from_args_and_bindings<'db>( ctx, ); - let mut substs = Vec::with_capacity(def_generics.len()); + let mut substs = Vec::with_capacity(def_generics.len(true)); substs.extend( def_generics.iter_parent_id().enumerate().map(|(idx, id)| ctx.parent_arg(idx as u32, id)), diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs index 50d0064d50..bdfa6ab87a 100644 --- a/crates/hir-ty/src/method_resolution.rs +++ b/crates/hir-ty/src/method_resolution.rs @@ -236,7 +236,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 796a37137e..3be9afdf45 100644 --- a/crates/hir-ty/src/method_resolution/probe.rs +++ b/crates/hir-ty/src/method_resolution/probe.rs @@ -2046,7 +2046,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 ab7e6df3f5..0ee9ed0e73 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -2358,8 +2358,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 af823aa005..0a41874374 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<T>( + self, + all_outlive_scope: SolverDefId, + value: Binder<'db, T>, + ) -> T + where + T: TypeFoldable<DbInterner<'db>>, + { + self.instantiate_bound_regions_uncached(value, |br| { + Region::new_late_param(self, all_outlive_scope, br) + }) + } } diff --git a/crates/hir-ty/src/next_solver/generic_arg.rs b/crates/hir-ty/src/next_solver/generic_arg.rs index 51f070cd64..4e5f3c8c49 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::LifetimeParamData}; use intern::InternedRef; use rustc_type_ir::{ ClosureArgs, ConstVid, CoroutineArgs, CoroutineClosureArgs, FallibleTypeFolder, @@ -518,10 +518,15 @@ impl<'db> GenericArgs<'db> { defs: &Generics<'db>, mut mk_kind: F, ) where - F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, + F: FnMut( + u32, + GenericParamId, + Option<&LifetimeParamData>, + &[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, lt_data))| { + let new_arg = mk_kind(idx as u32, param, lt_data, args.as_ref()); args.push(new_arg); }); } @@ -529,7 +534,12 @@ impl<'db> GenericArgs<'db> { #[cold] fn fill_vec_builder<F>(defs: &Generics<'db>, count: usize, mk_kind: F) -> GenericArgs<'db> where - F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, + F: FnMut( + u32, + GenericParamId, + Option<&LifetimeParamData>, + &[GenericArg<'db>], + ) -> GenericArg<'db>, { let mut args = Vec::with_capacity(count); Self::fill_builder(&mut args, defs, mk_kind); @@ -547,7 +557,12 @@ impl<'db> GenericArgs<'db> { mk_kind: F, ) -> GenericArgs<'db> where - F: FnMut(u32, GenericParamId, &[GenericArg<'db>]) -> GenericArg<'db>, + F: FnMut( + u32, + GenericParamId, + Option<&LifetimeParamData>, + &[GenericArg<'db>], + ) -> GenericArg<'db>, { let defs = interner.generics_of(def_id); let count = defs.count(); @@ -565,7 +580,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 +595,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 +614,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)) }) } @@ -676,7 +695,7 @@ impl<'db> rustc_type_ir::inherent::GenericArgs<DbInterner<'db>> for GenericArgs< interner: DbInterner<'db>, def_id: <DbInterner<'db> as rustc_type_ir::Interner>::DefId, ) -> <DbInterner<'db> as rustc_type_ir::Interner>::GenericArgs { - Self::for_item(interner, def_id, |index, kind, _| mk_param(interner, index, kind)) + Self::for_item(interner, def_id, |index, kind, _, _| mk_param(interner, index, kind)) } fn extend_with_error( @@ -684,7 +703,7 @@ impl<'db> rustc_type_ir::inherent::GenericArgs<DbInterner<'db>> for GenericArgs< def_id: <DbInterner<'db> as rustc_type_ir::Interner>::DefId, original_args: &[<DbInterner<'db> as rustc_type_ir::Interner>::GenericArg], ) -> <DbInterner<'db> 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 { diff --git a/crates/hir-ty/src/next_solver/generics.rs b/crates/hir-ty/src/next_solver/generics.rs index a798582cb9..49dbbcb06b 100644 --- a/crates/hir-ty/src/next_solver/generics.rs +++ b/crates/hir-ty/src/next_solver/generics.rs @@ -1,6 +1,9 @@ //! Things related to generics in the next-trait-solver. -use hir_def::{GenericDefId, GenericParamId}; +use hir_def::{ + GenericDefId, GenericParamId, TypeParamId, + hir::generics::{GenericParamDataRef, LifetimeParamData}, +}; use crate::db::HirDatabase; @@ -10,11 +13,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 +28,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,13 +38,14 @@ 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)] @@ -47,31 +53,53 @@ pub struct Generics<'db> { generics: crate::generics::Generics<'db>, /// This is used for builtin derives, specifically `CoercePointee`. additional_param: Option<GenericParamId>, + 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> { Generics { generics: crate::generics::generics(db, def), - additional_param: Some(additional_param), + additional_param: Some(additional_param.into()), + consider_late_bound, } } - pub(super) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> { - self.generics.iter_id().chain(self.additional_param) + pub(super) fn iter( + &self, + ) -> impl Iterator<Item = (GenericParamId, Option<&LifetimeParamData>)> { + self.generics + .iter(self.consider_late_bound) + .map(|(id, data)| { + if let GenericParamDataRef::LifetimeParamData(lt_param) = data { + (id, Some(lt_param)) + } else { + (id, None) + } + }) + .chain(self.additional_param.zip(None)) } } impl<'db> rustc_type_ir::inherent::GenericsOf<DbInterner<'db>> for Generics<'db> { fn count(&self) -> usize { - self.generics.len() + usize::from(self.additional_param.is_some()) + self.generics.len(self.consider_late_bound) + usize::from(self.additional_param.is_some()) } } diff --git a/crates/hir-ty/src/next_solver/infer/mod.rs b/crates/hir-ty/src/next_solver/infer/mod.rs index 2c2f7dbf67..3fdf0480eb 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 [`Self::fresh_args_for_item`], but first uses the args from `first`. diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs index 3c2976eccd..9d9e83fc1a 100644 --- a/crates/hir-ty/src/next_solver/interner.rs +++ b/crates/hir-ty/src/next_solver/interner.rs @@ -1145,7 +1145,7 @@ impl<'db> Interner for DbInterner<'db> { ) -> (rustc_type_ir::TraitRef<Self>, Self::GenericArgsSlice) { let trait_def_id = self.projection_parent(def_id).0; let trait_generics = crate::generics::generics(self.db, trait_def_id.into()); - let trait_generics_len = trait_generics.len(); + let trait_generics_len = trait_generics.len(true); let trait_args = GenericArgs::new_from_slice(&args.as_slice()[..trait_generics_len]); let alias_args = &args.as_slice()[trait_generics_len..]; (TraitRef::new_from_args(self, trait_def_id.into(), trait_args), alias_args) diff --git a/crates/hir-ty/src/next_solver/region.rs b/crates/hir-ty/src/next_solver/region.rs index 72a25f4df6..dc753a1b47 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: BoundRegion<'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(..)) } @@ -155,17 +164,13 @@ pub struct EarlyParamRegion { } #[derive(Copy, Clone, PartialEq, Eq, Hash, GenericTypeVisitable)] -/// The parameter representation of late-bound function parameters, "some region -/// at least as big as the scope `fr.scope`". +/// Represents a liberated late-bound function lifetime parameter. /// -/// Similar to a placeholder region as we create `LateParam` regions when entering a binder -/// except they are always in the root universe and instead of using a boundvar to distinguish -/// between others we use the `DefId` of the parameter. For this reason the `bound_region` field -/// should basically always be `BoundRegionKind::Named` as otherwise there is no way of telling -/// different parameters apart. +/// This denotes some region at least as big as `scope`. It is similar to a placeholder region +/// created when entering a binder, except it always lives in the root universe. pub struct LateParamRegion<'db> { pub scope: SolverDefId, - pub bound_region: BoundRegionKind<'db>, + pub bound_region: BoundRegion<'db>, } impl std::fmt::Debug for LateParamRegion<'_> { diff --git a/crates/hir-ty/src/tests/display_source_code.rs b/crates/hir-ty/src/tests/display_source_code.rs index 37da7fc875..5a4a6562ad 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<Assoc = ()> + Send), //^ &(dyn A<Assoc = ()> + Send + 'static) _: &'a (dyn Send + A<Assoc = ()>), - //^ &'a (dyn A<Assoc = ()> + Send + 'static) + //^ &(dyn A<Assoc = ()> + Send + 'static) _: &dyn B<Assoc = ()>, //^ &(dyn B<Assoc = ()> + 'static) ) {} diff --git a/crates/hir-ty/src/tests/regression/new_solver.rs b/crates/hir-ty/src/tests/regression/new_solver.rs index fb00a755fa..121e3959ce 100644 --- a/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/crates/hir-ty/src/tests/regression/new_solver.rs @@ -1,6 +1,55 @@ use expect_test::expect; +use hir_def::ModuleDefId; +use rustc_type_ir::inherent::IntoKind as _; +use test_fixture::WithFixture; -use crate::tests::{check_infer, check_no_mismatches, check_types}; +use crate::{ + db::HirDatabase, + next_solver::{DbInterner, RegionKind, TyKind}, + test_db::TestDB, + tests::{check_infer, check_no_mismatches, check_types}, +}; + +#[test] +fn liberating_distinct_late_bound_lifetimes_preserves_identity() { + let (db, file_id) = TestDB::with_single_file( + r#" +fn f<'a, 'b>(x: &'a u8, y: &'b u8) {} +"#, + ); + + crate::attach_db(&db, || { + let module_id = db.module_for_file(file_id.file_id(&db)); + let def_map = module_id.def_map(&db); + let scope = &def_map[module_id].scope; + let func = scope + .declarations() + .find_map( + |decl| { + if let ModuleDefId::FunctionId(func) = decl { Some(func) } else { None } + }, + ) + .unwrap(); + let interner = DbInterner::new_with(&db, module_id.krate(&db)); + let sig = db.callable_item_signature(func.into()).instantiate_identity().skip_norm_wip(); + let sig = interner.liberate_late_bound_regions(func.into(), sig); + let inputs = sig.inputs(); + let TyKind::Ref(first_region, _first_ty, _first_mutability) = inputs[0].kind() else { + panic!("expected reference input, got {:?}", inputs[0]); + }; + let TyKind::Ref(second_region, _second_ty, _second_mutability) = inputs[1].kind() else { + panic!("expected reference input, got {:?}", inputs[1]); + }; + let RegionKind::ReLateParam(_first_late_param) = first_region.kind() else { + panic!("expected late parameter region, got {first_region:?}"); + }; + let RegionKind::ReLateParam(_second_late_param) = second_region.kind() else { + panic!("expected late parameter region, got {second_region:?}"); + }; + + assert_ne!(first_region, second_region); + }); +} #[test] fn regression_20365() { diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index b54ed08031..d7b7e47839 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -3253,9 +3253,9 @@ fn main() { "#, expect![[r#" 104..108 'self': &'? Box<T> - 188..192 'self': &'a Box<Foo<T>> + 188..192 'self': &'_ Box<Foo<T>> 218..220 '{}': &'? T - 242..246 'self': &'a Box<Foo<T>> + 242..246 'self': &'_ Box<Foo<T>> 275..277 '{}': &'? Foo<T> 297..301 'self': Box<Foo<T>> 322..324 '{}': Foo<T> @@ -3270,7 +3270,7 @@ fn main() { 389..394 'boxed': Box<Foo<i32>> 389..406 'boxed....nner()': &'? i32 416..421 'good1': &'? i32 - 424..438 'Foo::get_inner': fn get_inner<i32, '?>(&'? Box<Foo<i32>>) -> &'? i32 + 424..438 'Foo::get_inner': fn get_inner<i32>(&'?0.0 Box<Foo<i32>>) -> &'?0.0 i32 424..446 'Foo::g...boxed)': &'? i32 439..445 '&boxed': &'? Box<Foo<i32>> 440..445 'boxed': Box<Foo<i32>> @@ -3278,7 +3278,7 @@ fn main() { 464..469 'boxed': Box<Foo<i32>> 464..480 'boxed....self()': &'? Foo<i32> 490..495 'good2': &'? Foo<i32> - 498..511 'Foo::get_self': fn get_self<i32, '?>(&'? Box<Foo<i32>>) -> &'? Foo<i32> + 498..511 'Foo::get_self': fn get_self<i32>(&'?0.0 Box<Foo<i32>>) -> &'?0.0 Foo<i32> 498..519 'Foo::g...boxed)': &'? Foo<i32> 512..518 '&boxed': &'? Box<Foo<i32>> 513..518 'boxed': Box<Foo<i32>> @@ -4323,3 +4323,39 @@ fn foo() { "#, ); } + +#[test] +fn type_alias_with_different_lifetime_name() { + check_infer( + r#" +trait Trait<'t> { + type Assoc<'a> where Self: 'a; +} + +struct Foo; + +impl<'u> Trait<'u> for Foo { + type Assoc<'b> = &'b u32; +} + +type Alias<'y, 'z> = <Foo as Trait<'y>>::Assoc<'z>; + +fn foo<'e, 'f>(alias: Alias<'e, 'f>) -> &'e u32 { + &1u32 +} + +fn check() { + let foo_fn = foo; +} +"#, + expect![[r#" + 199..204 'alias': &'_ u32 + 232..245 '{ &1u32 }': &'e u32 + 238..243 '&1u32': &'? u32 + 239..243 '1u32': u32 + 258..283 '{ ...foo; }': () + 268..274 'foo_fn': fn foo<'?>(<Foo as Trait<'?>>::Assoc<'?0.0>) -> &'? u32 + 277..280 'foo': fn foo<'?>(<Foo as Trait<'?>>::Assoc<'?0.0>) -> &'? u32 + "#]], + ); +} diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 85c93abcf9..67b35ff461 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<Assoc<i32> = &'a i32>) { "#, expect![[r#" 90..94 'self': &'? Self - 127..128 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + 'static) + 127..128 'v': &'? (dyn Trait<Assoc<i32> = &'_ i32> + 'static) 164..195 '{ ...f(); }': () - 170..171 'v': &'? (dyn Trait<Assoc<i32> = &'a i32> + 'static) + 170..171 'v': &'? (dyn Trait<Assoc<i32> = &'_ i32> + 'static) 170..184 'v.get::<i32>()': <{unknown} as Trait>::Assoc<i32> 170..192 'v.get:...eref()': {unknown} "#]], @@ -4884,6 +4884,23 @@ fn allowed3(baz: impl Baz<Assoc = Qux<impl Foo>>) {} } #[test] +fn rpit_with_lifetimes() { + check_no_mismatches( + r#" +struct Event<'a> {}; +struct Range<T> {} +trait Iterator { + type Item; +} + +struct Vec<T> {} + +fn foo<'e>(events: &'e mut dyn Iterator<Item = (Event<'e>, Range<usize>)>) -> impl Iterator<Item = Event<'e>> {} +"#, + ); +} + +#[test] fn recursive_tail_sized() { check_infer( r#" @@ -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<T> { v: T } + +impl Reader for () {} + +async fn read<'a>(path: &'a Path) -> Result<impl Reader + 'a> { + Result { v: () } +} + +fn foo() { + let p = Path {}; + let v = read(&p); +} +"#, + ); +} diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs index 2ca9ebe070..935f541841 100644 --- a/crates/hir-ty/src/traits.rs +++ b/crates/hir-ty/src/traits.rs @@ -24,7 +24,7 @@ use rustc_type_ir::{ }; use crate::{ - LifetimeElisionKind, Span, TyLoweringContext, + LifetimeElisionKind, LifetimeLoweringMode, Span, TyLoweringContext, db::HirDatabase, generics::Generics, lower::LoweringMode, @@ -192,6 +192,7 @@ pub fn where_predicate_must_hold<'db>( generic_def, &generics, LifetimeElisionKind::Infer, + LifetimeLoweringMode::Bound, ) .with_interning_mode(LoweringMode::Ide); let clauses = diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs index 0a95416e42..9e04353087 100644 --- a/crates/hir-ty/src/variance.rs +++ b/crates/hir-ty/src/variance.rs @@ -58,7 +58,7 @@ fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariance } let generics = generics(db, def); - let count = generics.len(); + let count = generics.len(true); if count == 0 { return VariancesOf::empty(DbInterner::new_no_crate(db)).store(); } @@ -106,7 +106,7 @@ pub(crate) fn variances_of_cycle_initial( ) -> StoredVariancesOf { let interner = DbInterner::new_no_crate(db); let generics = generics(db, def); - let count = generics.len(); + let count = generics.len(true); VariancesOf::new_from_iter(interner, std::iter::repeat_n(Variance::Bivariant, count)).store() } @@ -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; } @@ -940,7 +940,7 @@ struct FixedPoint<T, U, V>(&'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 fc04ea1f49..9ff7a7f7da 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1797,7 +1797,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) @@ -5414,7 +5414,7 @@ impl<'db> Type<'db> { TypeOwnerId::AnonConstId(def) => def.into(), TypeOwnerId::NoParams(_) => return ty.ty.skip_binder(), }; - let args = GenericArgs::for_item(infcx.interner, owner, |_, param, _| { + let args = GenericArgs::for_item(infcx.interner, owner, |_, param, _, _| { *var_for_param .entry(param) .or_insert_with(|| infcx.var_for_def(param, hir_ty::Span::Dummy)) @@ -5855,7 +5855,7 @@ impl<'db> Type<'db> { let env = ParamEnvAndCrate { param_env: ParamEnv::empty(interner), krate: self.krate(db) }; traits::implements_trait_unique_with_infcx(db, env, trait_.id, &mut |infcx| { let mut args = Self::instantiate_many_with_infer(iter::once(self).chain(args), infcx); - GenericArgs::for_item(infcx.interner, trait_.id.into(), |_, param, _| { + GenericArgs::for_item(infcx.interner, trait_.id.into(), |_, param, _, _| { if let GenericParamId::TypeParamId(_) = param && let Some(arg) = args.next() { @@ -7413,7 +7413,7 @@ fn generic_args_from_tys<'db>( ) -> (GenericArgs<'db>, TypeOwnerId) { let mut owner = None::<TypeOwnerId>; let mut args = args.into_iter(); - let args = GenericArgs::for_item(interner, def_id, |_, id, _| { + let args = 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 ba488b8af3..e9e6ec3a01 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -1823,11 +1823,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.skip_binder().into() - }); + }, + ); assert!(subst.next().is_none(), "too many subst"); Some(match self.db.lookup_impl_method(env.param_env(self.db), 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 21830f9d0d..485d525516 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, @@ -462,6 +462,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); @@ -1880,6 +1881,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())) @@ -2038,6 +2040,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 ecb031e42d..329f8325b4 100644 --- a/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -370,7 +370,7 @@ impl<'outer, Outer, const OUTER: usize> () { "#, r#" struct Struct<const C: usize>; -type $0Type<'inner, 'outer, Outer, Inner, const INNER: usize, const OUTER: usize> = &(Struct<INNER>, Struct<OUTER>, Outer, &'inner (), Inner, &'outer ()); +type $0Type<'inner, 'outer, Outer, Inner, const INNER: usize, const OUTER: usize> = &(Struct<INNER>, Struct<OUTER>, 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 0454f4e350..bc7b7274a8 100644 --- a/crates/ide-completion/src/tests/special.rs +++ b/crates/ide-completion/src/tests/special.rs @@ -1581,7 +1581,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 +1614,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 57b723cbd8..8af78532f3 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: "", - }, - ">", + "<'_>", ], ), ] |