Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/expr_store.rs40
-rw-r--r--crates/hir-def/src/expr_store/lower.rs299
-rw-r--r--crates/hir-def/src/expr_store/lower/generics.rs107
-rw-r--r--crates/hir-def/src/expr_store/lower/path.rs34
-rw-r--r--crates/hir-def/src/expr_store/tests/signatures.rs13
-rw-r--r--crates/hir-def/src/hir/generics.rs52
-rw-r--r--crates/hir-ty/src/builtin_derive.rs8
-rw-r--r--crates/hir-ty/src/display.rs8
-rw-r--r--crates/hir-ty/src/dyn_compatibility.rs15
-rw-r--r--crates/hir-ty/src/generics.rs129
-rw-r--r--crates/hir-ty/src/infer.rs6
-rw-r--r--crates/hir-ty/src/infer/closure.rs7
-rw-r--r--crates/hir-ty/src/infer/diagnostics.rs3
-rw-r--r--crates/hir-ty/src/infer/op.rs2
-rw-r--r--crates/hir-ty/src/infer/path.rs3
-rw-r--r--crates/hir-ty/src/lib.rs6
-rw-r--r--crates/hir-ty/src/lower.rs235
-rw-r--r--crates/hir-ty/src/lower/path.rs20
-rw-r--r--crates/hir-ty/src/method_resolution.rs2
-rw-r--r--crates/hir-ty/src/method_resolution/probe.rs2
-rw-r--r--crates/hir-ty/src/mir/lower.rs10
-rw-r--r--crates/hir-ty/src/next_solver/fold.rs18
-rw-r--r--crates/hir-ty/src/next_solver/generic_arg.rs45
-rw-r--r--crates/hir-ty/src/next_solver/generics.rs56
-rw-r--r--crates/hir-ty/src/next_solver/infer/mod.rs4
-rw-r--r--crates/hir-ty/src/next_solver/interner.rs2
-rw-r--r--crates/hir-ty/src/next_solver/region.rs21
-rw-r--r--crates/hir-ty/src/tests/display_source_code.rs2
-rw-r--r--crates/hir-ty/src/tests/regression/new_solver.rs51
-rw-r--r--crates/hir-ty/src/tests/simple.rs44
-rw-r--r--crates/hir-ty/src/tests/traits.rs83
-rw-r--r--crates/hir-ty/src/traits.rs3
-rw-r--r--crates/hir-ty/src/variance.rs8
-rw-r--r--crates/hir/src/lib.rs8
-rw-r--r--crates/hir/src/semantics.rs9
-rw-r--r--crates/hir/src/source_analyzer.rs7
-rw-r--r--crates/ide-assists/src/handlers/extract_type_alias.rs2
-rw-r--r--crates/ide-completion/src/tests/special.rs4
-rw-r--r--crates/ide/src/inlay_hints/bind_pat.rs19
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(&param);
- if enabled {
- has_self_param = true;
- params.push(match param.ty() {
- Some(ty) => collector.lower_type_ref(ty, &mut impl_trait_lower_fn),
- None => {
- let self_type = collector.alloc_type_ref_desugared(TypeRef::Path(
- Name::new_symbol_root(sym::Self_).into(),
- ));
- let lifetime = param
- .lifetime()
- .map(|lifetime| collector.lower_lifetime_ref(lifetime));
- match param.kind() {
- ast::SelfParamKind::Owned => self_type,
- ast::SelfParamKind::Ref => collector.alloc_type_ref_desugared(
- TypeRef::Reference(Box::new(RefType {
- ty: self_type,
- lifetime,
- mutability: Mutability::Shared,
- })),
- ),
- ast::SelfParamKind::MutRef => collector.alloc_type_ref_desugared(
- TypeRef::Reference(Box::new(RefType {
- ty: self_type,
- lifetime,
- mutability: Mutability::Mut,
- })),
- ),
+ collector.with_lifetime_bound_scope(LifetimeBoundScope::Argument, |collector| {
+ if let Some(param_list) = fn_.value.param_list() {
+ if let Some(param) = param_list.self_param() {
+ let enabled = collector.check_cfg(&param);
+ if enabled {
+ has_self_param = true;
+ params.push(match param.ty() {
+ Some(ty) => collector.lower_type_ref(ty, &mut impl_trait_lower_fn),
+ None => {
+ let self_type = collector.alloc_type_ref_desugared(TypeRef::Path(
+ Name::new_symbol_root(sym::Self_).into(),
+ ));
+ let lifetime = param
+ .lifetime()
+ .map(|lifetime| collector.lower_lifetime_ref(lifetime));
+ match param.kind() {
+ ast::SelfParamKind::Owned => self_type,
+ ast::SelfParamKind::Ref => collector.alloc_type_ref_desugared(
+ TypeRef::Reference(Box::new(RefType {
+ ty: self_type,
+ lifetime,
+ mutability: Mutability::Shared,
+ })),
+ ),
+ ast::SelfParamKind::MutRef => collector
+ .alloc_type_ref_desugared(TypeRef::Reference(Box::new(
+ RefType {
+ ty: self_type,
+ lifetime,
+ mutability: Mutability::Mut,
+ },
+ ))),
+ }
}
- }
- });
+ });
+ }
+ }
+ let p = param_list
+ .params()
+ .filter(|param| collector.check_cfg(param))
+ .filter(|param| {
+ let is_variadic = param.dotdotdot_token().is_some();
+ has_variadic |= is_variadic;
+ !is_variadic
+ })
+ .map(|param| param.ty())
+ // FIXME
+ .collect::<Vec<_>>();
+ for p in p {
+ params.push(collector.lower_type_ref_opt(p, &mut impl_trait_lower_fn));
}
}
- let p = param_list
- .params()
- .filter(|param| collector.check_cfg(param))
- .filter(|param| {
- let is_variadic = param.dotdotdot_token().is_some();
- has_variadic |= is_variadic;
- !is_variadic
- })
- .map(|param| param.ty())
- // FIXME
- .collect::<Vec<_>>();
- for p in p {
- params.push(collector.lower_type_ref_opt(p, &mut impl_trait_lower_fn));
- }
- }
+ })
});
- let generics = collector.finish();
let return_type = fn_.value.ret_type().map(|ret_type| {
- expr_collector.lower_type_ref_opt(ret_type.ty(), &mut ExprCollector::impl_trait_allocator)
+ expr_collector.with_lifetime_bound_scope(LifetimeBoundScope::Return, |this| {
+ this.lower_type_ref_opt(ret_type.ty(), &mut ExprCollector::impl_trait_allocator)
+ })
});
+ collector.update_to_late_bound_lifetimes(&expr_collector.named_lifetime_store);
+ let generics = collector.finish();
let return_type = if fn_.value.async_token().is_some() || fn_.value.gen_token().is_some() {
let (path, assoc_name) =
@@ -445,6 +451,7 @@ pub struct ExprCollector<'db> {
module: ModuleId,
lang_items: OnceCell<&'db LangItems>,
pub store: ExpressionStoreBuilder,
+ pub named_lifetime_store: NamedLifetimeStore,
// state stuff
// Prevent nested impl traits like `impl Foo<impl Bar>`.
@@ -551,6 +558,48 @@ impl BindingList {
}
}
+#[derive(Debug, Default)]
+pub struct NamedLifetimeStore {
+ lifetime_bound_scope: Option<LifetimeBoundScope>,
+ lifetimes_in_where_clause: FxIndexSet<Name>,
+ lifetimes_constrained_by_input: FxIndexSet<Name>,
+ lifetimes_in_output: FxIndexSet<Name>,
+}
+
+#[derive(Debug)]
+enum LifetimeBoundScope {
+ Argument,
+ Return,
+ WhereClause,
+ ImplTrait { is_argument_scope: bool },
+}
+
+impl NamedLifetimeStore {
+ /// Adds in the lifetime one of three lists fields if
+ /// `lifetime_bound_context` is `Some` and based on enum variant.
+ pub(crate) fn push_named_lifetime(&mut self, lifetime: Name) {
+ match self.lifetime_bound_scope {
+ Some(LifetimeBoundScope::Argument) => {
+ self.lifetimes_constrained_by_input.insert(lifetime);
+ }
+ Some(LifetimeBoundScope::Return) => {
+ self.lifetimes_in_output.insert(lifetime);
+ }
+ Some(LifetimeBoundScope::WhereClause) => {
+ self.lifetimes_in_where_clause.insert(lifetime);
+ }
+ Some(LifetimeBoundScope::ImplTrait { is_argument_scope }) => {
+ if is_argument_scope {
+ self.lifetimes_in_where_clause.insert(lifetime);
+ } else {
+ self.lifetimes_in_output.insert(lifetime);
+ }
+ }
+ None => (),
+ };
+ }
+}
+
impl<'db> ExprCollector<'db> {
pub fn new(
db: &dyn SourceDatabase,
@@ -578,6 +627,7 @@ impl<'db> ExprCollector<'db> {
outer_impl_trait: false,
krate,
name_generator_index: 0,
+ named_lifetime_store: NamedLifetimeStore::default(),
};
result.store.inference_roots = Some(SmallVec::new());
result
@@ -717,8 +767,16 @@ impl<'db> ExprCollector<'db> {
TypeRef::Error
} else {
return self.with_outer_impl_trait_scope(true, |this| {
- let type_bounds =
- this.type_bounds_from_ast(inner.type_bound_list(), impl_trait_lower_fn);
+ let is_argument_scope = this.is_argument_lt_bound_scope();
+ let type_bounds = this.with_lifetime_bound_scope(
+ LifetimeBoundScope::ImplTrait { is_argument_scope },
+ |this| {
+ this.type_bounds_from_ast(
+ inner.type_bound_list(),
+ impl_trait_lower_fn,
+ )
+ },
+ );
impl_trait_lower_fn(this, AstPtr::new(&node), type_bounds)
});
}
@@ -781,6 +839,10 @@ impl<'db> ExprCollector<'db> {
lifetime_ref: LifetimeRef,
node: LifetimePtr,
) -> LifetimeRefId {
+ if let LifetimeRef::Named(name) = &lifetime_ref {
+ self.named_lifetime_store.push_named_lifetime(name.clone());
+ }
+
let id = self.store.lifetimes.alloc(lifetime_ref);
let ptr = self.expander.in_file(node);
self.store.lifetime_map_back.insert(id, ptr);
@@ -3359,6 +3421,137 @@ impl ExprCollector<'_> {
fn hygiene_id_for(&self, range: TextRange) -> HygieneId {
self.expander.hygiene_for_range(self.db, range)
}
+
+ fn with_lifetime_bound_scope<T>(
+ &mut self,
+ bound_scope: LifetimeBoundScope,
+ f: impl FnOnce(&mut Self) -> T,
+ ) -> T {
+ let old = self.named_lifetime_store.lifetime_bound_scope.replace(bound_scope);
+ let res = f(self);
+ self.named_lifetime_store.lifetime_bound_scope = old;
+ res
+ }
+
+ fn for_path_type_projection<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
+ if self.is_argument_lt_bound_scope() {
+ let old = self.named_lifetime_store.lifetime_bound_scope.take();
+ let res = f(self);
+ self.named_lifetime_store.lifetime_bound_scope = old;
+ res
+ } else {
+ f(self)
+ }
+ }
+
+ fn push_named_target_lifetime(&mut self, id: LifetimeRefId) {
+ if let LifetimeRef::Named(name) = &self.store.lifetimes[id] {
+ self.named_lifetime_store.push_named_lifetime(name.clone());
+ }
+ }
+
+ fn extend_type_alias_lifetime(&mut self, lifetimes: impl Iterator<Item = Name>) {
+ self.named_lifetime_store.lifetimes_constrained_by_input.extend(lifetimes);
+ }
+
+ fn is_argument_lt_bound_scope(&mut self) -> bool {
+ matches!(self.named_lifetime_store.lifetime_bound_scope, Some(LifetimeBoundScope::Argument))
+ }
+
+ fn get_constrained_lifetimes_if_type_alias(
+ &mut self,
+ mod_path: &intern::Interned<ModPath>,
+ generic_args: Option<&GenericArgs>,
+ ) -> Option<FxIndexSet<Name>> {
+ let r_path = self.def_map.resolve_path(
+ self.local_def_map,
+ self.db,
+ self.module,
+ mod_path,
+ BuiltinShadowMode::Module,
+ None,
+ );
+ let def_id = r_path.0.types.map(|item| item.def)?;
+ let res = if let crate::ModuleDefId::TypeAliasId(id) = def_id {
+ let Some(generic_args) = generic_args else { return Some(FxIndexSet::default()) };
+
+ let constrained_lt_indices = get_constrained_lifetimes(self.db, id);
+ let res = constrained_lt_indices
+ .iter()
+ .filter_map(|&idx| {
+ let lt_ref = generic_args
+ .args
+ .iter()
+ .filter_map(|arg| match arg {
+ &GenericArg::Lifetime(lt_ref) => Some(lt_ref),
+ GenericArg::Type(_) | GenericArg::Const(_) => None,
+ })
+ .nth(idx as usize)?;
+ match &self.store.lifetimes[lt_ref] {
+ LifetimeRef::Named(name) => Some(name.clone()),
+ _ => None,
+ }
+ })
+ .collect();
+ Some(res)
+ } else {
+ None
+ };
+ return res;
+
+ #[salsa::tracked(returns(deref), cycle_result = get_constrained_lifetimes_cycle_result)]
+ fn get_constrained_lifetimes(
+ db: &dyn SourceDatabase,
+ type_alias_id: TypeAliasId,
+ ) -> Box<[u32]> {
+ let TypeAliasSignature { generic_params, store, ty, .. } =
+ TypeAliasSignature::of(db, type_alias_id);
+ let &Some(ty) = ty else { return Default::default() };
+
+ let mut visitor = Visitor {
+ store,
+ generic_params,
+ parent: type_alias_id,
+ constrained_lt_indices: Vec::new(),
+ };
+ store.visit_type_ref_children(ty, &mut visitor);
+
+ return visitor.constrained_lt_indices.into_boxed_slice();
+
+ struct Visitor<'a> {
+ store: &'a ExpressionStore,
+ generic_params: &'a GenericParams,
+ parent: TypeAliasId,
+ constrained_lt_indices: Vec<u32>,
+ }
+
+ impl StoreVisitor for Visitor<'_> {
+ fn on_lifetime(&mut self, lifetime: LifetimeRefId) {
+ if let LifetimeRef::Named(lifetime_name) = &self.store[lifetime]
+ && let Some(param_id) = self
+ .generic_params
+ .find_lifetime_by_name(lifetime_name, self.parent.into())
+ {
+ self.constrained_lt_indices.push(param_id.local_id.into_raw().into_u32());
+ }
+ }
+
+ fn on_generic_args(&mut self, args: &GenericArgs) {
+ if !args.has_self_type {
+ crate::expr_store::visit_generic_args(self, args);
+ }
+ }
+ }
+ }
+
+ fn get_constrained_lifetimes_cycle_result(
+ _db: &dyn SourceDatabase,
+ _: salsa::Id,
+ _id: TypeAliasId,
+ ) -> Box<[u32]> {
+ Default::default()
+ }
+ }
}
fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool {
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(&lt.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(&lt.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(&param.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: "",
- },
- ">",
+ "<'_>",
],
),
]