Auto merge of #16805 - dfireBird:lifetime_lowering, r=Veykril

feat: Implement resolving and lowering of Lifetimes (no inference yet)
This commit is contained in:
bors 2024-03-26 07:58:43 +00:00
commit 0583aaa555
23 changed files with 571 additions and 157 deletions

View file

@ -22,8 +22,8 @@ use crate::{
lower::LowerCtx,
nameres::{DefMap, MacroSubNs},
type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LocalTypeOrConstParamId, Lookup,
TypeOrConstParamId, TypeParamId,
AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId,
LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
};
/// Data about a generic type parameter (to a function, struct, impl, ...).
@ -102,6 +102,52 @@ impl TypeOrConstParamData {
impl_from!(TypeParamData, ConstParamData for TypeOrConstParamData);
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum GenericParamData {
TypeParamData(TypeParamData),
ConstParamData(ConstParamData),
LifetimeParamData(LifetimeParamData),
}
impl GenericParamData {
pub fn name(&self) -> Option<&Name> {
match self {
GenericParamData::TypeParamData(it) => it.name.as_ref(),
GenericParamData::ConstParamData(it) => Some(&it.name),
GenericParamData::LifetimeParamData(it) => Some(&it.name),
}
}
pub fn type_param(&self) -> Option<&TypeParamData> {
match self {
GenericParamData::TypeParamData(it) => Some(it),
_ => None,
}
}
pub fn const_param(&self) -> Option<&ConstParamData> {
match self {
GenericParamData::ConstParamData(it) => Some(it),
_ => None,
}
}
pub fn lifetime_param(&self) -> Option<&LifetimeParamData> {
match self {
GenericParamData::LifetimeParamData(it) => Some(it),
_ => None,
}
}
}
impl_from!(TypeParamData, ConstParamData, LifetimeParamData for GenericParamData);
pub enum GenericParamDataRef<'a> {
TypeParamData(&'a TypeParamData),
ConstParamData(&'a ConstParamData),
LifetimeParamData(&'a LifetimeParamData),
}
/// Data about the generic parameters of a function, struct, impl, etc.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct GenericParams {
@ -365,6 +411,13 @@ impl GenericParams {
self.type_or_consts.iter()
}
/// Iterator of lifetimes field
pub fn iter_lt(
&self,
) -> impl DoubleEndedIterator<Item = (Idx<LifetimeParamData>, &LifetimeParamData)> {
self.lifetimes.iter()
}
pub(crate) fn generic_params_query(
db: &dyn DefDatabase,
def: GenericDefId,
@ -507,4 +560,18 @@ impl GenericParams {
.then(|| id)
})
}
pub fn find_lifetime_by_name(
&self,
name: &Name,
parent: GenericDefId,
) -> Option<LifetimeParamId> {
self.lifetimes.iter().find_map(|(id, p)| {
if &p.name == name {
Some(LifetimeParamId { local_id: id, parent })
} else {
None
}
})
}
}

View file

@ -24,6 +24,7 @@ use crate::{
nameres::{DefMap, MacroSubNs},
path::{ModPath, Path, PathKind},
per_ns::PerNs,
type_ref::LifetimeRef,
visibility::{RawVisibility, Visibility},
AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId,
ExternBlockId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId,
@ -120,6 +121,12 @@ pub enum ValueNs {
GenericParam(ConstParamId),
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum LifetimeNs {
Static,
LifetimeParam(LifetimeParamId),
}
impl Resolver {
/// Resolve known trait from std, like `std::futures::Future`
pub fn resolve_known_trait(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<TraitId> {
@ -418,6 +425,19 @@ impl Resolver {
self.resolve_path_as_macro(db, path, expected_macro_kind).map(|(it, _)| db.macro_def(it))
}
pub fn resolve_lifetime(&self, lifetime: &LifetimeRef) -> Option<LifetimeNs> {
if lifetime.name == name::known::STATIC_LIFETIME {
return Some(LifetimeNs::Static);
}
self.scopes().find_map(|scope| match scope {
Scope::GenericParams { def, params } => {
params.find_lifetime_by_name(&lifetime.name, *def).map(LifetimeNs::LifetimeParam)
}
_ => None,
})
}
/// Returns a set of names available in the current scope.
///
/// Note that this is a somewhat fuzzy concept -- internally, the compiler

View file

@ -9,21 +9,21 @@ use chalk_ir::{
AdtId, DebruijnIndex, Scalar,
};
use hir_def::{
builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, DefWithBodyId,
GenericDefId, TraitId, TypeAliasId,
builtin_type::BuiltinType, DefWithBodyId, GenericDefId, GenericParamId, TraitId, TypeAliasId,
};
use smallvec::SmallVec;
use crate::{
consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive,
to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, BoundVar, CallableSig,
GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt,
TyKind,
consteval::unknown_const_as_generic, db::HirDatabase, error_lifetime,
infer::unify::InferenceTable, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics,
Binders, BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy,
Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParamKind {
Type,
Lifetime,
Const(Ty),
}
@ -107,6 +107,9 @@ impl<D> TyBuilder<D> {
ParamKind::Const(ty) => {
BoundVar::new(debruijn, idx).to_const(Interner, ty.clone()).cast(Interner)
}
ParamKind::Lifetime => {
BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner)
}
});
this.vec.extend(filler.take(this.remaining()).casted(Interner));
assert_eq!(this.remaining(), 0);
@ -119,6 +122,7 @@ impl<D> TyBuilder<D> {
let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x {
ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
ParamKind::Lifetime => error_lifetime().cast(Interner),
});
this.vec.extend(filler.casted(Interner));
assert_eq!(this.remaining(), 0);
@ -130,6 +134,7 @@ impl<D> TyBuilder<D> {
self.fill(|x| match x {
ParamKind::Type => table.new_type_var().cast(Interner),
ParamKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner),
ParamKind::Lifetime => table.new_lifetime_var().cast(Interner),
})
}
@ -142,7 +147,8 @@ impl<D> TyBuilder<D> {
fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
match (a.data(Interner), e) {
(GenericArgData::Ty(_), ParamKind::Type)
| (GenericArgData::Const(_), ParamKind::Const(_)) => (),
| (GenericArgData::Const(_), ParamKind::Const(_))
| (GenericArgData::Lifetime(_), ParamKind::Lifetime) => (),
_ => panic!("Mismatched kinds: {a:?}, {:?}, {:?}", self.vec, self.param_kinds),
}
}
@ -201,10 +207,11 @@ impl TyBuilder<()> {
Substitution::from_iter(
Interner,
params.iter_id().map(|id| match id {
either::Either::Left(_) => TyKind::Error.intern(Interner).cast(Interner),
either::Either::Right(id) => {
GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner),
GenericParamId::ConstParamId(id) => {
unknown_const_as_generic(db.const_param_ty(id)).cast(Interner)
}
GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
}),
)
}
@ -219,11 +226,10 @@ impl TyBuilder<()> {
assert!(generics.parent_generics().is_some() == parent_subst.is_some());
let params = generics
.iter_self()
.map(|(id, data)| match data {
TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
TypeOrConstParamData::ConstParamData(_) => {
ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
}
.map(|(id, _data)| match id {
GenericParamId::TypeParamId(_) => ParamKind::Type,
GenericParamId::ConstParamId(id) => ParamKind::Const(db.const_param_ty(id)),
GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
})
.collect();
TyBuilder::new((), params, parent_subst)

View file

@ -938,18 +938,32 @@ impl HirDisplay for Ty {
f.end_location_link();
if parameters.len(Interner) > 0 {
let generics = generics(db.upcast(), def.into());
let (parent_params, self_param, type_params, const_params, _impl_trait_params) =
generics.provenance_split();
let total_len = parent_params + self_param + type_params + const_params;
let (
parent_params,
self_param,
type_params,
const_params,
_impl_trait_params,
lifetime_params,
) = generics.provenance_split();
let total_len =
parent_params + self_param + type_params + const_params + lifetime_params;
// We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
if total_len > 0 {
// `parameters` are in the order of fn's params (including impl traits),
// `parameters` are in the order of fn's params (including impl traits), fn's lifetimes
// parent's params (those from enclosing impl or trait, if any).
let parameters = parameters.as_slice(Interner);
let fn_params_len = self_param + type_params + const_params;
// This will give slice till last type or const
let fn_params = parameters.get(..fn_params_len);
let fn_lt_params =
parameters.get(fn_params_len..(fn_params_len + lifetime_params));
let parent_params = parameters.get(parameters.len() - parent_params..);
let params = parent_params.into_iter().chain(fn_params).flatten();
let params = parent_params
.into_iter()
.chain(fn_lt_params)
.chain(fn_params)
.flatten();
write!(f, "<")?;
f.write_joined(params, ", ")?;
write!(f, ">")?;
@ -1308,8 +1322,17 @@ fn hir_fmt_generics(
generic_def: Option<hir_def::GenericDefId>,
) -> Result<(), HirDisplayError> {
let db = f.db;
let lifetime_args_count = generic_def.map_or(0, |g| db.generic_params(g).lifetimes.len());
if parameters.len(Interner) + lifetime_args_count > 0 {
if parameters.len(Interner) > 0 {
use std::cmp::Ordering;
let param_compare =
|a: &GenericArg, b: &GenericArg| match (a.data(Interner), b.data(Interner)) {
(crate::GenericArgData::Lifetime(_), crate::GenericArgData::Lifetime(_)) => {
Ordering::Equal
}
(crate::GenericArgData::Lifetime(_), _) => Ordering::Less,
(_, crate::GenericArgData::Lifetime(_)) => Ordering::Less,
(_, _) => Ordering::Equal,
};
let parameters_to_write = if f.display_target.is_source_code() || f.omit_verbose_types() {
match generic_def
.map(|generic_def_id| db.generic_defaults(generic_def_id))
@ -1335,6 +1358,11 @@ fn hir_fmt_generics(
return true;
}
}
if parameter.lifetime(Interner).map(|it| it.data(Interner))
== Some(&crate::LifetimeData::Static)
{
return true;
}
let default_parameter = match default_parameters.get(i) {
Some(it) => it,
None => return true,
@ -1355,16 +1383,12 @@ fn hir_fmt_generics(
} else {
parameters.as_slice(Interner)
};
if !parameters_to_write.is_empty() || lifetime_args_count != 0 {
//FIXME: Should handle the ordering of lifetimes when creating substitutions
let mut parameters_to_write = parameters_to_write.to_vec();
parameters_to_write.sort_by(param_compare);
if !parameters_to_write.is_empty() {
write!(f, "<")?;
let mut first = true;
for _ in 0..lifetime_args_count {
if !first {
write!(f, ", ")?;
}
first = false;
write!(f, "'_")?;
}
for generic_arg in parameters_to_write {
if !first {
write!(f, ", ")?;

View file

@ -42,7 +42,7 @@ use hir_def::{
layout::Integer,
path::{ModPath, Path},
resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
type_ref::TypeRef,
type_ref::{LifetimeRef, TypeRef},
AdtId, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, Lookup, TraitId,
TupleFieldId, TupleId, TypeAliasId, VariantId,
};
@ -1037,6 +1037,12 @@ impl<'a> InferenceContext<'a> {
self.result.standard_types.unknown.clone()
}
fn make_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime {
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into());
let lt = ctx.lower_lifetime(lifetime_ref);
self.insert_type_vars(lt)
}
/// Replaces `Ty::Error` by a new type var, so we can maybe still infer it.
fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
self.table.insert_type_vars_shallow(ty)

View file

@ -8,13 +8,12 @@ use std::{
use chalk_ir::{cast::Cast, fold::Shift, DebruijnIndex, Mutability, TyVariableKind};
use either::Either;
use hir_def::{
generics::TypeOrConstParamData,
hir::{
ArithOp, Array, BinaryOp, ClosureKind, Expr, ExprId, LabelId, Literal, Statement, UnaryOp,
},
lang_item::{LangItem, LangItemTarget},
path::{GenericArg, GenericArgs, Path},
BlockId, ConstParamId, FieldId, ItemContainerId, Lookup, TupleFieldId, TupleId,
path::{GenericArgs, Path},
BlockId, FieldId, GenericParamId, ItemContainerId, Lookup, TupleFieldId, TupleId,
};
use hir_expand::name::{name, Name};
use stdx::always;
@ -1816,10 +1815,17 @@ impl InferenceContext<'_> {
def_generics: Generics,
generic_args: Option<&GenericArgs>,
) -> Substitution {
let (parent_params, self_params, type_params, const_params, impl_trait_params) =
def_generics.provenance_split();
let (
parent_params,
self_params,
type_params,
const_params,
impl_trait_params,
lifetime_params,
) = def_generics.provenance_split();
assert_eq!(self_params, 0); // method shouldn't have another Self param
let total_len = parent_params + type_params + const_params + impl_trait_params;
let total_len =
parent_params + type_params + const_params + impl_trait_params + lifetime_params;
let mut substs = Vec::with_capacity(total_len);
// handle provided arguments
@ -1828,8 +1834,7 @@ impl InferenceContext<'_> {
for (arg, kind_id) in generic_args
.args
.iter()
.filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
.take(type_params + const_params)
.take(type_params + const_params + lifetime_params)
.zip(def_generics.iter_id())
{
if let Some(g) = generic_arg_to_chalk(
@ -1850,6 +1855,7 @@ impl InferenceContext<'_> {
DebruijnIndex::INNERMOST,
)
},
|this, lt_ref| this.make_lifetime(lt_ref),
) {
substs.push(g);
}
@ -1858,16 +1864,17 @@ impl InferenceContext<'_> {
// Handle everything else as unknown. This also handles generic arguments for the method's
// parent (impl or trait), which should come after those for the method.
for (id, data) in def_generics.iter().skip(substs.len()) {
match data {
TypeOrConstParamData::TypeParamData(_) => {
for (id, _data) in def_generics.iter().skip(substs.len()) {
match id {
GenericParamId::TypeParamId(_) => {
substs.push(self.table.new_type_var().cast(Interner))
}
TypeOrConstParamData::ConstParamData(_) => substs.push(
self.table
.new_const_var(self.db.const_param_ty(ConstParamId::from_unchecked(id)))
.cast(Interner),
),
GenericParamId::ConstParamId(id) => {
substs.push(self.table.new_const_var(self.db.const_param_ty(id)).cast(Interner))
}
GenericParamId::LifetimeParamId(_) => {
substs.push(self.table.new_lifetime_var().cast(Interner))
}
}
}
assert_eq!(substs.len(), total_len);

View file

@ -11,7 +11,7 @@ use stdx::never;
use crate::{
builder::ParamKind,
consteval,
consteval, error_lifetime,
method_resolution::{self, VisibleFromModule},
to_chalk_trait_id,
utils::generics,
@ -111,6 +111,7 @@ impl InferenceContext<'_> {
it.next().unwrap_or_else(|| match x {
ParamKind::Type => self.result.standard_types.unknown.clone().cast(Interner),
ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
ParamKind::Lifetime => error_lifetime().cast(Interner),
})
})
.build();

View file

@ -16,12 +16,12 @@ use triomphe::Arc;
use super::{InferOk, InferResult, InferenceContext, TypeError};
use crate::{
consteval::unknown_const, db::HirDatabase, fold_tys_and_consts, static_lifetime,
to_chalk_trait_id, traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue,
DebruijnIndex, DomainGoal, GenericArg, GenericArgData, Goal, GoalData, Guidance, InEnvironment,
InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind, ProjectionTy, ProjectionTyExt, Scalar,
Solution, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind,
WhereClause,
consteval::unknown_const, db::HirDatabase, fold_generic_args, fold_tys_and_consts,
static_lifetime, to_chalk_trait_id, traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical,
Const, ConstValue, DebruijnIndex, DomainGoal, GenericArg, GenericArgData, Goal, GoalData,
Guidance, InEnvironment, InferenceVar, Interner, Lifetime, OpaqueTyId, ParamKind, ProjectionTy,
ProjectionTyExt, Scalar, Solution, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt,
TyKind, VariableKind, WhereClause,
};
impl InferenceContext<'_> {
@ -807,6 +807,7 @@ impl<'a> InferenceTable<'a> {
.fill(|it| {
let arg = match it {
ParamKind::Type => self.new_type_var(),
ParamKind::Lifetime => unreachable!("Tuple with lifetime parameter"),
ParamKind::Const(_) => unreachable!("Tuple with const parameter"),
};
arg_tys.push(arg.clone());
@ -861,11 +862,16 @@ impl<'a> InferenceTable<'a> {
where
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
{
fold_tys_and_consts(
fold_generic_args(
ty,
|it, _| match it {
Either::Left(ty) => Either::Left(self.insert_type_vars_shallow(ty)),
Either::Right(c) => Either::Right(self.insert_const_vars_shallow(c)),
|arg, _| match arg {
GenericArgData::Ty(ty) => GenericArgData::Ty(self.insert_type_vars_shallow(ty)),
// FIXME: insert lifetime vars once LifetimeData::InferenceVar
// and specific error variant for lifetimes start being constructed
GenericArgData::Lifetime(lt) => GenericArgData::Lifetime(lt),
GenericArgData::Const(c) => {
GenericArgData::Const(self.insert_const_vars_shallow(c))
}
},
DebruijnIndex::INNERMOST,
)

View file

@ -90,8 +90,8 @@ pub use lower::{
};
pub use mapping::{
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
lt_from_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id,
to_placeholder_idx,
lt_from_placeholder_idx, lt_to_placeholder_idx, to_assoc_type_id, to_chalk_trait_id,
to_foreign_def_id, to_placeholder_idx,
};
pub use method_resolution::check_orphan_rules;
pub use traits::TraitEnvironment;
@ -335,11 +335,23 @@ pub(crate) fn make_binders_with_count<T: HasInterner<Interner = Interner>>(
generics: &Generics,
value: T,
) -> Binders<T> {
let it = generics.iter_id().take(count).map(|id| match id {
Either::Left(_) => None,
Either::Right(id) => Some(db.const_param_ty(id)),
});
crate::make_type_and_const_binders(it, value)
let it = generics.iter_id().take(count);
Binders::new(
VariableKinds::from_iter(
Interner,
it.map(|x| match x {
hir_def::GenericParamId::ConstParamId(id) => {
chalk_ir::VariableKind::Const(db.const_param_ty(id))
}
hir_def::GenericParamId::TypeParamId(_) => {
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
}
hir_def::GenericParamId::LifetimeParamId(_) => chalk_ir::VariableKind::Lifetime,
}),
),
value,
)
}
pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
@ -609,6 +621,10 @@ pub fn static_lifetime() -> Lifetime {
LifetimeData::Static.intern(Interner)
}
pub fn error_lifetime() -> Lifetime {
static_lifetime()
}
pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
t: T,
for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
@ -698,6 +714,55 @@ pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFold
t.fold_with(&mut TyFolder(f), binders)
}
pub(crate) fn fold_generic_args<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>>(
t: T,
f: impl FnMut(GenericArgData, DebruijnIndex) -> GenericArgData,
binders: DebruijnIndex,
) -> T {
use chalk_ir::fold::{TypeFolder, TypeSuperFoldable};
#[derive(chalk_derive::FallibleTypeFolder)]
#[has_interner(Interner)]
struct TyFolder<F: FnMut(GenericArgData, DebruijnIndex) -> GenericArgData>(F);
impl<F: FnMut(GenericArgData, DebruijnIndex) -> GenericArgData> TypeFolder<Interner>
for TyFolder<F>
{
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
self
}
fn interner(&self) -> Interner {
Interner
}
fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty {
let ty = ty.super_fold_with(self.as_dyn(), outer_binder);
self.0(GenericArgData::Ty(ty), outer_binder)
.intern(Interner)
.ty(Interner)
.unwrap()
.clone()
}
fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Const {
self.0(GenericArgData::Const(c), outer_binder)
.intern(Interner)
.constant(Interner)
.unwrap()
.clone()
}
fn fold_lifetime(&mut self, lt: Lifetime, outer_binder: DebruijnIndex) -> Lifetime {
let lt = lt.super_fold_with(self.as_dyn(), outer_binder);
self.0(GenericArgData::Lifetime(lt), outer_binder)
.intern(Interner)
.lifetime(Interner)
.unwrap()
.clone()
}
}
t.fold_with(&mut TyFolder(f), binders)
}
/// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
/// ensures there are no unbound variables or inference variables anywhere in
/// the `t`.

View file

@ -24,17 +24,20 @@ use hir_def::{
data::adt::StructKind,
expander::Expander,
generics::{
TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
GenericParamDataRef, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
WherePredicateTypeTarget,
},
lang_item::LangItem,
nameres::MacroSubNs,
path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments},
resolver::{HasResolver, Resolver, TypeNs},
type_ref::{ConstRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
resolver::{HasResolver, LifetimeNs, Resolver, TypeNs},
type_ref::{
ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef,
},
AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId,
GenericDefId, HasModule, ImplId, InTypeConstLoc, ItemContainerId, LocalFieldId, Lookup,
ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId,
TypeParamId, UnionId, VariantId,
GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId, LocalFieldId,
Lookup, ModuleDefId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeOwnerId,
UnionId, VariantId,
};
use hir_expand::{name::Name, ExpandResult};
use intern::Interned;
@ -52,18 +55,18 @@ use crate::{
unknown_const_as_generic,
},
db::HirDatabase,
make_binders,
mapping::{from_chalk_trait_id, ToChalk},
error_lifetime, make_binders,
mapping::{from_chalk_trait_id, lt_to_placeholder_idx, ToChalk},
static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
utils::Generics,
utils::{
all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
all_super_trait_refs, associated_type_by_name_including_super_traits, generics, Generics,
InTypeConstIdMetadata,
},
AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy,
FnAbi, FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, ParamKind,
PolyFnSig, ProjectionTy, QuantifiedWhereClause, QuantifiedWhereClauses, Substitution,
TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
FnAbi, FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime,
LifetimeData, ParamKind, PolyFnSig, ProjectionTy, QuantifiedWhereClause,
QuantifiedWhereClauses, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder,
TyKind, WhereClause,
};
#[derive(Debug)]
@ -275,9 +278,11 @@ impl<'a> TyLoweringContext<'a> {
let inner_ty = self.lower_ty(inner);
TyKind::Slice(inner_ty).intern(Interner)
}
TypeRef::Reference(inner, _, mutability) => {
TypeRef::Reference(inner, lifetime, mutability) => {
let inner_ty = self.lower_ty(inner);
let lifetime = static_lifetime();
// FIXME: It should infer the eldided lifetimes instead of stubbing with static
let lifetime =
lifetime.as_ref().map_or_else(static_lifetime, |lr| self.lower_lifetime(lr));
TyKind::Ref(lower_to_chalk_mutability(*mutability), lifetime, inner_ty)
.intern(Interner)
}
@ -351,13 +356,18 @@ impl<'a> TyLoweringContext<'a> {
.filter(|(_, data)| {
matches!(
data,
TypeOrConstParamData::TypeParamData(data)
GenericParamDataRef::TypeParamData(data)
if data.provenance == TypeParamProvenance::ArgumentImplTrait
)
})
.nth(idx as usize)
.map_or(TyKind::Error, |(id, _)| {
TyKind::Placeholder(to_placeholder_idx(self.db, id))
if let GenericParamId::TypeParamId(id) = id {
TyKind::Placeholder(to_placeholder_idx(self.db, id.into()))
} else {
// we just filtered them out
unreachable!("Unexpected lifetime or const argument");
}
});
param.intern(Interner)
} else {
@ -374,11 +384,12 @@ impl<'a> TyLoweringContext<'a> {
list_params,
const_params,
_impl_trait_params,
_lifetime_params,
) = if let Some(def) = self.resolver.generic_def() {
let generics = generics(self.db.upcast(), def);
generics.provenance_split()
} else {
(0, 0, 0, 0, 0)
(0, 0, 0, 0, 0, 0)
};
TyKind::BoundVar(BoundVar::new(
self.in_binders,
@ -815,9 +826,16 @@ impl<'a> TyLoweringContext<'a> {
return Substitution::empty(Interner);
};
let def_generics = generics(self.db.upcast(), def);
let (parent_params, self_params, type_params, const_params, impl_trait_params) =
def_generics.provenance_split();
let item_len = self_params + type_params + const_params + impl_trait_params;
let (
parent_params,
self_params,
type_params,
const_params,
impl_trait_params,
lifetime_params,
) = def_generics.provenance_split();
let item_len =
self_params + type_params + const_params + impl_trait_params + lifetime_params;
let total_len = parent_params + item_len;
let ty_error = TyKind::Error.intern(Interner).cast(Interner);
@ -832,7 +850,10 @@ impl<'a> TyLoweringContext<'a> {
.take(self_params)
{
if let Some(id) = def_generic_iter.next() {
assert!(id.is_left());
assert!(matches!(
id,
GenericParamId::TypeParamId(_) | GenericParamId::LifetimeParamId(_)
));
substs.push(x);
}
}
@ -865,6 +886,7 @@ impl<'a> TyLoweringContext<'a> {
&mut (),
|_, type_ref| self.lower_ty(type_ref),
|_, const_ref, ty| self.lower_const(const_ref, ty),
|_, lifetime_ref| self.lower_lifetime(lifetime_ref),
) {
had_explicit_args = true;
substs.push(x);
@ -874,15 +896,45 @@ impl<'a> TyLoweringContext<'a> {
}
}
}
for arg in generic_args
.args
.iter()
.filter(|arg| matches!(arg, GenericArg::Lifetime(_)))
.take(lifetime_params)
{
// Taking into the fact that def_generic_iter will always have lifetimes at the end
// Should have some test cases tho to test this behaviour more properly
if let Some(id) = def_generic_iter.next() {
if let Some(x) = generic_arg_to_chalk(
self.db,
id,
arg,
&mut (),
|_, type_ref| self.lower_ty(type_ref),
|_, const_ref, ty| self.lower_const(const_ref, ty),
|_, lifetime_ref| self.lower_lifetime(lifetime_ref),
) {
had_explicit_args = true;
substs.push(x);
} else {
// Never return a None explicitly
never!("Unexpected None by generic_arg_to_chalk");
}
}
}
} else {
fill_self_params();
}
// These params include those of parent.
let remaining_params: SmallVec<[_; 2]> = def_generic_iter
.map(|eid| match eid {
Either::Left(_) => ty_error.clone(),
Either::Right(x) => unknown_const_as_generic(self.db.const_param_ty(x)),
.map(|id| match id {
GenericParamId::ConstParamId(x) => {
unknown_const_as_generic(self.db.const_param_ty(x))
}
GenericParamId::TypeParamId(_) => ty_error.clone(),
GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner),
})
.collect();
assert_eq!(remaining_params.len() + substs.len(), total_len);
@ -1309,6 +1361,33 @@ impl<'a> TyLoweringContext<'a> {
});
ImplTrait { bounds: crate::make_single_type_binders(predicates) }
}
pub fn lower_lifetime(&self, lifetime: &LifetimeRef) -> Lifetime {
match self.resolver.resolve_lifetime(lifetime) {
Some(resolution) => match resolution {
LifetimeNs::Static => static_lifetime(),
LifetimeNs::LifetimeParam(id) => match self.type_param_mode {
ParamLoweringMode::Placeholder => {
LifetimeData::Placeholder(lt_to_placeholder_idx(self.db, id))
}
ParamLoweringMode::Variable => {
let generics = generics(
self.db.upcast(),
self.resolver.generic_def().expect("generics in scope"),
);
let idx = match generics.lifetime_idx(id) {
None => return error_lifetime(),
Some(idx) => idx,
};
LifetimeData::BoundVar(BoundVar::new(self.in_binders, idx))
}
}
.intern(Interner),
},
None => error_lifetime(),
}
}
}
fn count_impl_traits(type_ref: &TypeRef) -> usize {
@ -1691,7 +1770,7 @@ pub(crate) fn generic_defaults_query(
let defaults = Arc::from_iter(generic_params.iter().enumerate().map(|(idx, (id, p))| {
match p {
TypeOrConstParamData::TypeParamData(p) => {
GenericParamDataRef::TypeParamData(p) => {
let mut ty =
p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
// Each default can only refer to previous parameters.
@ -1700,13 +1779,13 @@ pub(crate) fn generic_defaults_query(
ty = fallback_bound_vars(ty, idx, parent_start_idx);
crate::make_binders(db, &generic_params, ty.cast(Interner))
}
TypeOrConstParamData::ConstParamData(p) => {
GenericParamDataRef::ConstParamData(p) => {
let GenericParamId::ConstParamId(id) = id else {
unreachable!("Unexpected lifetime or type argument")
};
let mut val = p.default.as_ref().map_or_else(
|| {
unknown_const_as_generic(
db.const_param_ty(ConstParamId::from_unchecked(id)),
)
},
|| unknown_const_as_generic(db.const_param_ty(id)),
|c| {
let c = ctx.lower_const(c, ctx.lower_ty(&p.ty));
c.cast(Interner)
@ -1716,6 +1795,10 @@ pub(crate) fn generic_defaults_query(
val = fallback_bound_vars(val, idx, parent_start_idx);
make_binders(db, &generic_params, val)
}
GenericParamDataRef::LifetimeParamData(_) => {
// using static because it requires defaults
make_binders(db, &generic_params, static_lifetime().cast(Interner))
}
}
}));
@ -1732,8 +1815,9 @@ pub(crate) fn generic_defaults_recover(
// we still need one default per parameter
let defaults = Arc::from_iter(generic_params.iter_id().map(|id| {
let val = match id {
Either::Left(_) => TyKind::Error.intern(Interner).cast(Interner),
Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner),
GenericParamId::ConstParamId(id) => unknown_const_as_generic(db.const_param_ty(id)),
GenericParamId::LifetimeParamId(_) => static_lifetime().cast(Interner),
};
crate::make_binders(db, &generic_params, val)
}));
@ -2097,23 +2181,29 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut
/// Returns `Some` of the lowered generic arg. `None` if the provided arg is a lifetime.
pub(crate) fn generic_arg_to_chalk<'a, T>(
db: &dyn HirDatabase,
kind_id: Either<TypeParamId, ConstParamId>,
kind_id: GenericParamId,
arg: &'a GenericArg,
this: &mut T,
for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a,
for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a,
) -> Option<crate::GenericArg> {
let kind = match kind_id {
Either::Left(_) => ParamKind::Type,
Either::Right(id) => {
GenericParamId::TypeParamId(_) => ParamKind::Type,
GenericParamId::ConstParamId(id) => {
let ty = db.const_param_ty(id);
ParamKind::Const(ty)
}
GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime,
};
Some(match (arg, kind) {
(GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, type_ref).cast(Interner),
(GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner),
(GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => {
for_lifetime(this, lifetime_ref).cast(Interner)
}
(GenericArg::Const(_), ParamKind::Type) => TyKind::Error.intern(Interner).cast(Interner),
(GenericArg::Lifetime(_), ParamKind::Type) => TyKind::Error.intern(Interner).cast(Interner),
(GenericArg::Type(t), ParamKind::Const(c_ty)) => {
// We want to recover simple idents, which parser detects them
// as types. Maybe here is not the best place to do it, but
@ -2129,7 +2219,9 @@ pub(crate) fn generic_arg_to_chalk<'a, T>(
}
unknown_const_as_generic(c_ty)
}
(GenericArg::Lifetime(_), _) => return None,
(GenericArg::Lifetime(_), ParamKind::Const(c_ty)) => unknown_const_as_generic(c_ty),
(GenericArg::Type(_), ParamKind::Lifetime) => error_lifetime().cast(Interner),
(GenericArg::Const(_), ParamKind::Lifetime) => error_lifetime().cast(Interner),
})
}

View file

@ -151,6 +151,14 @@ pub fn lt_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> L
db.lookup_intern_lifetime_param_id(interned_id)
}
pub fn lt_to_placeholder_idx(db: &dyn HirDatabase, id: LifetimeParamId) -> PlaceholderIndex {
let interned_id = db.intern_lifetime_param_id(id);
PlaceholderIndex {
ui: chalk_ir::UniverseIndex::ROOT,
idx: salsa::InternKey::as_intern_id(&interned_id).as_usize(),
}
}
pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId {
chalk_ir::TraitId(salsa::InternKey::as_intern_id(&id))
}

View file

@ -184,8 +184,16 @@ impl Filler<'_> {
self.generics
.as_ref()
.and_then(|it| it.iter().nth(b.index))
.unwrap()
.0,
.and_then(|(id, _)| match id {
hir_def::GenericParamId::ConstParamId(id) => {
Some(hir_def::TypeOrConstParamId::from(id))
}
hir_def::GenericParamId::TypeParamId(id) => {
Some(hir_def::TypeOrConstParamId::from(id))
}
_ => None,
})
.unwrap(),
self.subst.clone(),
)
})?

View file

@ -85,7 +85,7 @@ fn render_dyn_for_ty() {
trait Foo<'a> {}
fn foo(foo: &dyn for<'a> Foo<'a>) {}
// ^^^ &dyn Foo
// ^^^ &dyn Foo<'static>
"#,
);
}

View file

@ -1109,7 +1109,7 @@ fn var_args() {
#[lang = "va_list"]
pub struct VaListImpl<'f>;
fn my_fn(foo: ...) {}
//^^^ VaListImpl<'_>
//^^^ VaListImpl<'static>
"#,
);
}

View file

@ -896,13 +896,13 @@ fn flush(&self) {
"#,
expect![[r#"
123..127 'self': &Mutex<T>
150..152 '{}': MutexGuard<'_, T>
150..152 '{}': MutexGuard<'static, T>
234..238 'self': &{unknown}
240..290 '{ ...()); }': ()
250..251 'w': &Mutex<BufWriter>
276..287 '*(w.lock())': BufWriter
278..279 'w': &Mutex<BufWriter>
278..286 'w.lock()': MutexGuard<'_, BufWriter>
278..286 'w.lock()': MutexGuard<'static, BufWriter>
"#]],
);
}

View file

@ -3092,7 +3092,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, 'static>(&Box<Foo<i32>>) -> &i32
424..446 'Foo::g...boxed)': &i32
439..445 '&boxed': &Box<Foo<i32>>
440..445 'boxed': Box<Foo<i32>>
@ -3100,7 +3100,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, 'static>(&Box<Foo<i32>>) -> &Foo<i32>
498..519 'Foo::g...boxed)': &Foo<i32>
512..518 '&boxed': &Box<Foo<i32>>
513..518 'boxed': Box<Foo<i32>>
@ -3659,7 +3659,7 @@ fn main() {
let are = "are";
let count = 10;
builtin#format_args("hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'_>
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'static>
}
"#,
);

View file

@ -9,18 +9,18 @@ use chalk_ir::{
fold::{FallibleTypeFolder, Shift},
BoundVar, DebruijnIndex,
};
use either::Either;
use hir_def::{
db::DefDatabase,
generics::{
GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
WherePredicateTypeTarget,
GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData,
TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
},
lang_item::LangItem,
resolver::{HasResolver, TypeNs},
type_ref::{TraitBoundModifier, TypeRef},
ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, ItemContainerId, Lookup,
OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId,
ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, GenericParamId, ItemContainerId,
LifetimeParamId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId,
TypeParamId,
};
use hir_expand::name::Name;
use intern::Interned;
@ -270,64 +270,130 @@ pub(crate) struct Generics {
}
impl Generics {
pub(crate) fn iter_id(&self) -> impl Iterator<Item = Either<TypeParamId, ConstParamId>> + '_ {
self.iter().map(|(id, data)| match data {
TypeOrConstParamData::TypeParamData(_) => Either::Left(TypeParamId::from_unchecked(id)),
TypeOrConstParamData::ConstParamData(_) => {
Either::Right(ConstParamId::from_unchecked(id))
}
})
pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ {
self.iter().map(|(id, _)| id)
}
/// Iterator over types and const params of self, then parent.
pub(crate) fn iter<'a>(
&'a self,
) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
let to_toc_id = |it: &'a Generics| {
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'a>)> + 'a {
let from_toc_id = |it: &'a Generics| {
move |(local_id, p): (_, &'a TypeOrConstParamData)| {
let id = TypeOrConstParamId { parent: it.def, local_id };
match p {
TypeOrConstParamData::TypeParamData(p) => (
GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)),
GenericParamDataRef::TypeParamData(p),
),
TypeOrConstParamData::ConstParamData(p) => (
GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)),
GenericParamDataRef::ConstParamData(p),
),
}
}
};
self.params.iter().map(to_toc_id(self)).chain(self.iter_parent())
let from_lt_id = |it: &'a Generics| {
move |(local_id, p): (_, &'a LifetimeParamData)| {
(
GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }),
GenericParamDataRef::LifetimeParamData(p),
)
}
};
let lt_iter = self.params.iter_lt().map(from_lt_id(self));
self.params.iter().map(from_toc_id(self)).chain(lt_iter).chain(self.iter_parent())
}
/// Iterate over types and const params without parent params.
pub(crate) fn iter_self<'a>(
&'a self,
) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
let to_toc_id = |it: &'a Generics| {
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'a>)> + 'a {
let from_toc_id = |it: &'a Generics| {
move |(local_id, p): (_, &'a TypeOrConstParamData)| {
let id = TypeOrConstParamId { parent: it.def, local_id };
match p {
TypeOrConstParamData::TypeParamData(p) => (
GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)),
GenericParamDataRef::TypeParamData(p),
),
TypeOrConstParamData::ConstParamData(p) => (
GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)),
GenericParamDataRef::ConstParamData(p),
),
}
}
};
self.params.iter().map(to_toc_id(self))
let from_lt_id = |it: &'a Generics| {
move |(local_id, p): (_, &'a LifetimeParamData)| {
(
GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }),
GenericParamDataRef::LifetimeParamData(p),
)
}
};
self.params.iter().map(from_toc_id(self)).chain(self.params.iter_lt().map(from_lt_id(self)))
}
/// Iterator over types and const params of parent.
pub(crate) fn iter_parent(
&self,
) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &TypeOrConstParamData)> {
#[allow(clippy::needless_lifetimes)]
pub(crate) fn iter_parent<'a>(
&'a self,
) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'a>)> + 'a {
self.parent_generics().into_iter().flat_map(|it| {
let to_toc_id =
move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p);
it.params.iter().map(to_toc_id)
let from_toc_id = move |(local_id, p): (_, &'a TypeOrConstParamData)| {
let id = TypeOrConstParamId { parent: it.def, local_id };
match p {
TypeOrConstParamData::TypeParamData(p) => (
GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)),
GenericParamDataRef::TypeParamData(p),
),
TypeOrConstParamData::ConstParamData(p) => (
GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)),
GenericParamDataRef::ConstParamData(p),
),
}
};
let from_lt_id = move |(local_id, p): (_, &'a LifetimeParamData)| {
(
GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }),
GenericParamDataRef::LifetimeParamData(p),
)
};
let lt_iter = it.params.iter_lt().map(from_lt_id);
it.params.iter().map(from_toc_id).chain(lt_iter)
})
}
/// Returns total number of generic parameters in scope, including those from parent.
pub(crate) fn len(&self) -> usize {
let parent = self.parent_generics().map_or(0, Generics::len);
let child = self.params.type_or_consts.len();
let child = self.params.type_or_consts.len() + self.params.lifetimes.len();
parent + child
}
/// Returns numbers of generic parameters excluding those from parent.
/// Returns numbers of generic parameters and lifetimes excluding those from parent.
pub(crate) fn len_self(&self) -> usize {
self.params.type_or_consts.len() + self.params.lifetimes.len()
}
/// Returns number of generic parameter excluding those from parent
fn len_params(&self) -> usize {
self.params.type_or_consts.len()
}
/// (parent total, self param, type param list, const param list, impl trait)
pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize) {
pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize, usize) {
let mut self_params = 0;
let mut type_params = 0;
let mut impl_trait_params = 0;
let mut const_params = 0;
let mut lifetime_params = 0;
self.params.iter().for_each(|(_, data)| match data {
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
TypeParamProvenance::TypeParamList => type_params += 1,
@ -337,8 +403,10 @@ impl Generics {
TypeOrConstParamData::ConstParamData(_) => const_params += 1,
});
self.params.iter_lt().for_each(|(_, _)| lifetime_params += 1);
let parent_len = self.parent_generics().map_or(0, Generics::len);
(parent_len, self_params, type_params, const_params, impl_trait_params)
(parent_len, self_params, type_params, const_params, impl_trait_params, lifetime_params)
}
pub(crate) fn param_idx(&self, param: TypeOrConstParamId) -> Option<usize> {
@ -358,6 +426,26 @@ impl Generics {
}
}
pub(crate) fn lifetime_idx(&self, lifetime: LifetimeParamId) -> Option<usize> {
Some(self.find_lifetime(lifetime)?.0)
}
fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option<(usize, &LifetimeParamData)> {
if lifetime.parent == self.def {
let (idx, (_local_id, data)) = self
.params
.iter_lt()
.enumerate()
.find(|(_, (idx, _))| *idx == lifetime.local_id)?;
Some((self.len_params() + idx, data))
} else {
self.parent_generics()
.and_then(|g| g.find_lifetime(lifetime))
.map(|(idx, data)| (self.len_self() + idx, data))
}
}
pub(crate) fn parent_generics(&self) -> Option<&Generics> {
self.parent_generics.as_deref()
}
@ -371,10 +459,15 @@ impl Generics {
Substitution::from_iter(
Interner,
self.iter_id().enumerate().map(|(idx, id)| match id {
Either::Left(_) => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
Either::Right(id) => BoundVar::new(debruijn, idx)
GenericParamId::ConstParamId(id) => BoundVar::new(debruijn, idx)
.to_const(Interner, db.const_param_ty(id))
.cast(Interner),
GenericParamId::TypeParamId(_) => {
BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner)
}
GenericParamId::LifetimeParamId(_) => {
BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner)
}
}),
)
}
@ -384,12 +477,15 @@ impl Generics {
Substitution::from_iter(
Interner,
self.iter_id().map(|id| match id {
Either::Left(id) => {
GenericParamId::TypeParamId(id) => {
crate::to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner)
}
Either::Right(id) => crate::to_placeholder_idx(db, id.into())
GenericParamId::ConstParamId(id) => crate::to_placeholder_idx(db, id.into())
.to_const(Interner, db.const_param_ty(id))
.cast(Interner),
GenericParamId::LifetimeParamId(id) => {
crate::lt_to_placeholder_idx(db, id).to_lifetime(Interner).cast(Interner)
}
}),
)
}

View file

@ -65,7 +65,7 @@ use hir_ty::{
consteval::{try_const_usize, unknown_const_as_generic, ConstExt},
db::InternedClosure,
diagnostics::BodyValidationDiagnostic,
known_const_to_ast,
error_lifetime, known_const_to_ast,
layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding},
method_resolution::{self, TyFingerprint},
mir::{interpret_mir, MutBorrowKind},
@ -1107,6 +1107,7 @@ impl Field {
generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner)
}
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
ParamKind::Lifetime => error_lifetime().cast(Interner),
})
.build();
let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
@ -1448,6 +1449,7 @@ impl Adt {
match x {
ParamKind::Type => r.cast(Interner),
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
ParamKind::Lifetime => error_lifetime().cast(Interner),
}
})
.build();
@ -1866,6 +1868,7 @@ impl Function {
generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner)
}
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
ParamKind::Lifetime => error_lifetime().cast(Interner),
};
let parent_substs =
@ -1964,6 +1967,7 @@ impl Function {
.unwrap_or_else(|| TyKind::Error.intern(Interner))
.cast(Interner),
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
ParamKind::Lifetime => error_lifetime().cast(Interner),
})
.build()
});
@ -2221,6 +2225,7 @@ impl SelfParam {
generics.next().unwrap_or_else(|| TyKind::Error.intern(Interner)).cast(Interner)
}
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
ParamKind::Lifetime => error_lifetime().cast(Interner),
};
let parent_substs = TyBuilder::subst_for_def(db, parent_id, None).fill(&mut filler).build();
@ -4139,6 +4144,7 @@ impl Type {
// FIXME: this code is not covered in tests.
unknown_const_as_generic(ty.clone())
}
ParamKind::Lifetime => error_lifetime().cast(Interner),
}
})
.build();
@ -4169,6 +4175,7 @@ impl Type {
match it {
ParamKind::Type => args.next().unwrap().ty.clone().cast(Interner),
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
ParamKind::Lifetime => error_lifetime().cast(Interner),
}
})
.build();

View file

@ -5617,7 +5617,7 @@ fn func<T: Debug>(i: Struct<'_, T>) {
fun_name(i);
}
fn $0fun_name(i: Struct<'_, T>) {
fn $0fun_name(i: Struct<'static, T>) {
foo(i);
}
"#,

View file

@ -614,7 +614,7 @@ struct Foo<'a, T> {
}
impl<'a, T> Foo<'a, T> {
$0fn bar(self, mut b: Vec<&'a Bar<'_, T>>) -> &'a Bar<'_, T> {
$0fn bar(self, mut b: Vec<&'a Bar<'a, T>>) -> &'a Bar<'a, T> {
self.field.bar(b)
}
}

View file

@ -19,7 +19,7 @@ struct Foo<'lt, T, const C: usize> where $0 {}
en Enum Enum
ma makro!() macro_rules! makro
md module
st Foo<> Foo<'_, {unknown}, _>
st Foo<> Foo<'static, {unknown}, _>
st Record Record
st Tuple Tuple
st Unit Unit
@ -92,7 +92,7 @@ struct Foo<'lt, T, const C: usize> where for<'a> $0 {}
en Enum Enum
ma makro!() macro_rules! makro
md module
st Foo<> Foo<'_, {unknown}, _>
st Foo<> Foo<'static, {unknown}, _>
st Record Record
st Tuple Tuple
st Unit Unit

View file

@ -20,8 +20,8 @@ struct Foo<'lt, T, const C: usize> {
en Enum Enum
ma makro!() macro_rules! makro
md module
sp Self Foo<'_, {unknown}, _>
st Foo<> Foo<'_, {unknown}, _>
sp Self Foo<'static, {unknown}, _>
st Foo<> Foo<'static, {unknown}, _>
st Record Record
st Tuple Tuple
st Unit Unit
@ -45,8 +45,8 @@ struct Foo<'lt, T, const C: usize>(f$0);
en Enum Enum
ma makro!() macro_rules! makro
md module
sp Self Foo<'_, {unknown}, _>
st Foo<> Foo<'_, {unknown}, _>
sp Self Foo<'static, {unknown}, _>
st Foo<> Foo<'static, {unknown}, _>
st Record Record
st Tuple Tuple
st Unit Unit

View file

@ -279,7 +279,8 @@ impl flags::AnalysisStats {
let mut all = 0;
let mut fail = 0;
for &a in adts {
if db.generic_params(a.into()).iter().next().is_some() {
let generic_params = db.generic_params(a.into());
if generic_params.iter().next().is_some() || generic_params.iter_lt().next().is_some() {
// Data types with generics don't have layout.
continue;
}