mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 20:43:21 +00:00
Add const generics
This commit is contained in:
parent
5e85158706
commit
b301b040f5
32 changed files with 1272 additions and 527 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -171,9 +171,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "chalk-derive"
|
||||
version = "0.76.0"
|
||||
version = "0.79.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58c24b8052ea1e3adbb6f9ab7ba5fcc18b9d12591c042de4c833f709ce81e0e0"
|
||||
checksum = "0b14364774396379d5c488e73d88e0a6d2b51acd0dac9c8359e2f84c58cf3a16"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -183,9 +183,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "chalk-ir"
|
||||
version = "0.76.0"
|
||||
version = "0.79.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cad5c3f1edd4b4a2c9bda24ae558ceb4f88336f88f944c2e35d0bfeb13c818"
|
||||
checksum = "cd571e8931d3075f562a2d460bfe3028a9c7b343876765cce95b6143a76b882e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"chalk-derive",
|
||||
|
@ -194,9 +194,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "chalk-recursive"
|
||||
version = "0.76.0"
|
||||
version = "0.79.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e68ba0c7219f34738b66c0c992438c644ca33f4d8a29da3d41604299c7eaf419"
|
||||
checksum = "54ceedab35607f4680d02de80f8be005af0ad5c1dcfec56cfd849d33da5fe736"
|
||||
dependencies = [
|
||||
"chalk-derive",
|
||||
"chalk-ir",
|
||||
|
@ -207,9 +207,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "chalk-solve"
|
||||
version = "0.76.0"
|
||||
version = "0.79.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94533188d3452bc72cbd5618d166f45fc7646b674ad3fe9667d557bc25236dee"
|
||||
checksum = "9e31bb853cf921365759346db05d833f969e330462432bf38c9c2be1e78a9abd"
|
||||
dependencies = [
|
||||
"chalk-derive",
|
||||
"chalk-ir",
|
||||
|
|
|
@ -256,7 +256,7 @@ impl HirDisplay for TypeParam {
|
|||
}
|
||||
|
||||
let bounds = f.db.generic_predicates_for_param(self.id.parent(), self.id.into(), None);
|
||||
let substs = TyBuilder::type_params_subst(f.db, self.id.parent());
|
||||
let substs = TyBuilder::placeholder_subst(f.db, self.id.parent());
|
||||
let predicates: Vec<_> =
|
||||
bounds.iter().cloned().map(|b| b.substitute(Interner, &substs)).collect();
|
||||
let krate = self.id.parent().krate(f.db).id;
|
||||
|
@ -292,8 +292,9 @@ impl HirDisplay for ConstParam {
|
|||
fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
let params = f.db.generic_params(def);
|
||||
if params.lifetimes.is_empty()
|
||||
&& params.type_or_consts.iter().all(|x| x.1.const_param().is_none())
|
||||
&& params
|
||||
.tocs
|
||||
.type_or_consts
|
||||
.iter()
|
||||
.filter_map(|x| x.1.type_param())
|
||||
.all(|param| !matches!(param.provenance, TypeParamProvenance::TypeParamList))
|
||||
|
@ -315,7 +316,7 @@ fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), H
|
|||
delim(f)?;
|
||||
write!(f, "{}", lifetime.name)?;
|
||||
}
|
||||
for (_, ty) in params.tocs.iter() {
|
||||
for (_, ty) in params.type_or_consts.iter() {
|
||||
if let Some(name) = &ty.name() {
|
||||
match ty {
|
||||
TypeOrConstParamData::TypeParamData(ty) => {
|
||||
|
@ -348,7 +349,9 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter) -> Result<(), Hir
|
|||
// unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
|
||||
let is_unnamed_type_target = |target: &WherePredicateTypeTarget| match target {
|
||||
WherePredicateTypeTarget::TypeRef(_) => false,
|
||||
WherePredicateTypeTarget::TypeOrConstParam(id) => params.tocs[*id].name().is_none(),
|
||||
WherePredicateTypeTarget::TypeOrConstParam(id) => {
|
||||
params.type_or_consts[*id].name().is_none()
|
||||
}
|
||||
};
|
||||
|
||||
let has_displayable_predicate = params
|
||||
|
@ -364,10 +367,12 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter) -> Result<(), Hir
|
|||
|
||||
let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter| match target {
|
||||
WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
|
||||
WherePredicateTypeTarget::TypeOrConstParam(id) => match ¶ms.tocs[*id].name() {
|
||||
WherePredicateTypeTarget::TypeOrConstParam(id) => {
|
||||
match ¶ms.type_or_consts[*id].name() {
|
||||
Some(name) => write!(f, "{}", name),
|
||||
None => write!(f, "{{unnamed}}"),
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
write!(f, "\nwhere")?;
|
||||
|
|
|
@ -55,7 +55,9 @@ use hir_def::{
|
|||
use hir_expand::{name::name, MacroCallKind};
|
||||
use hir_ty::{
|
||||
autoderef,
|
||||
consteval::{eval_const, ComputedExpr, ConstEvalCtx, ConstEvalError, ConstExt},
|
||||
consteval::{
|
||||
eval_const, unknown_const_as_generic, ComputedExpr, ConstEvalCtx, ConstEvalError, ConstExt,
|
||||
},
|
||||
could_unify,
|
||||
diagnostics::BodyValidationDiagnostic,
|
||||
method_resolution::{self, TyFingerprint},
|
||||
|
@ -63,9 +65,9 @@ use hir_ty::{
|
|||
subst_prefix,
|
||||
traits::FnTrait,
|
||||
AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
|
||||
DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, Substitution,
|
||||
TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind,
|
||||
WhereClause,
|
||||
DebruijnIndex, GenericArgData, InEnvironment, Interner, ParamKind, QuantifiedWhereClause,
|
||||
Scalar, Solution, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt,
|
||||
TyKind, TyVariableKind, WhereClause,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use nameres::diagnostics::DefDiagnosticKind;
|
||||
|
@ -796,7 +798,7 @@ impl Field {
|
|||
VariantDef::Union(it) => it.id.into(),
|
||||
VariantDef::Variant(it) => it.parent.id.into(),
|
||||
};
|
||||
let substs = TyBuilder::type_params_subst(db, generic_def_id);
|
||||
let substs = TyBuilder::placeholder_subst(db, generic_def_id);
|
||||
let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
|
||||
Type::new(db, self.parent.module(db).id.krate(), var_id, ty)
|
||||
}
|
||||
|
@ -983,7 +985,10 @@ impl_from!(Struct, Union, Enum for Adt);
|
|||
impl Adt {
|
||||
pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
|
||||
let subst = db.generic_defaults(self.into());
|
||||
subst.iter().any(|ty| ty.skip_binders().is_unknown())
|
||||
subst.iter().any(|ty| match ty.skip_binders().data(Interner) {
|
||||
GenericArgData::Ty(x) => x.is_unknown(),
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Turns this ADT into a type. Any type parameters of the ADT will be
|
||||
|
@ -1680,7 +1685,10 @@ pub struct TypeAlias {
|
|||
impl TypeAlias {
|
||||
pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
|
||||
let subst = db.generic_defaults(self.id.into());
|
||||
subst.iter().any(|ty| ty.skip_binders().is_unknown())
|
||||
subst.iter().any(|ty| match ty.skip_binders().data(Interner) {
|
||||
GenericArgData::Ty(x) => x.is_unknown(),
|
||||
_ => false,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn module(self, db: &dyn HirDatabase) -> Module {
|
||||
|
@ -2047,7 +2055,7 @@ impl_from!(
|
|||
impl GenericDef {
|
||||
pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
|
||||
let generics = db.generic_params(self.into());
|
||||
let ty_params = generics.tocs.iter().map(|(local_id, _)| {
|
||||
let ty_params = generics.type_or_consts.iter().map(|(local_id, _)| {
|
||||
let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } };
|
||||
match toc.split(db) {
|
||||
Either::Left(x) => GenericParam::ConstParam(x),
|
||||
|
@ -2067,7 +2075,7 @@ impl GenericDef {
|
|||
pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
|
||||
let generics = db.generic_params(self.into());
|
||||
generics
|
||||
.tocs
|
||||
.type_or_consts
|
||||
.iter()
|
||||
.map(|(local_id, _)| TypeOrConstParam {
|
||||
id: TypeOrConstParamId { parent: self.into(), local_id },
|
||||
|
@ -2351,9 +2359,14 @@ impl TypeParam {
|
|||
let resolver = self.id.parent().resolver(db.upcast());
|
||||
let krate = self.id.parent().module(db.upcast()).krate();
|
||||
let ty = params.get(local_idx)?.clone();
|
||||
let subst = TyBuilder::type_params_subst(db, self.id.parent());
|
||||
let subst = TyBuilder::placeholder_subst(db, self.id.parent());
|
||||
let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx));
|
||||
Some(Type::new_with_resolver_inner(db, krate, &resolver, ty))
|
||||
match ty.data(Interner) {
|
||||
GenericArgData::Ty(x) => {
|
||||
Some(Type::new_with_resolver_inner(db, krate, &resolver, x.clone()))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2389,7 +2402,7 @@ impl ConstParam {
|
|||
|
||||
pub fn name(self, db: &dyn HirDatabase) -> Name {
|
||||
let params = db.generic_params(self.id.parent());
|
||||
match params.tocs[self.id.local_id()].name() {
|
||||
match params.type_or_consts[self.id.local_id()].name() {
|
||||
Some(x) => x.clone(),
|
||||
None => {
|
||||
never!();
|
||||
|
@ -2421,7 +2434,7 @@ pub struct TypeOrConstParam {
|
|||
impl TypeOrConstParam {
|
||||
pub fn name(self, db: &dyn HirDatabase) -> Name {
|
||||
let params = db.generic_params(self.id.parent);
|
||||
match params.tocs[self.id.local_id].name() {
|
||||
match params.type_or_consts[self.id.local_id].name() {
|
||||
Some(n) => n.clone(),
|
||||
_ => Name::missing(),
|
||||
}
|
||||
|
@ -2437,12 +2450,12 @@ impl TypeOrConstParam {
|
|||
|
||||
pub fn split(self, db: &dyn HirDatabase) -> Either<ConstParam, TypeParam> {
|
||||
let params = db.generic_params(self.id.parent);
|
||||
match ¶ms.tocs[self.id.local_id] {
|
||||
match ¶ms.type_or_consts[self.id.local_id] {
|
||||
hir_def::generics::TypeOrConstParamData::TypeParamData(_) => {
|
||||
Either::Right(TypeParam { id: self.id.into() })
|
||||
Either::Right(TypeParam { id: TypeParamId::from_unchecked(self.id) })
|
||||
}
|
||||
hir_def::generics::TypeOrConstParamData::ConstParamData(_) => {
|
||||
Either::Left(ConstParam { id: self.id.into() })
|
||||
Either::Left(ConstParam { id: ConstParamId::from_unchecked(self.id) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2688,9 +2701,19 @@ impl Type {
|
|||
}
|
||||
|
||||
pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
|
||||
let mut it = args.iter().map(|t| t.ty.clone());
|
||||
let trait_ref = TyBuilder::trait_ref(db, trait_.id)
|
||||
.push(self.ty.clone())
|
||||
.fill(args.iter().map(|t| t.ty.clone()))
|
||||
.fill(|x| {
|
||||
let r = it.next().unwrap();
|
||||
match x {
|
||||
ParamKind::Type => GenericArgData::Ty(r).intern(Interner),
|
||||
ParamKind::Const(ty) => {
|
||||
// FIXME: this code is not covered in tests.
|
||||
unknown_const_as_generic(ty.clone())
|
||||
}
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
let goal = Canonical {
|
||||
|
@ -2707,9 +2730,18 @@ impl Type {
|
|||
args: &[Type],
|
||||
alias: TypeAlias,
|
||||
) -> Option<Type> {
|
||||
let mut args = args.iter();
|
||||
let projection = TyBuilder::assoc_type_projection(db, alias.id)
|
||||
.push(self.ty.clone())
|
||||
.fill(args.iter().map(|t| t.ty.clone()))
|
||||
.fill(|x| {
|
||||
// FIXME: this code is not covered in tests.
|
||||
match x {
|
||||
ParamKind::Type => {
|
||||
GenericArgData::Ty(args.next().unwrap().ty.clone()).intern(Interner)
|
||||
}
|
||||
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
|
||||
}
|
||||
})
|
||||
.build();
|
||||
let goal = hir_ty::make_canonical(
|
||||
InEnvironment::new(
|
||||
|
|
|
@ -279,7 +279,7 @@ impl SourceToDefCtx<'_, '_> {
|
|||
pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> {
|
||||
let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into();
|
||||
let dyn_map = self.cache_for(container, src.file_id);
|
||||
dyn_map[keys::TYPE_PARAM].get(&src.value).copied().map(|x| x.into())
|
||||
dyn_map[keys::TYPE_PARAM].get(&src.value).copied().map(|x| TypeParamId::from_unchecked(x))
|
||||
}
|
||||
|
||||
pub(super) fn lifetime_param_to_def(
|
||||
|
@ -297,7 +297,7 @@ impl SourceToDefCtx<'_, '_> {
|
|||
) -> Option<ConstParamId> {
|
||||
let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into();
|
||||
let dyn_map = self.cache_for(container, src.file_id);
|
||||
dyn_map[keys::CONST_PARAM].get(&src.value).copied().map(|x| x.into())
|
||||
dyn_map[keys::CONST_PARAM].get(&src.value).copied().map(|x| ConstParamId::from_unchecked(x))
|
||||
}
|
||||
|
||||
pub(super) fn generic_param_to_def(
|
||||
|
|
|
@ -24,8 +24,8 @@ use crate::{
|
|||
keys,
|
||||
src::{HasChildSource, HasSource},
|
||||
type_ref::{LifetimeRef, TypeBound, TypeRef},
|
||||
AdtId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId, LocalTypeOrConstParamId,
|
||||
Lookup, TypeOrConstParamId,
|
||||
AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId,
|
||||
LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
|
||||
};
|
||||
|
||||
/// Data about a generic type parameter (to a function, struct, impl, ...).
|
||||
|
@ -99,7 +99,7 @@ impl_from!(TypeParamData, ConstParamData for TypeOrConstParamData);
|
|||
/// Data about the generic parameters of a function, struct, impl, etc.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Default, Hash)]
|
||||
pub struct GenericParams {
|
||||
pub tocs: Arena<TypeOrConstParamData>,
|
||||
pub type_or_consts: Arena<TypeOrConstParamData>,
|
||||
pub lifetimes: Arena<LifetimeParamData>,
|
||||
pub where_predicates: Vec<WherePredicate>,
|
||||
}
|
||||
|
@ -138,13 +138,14 @@ impl GenericParams {
|
|||
pub fn type_iter<'a>(
|
||||
&'a self,
|
||||
) -> impl Iterator<Item = (Idx<TypeOrConstParamData>, &TypeParamData)> {
|
||||
self.tocs.iter().filter_map(|x| x.1.type_param().map(|y| (x.0, y)))
|
||||
self.type_or_consts.iter().filter_map(|x| x.1.type_param().map(|y| (x.0, y)))
|
||||
}
|
||||
|
||||
pub fn toc_iter<'a>(
|
||||
/// Iterator of type_or_consts field
|
||||
pub fn iter<'a>(
|
||||
&'a self,
|
||||
) -> impl Iterator<Item = (Idx<TypeOrConstParamData>, &TypeOrConstParamData)> {
|
||||
self.tocs.iter()
|
||||
) -> impl DoubleEndedIterator<Item = (Idx<TypeOrConstParamData>, &TypeOrConstParamData)> {
|
||||
self.type_or_consts.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn generic_params_query(
|
||||
|
@ -251,7 +252,7 @@ impl GenericParams {
|
|||
default,
|
||||
provenance: TypeParamProvenance::TypeParamList,
|
||||
};
|
||||
self.tocs.alloc(param.into());
|
||||
self.type_or_consts.alloc(param.into());
|
||||
let type_ref = TypeRef::Path(name.into());
|
||||
self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref));
|
||||
}
|
||||
|
@ -261,7 +262,7 @@ impl GenericParams {
|
|||
.ty()
|
||||
.map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
|
||||
let param = ConstParamData { name, ty: Interned::new(ty) };
|
||||
self.tocs.alloc(param.into());
|
||||
self.type_or_consts.alloc(param.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -348,7 +349,7 @@ impl GenericParams {
|
|||
default: None,
|
||||
provenance: TypeParamProvenance::ArgumentImplTrait,
|
||||
};
|
||||
let param_id = self.tocs.alloc(param.into());
|
||||
let param_id = self.type_or_consts.alloc(param.into());
|
||||
for bound in bounds {
|
||||
self.where_predicates.push(WherePredicate::TypeBound {
|
||||
target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
|
||||
|
@ -372,27 +373,34 @@ impl GenericParams {
|
|||
}
|
||||
|
||||
pub(crate) fn shrink_to_fit(&mut self) {
|
||||
let Self { lifetimes, tocs: types, where_predicates } = self;
|
||||
let Self { lifetimes, type_or_consts: types, where_predicates } = self;
|
||||
lifetimes.shrink_to_fit();
|
||||
types.shrink_to_fit();
|
||||
where_predicates.shrink_to_fit();
|
||||
}
|
||||
|
||||
pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeOrConstParamId> {
|
||||
self.tocs
|
||||
.iter()
|
||||
.filter(|x| matches!(x.1, TypeOrConstParamData::TypeParamData(_)))
|
||||
.find_map(|(id, p)| if p.name().as_ref() == Some(&name) { Some(id) } else { None })
|
||||
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() {
|
||||
Some(TypeParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn find_type_or_const_by_name(&self, name: &Name) -> Option<LocalTypeOrConstParamId> {
|
||||
self.tocs
|
||||
.iter()
|
||||
.find_map(|(id, p)| if p.name().as_ref() == Some(&name) { Some(id) } else { None })
|
||||
pub fn find_const_by_name(&self, name: &Name, parent: GenericDefId) -> Option<ConstParamId> {
|
||||
self.type_or_consts.iter().find_map(|(id, p)| {
|
||||
if p.name().as_ref() == Some(&name) && p.const_param().is_some() {
|
||||
Some(ConstParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn find_trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
|
||||
self.tocs.iter().find_map(|(id, p)| {
|
||||
self.type_or_consts.iter().find_map(|(id, p)| {
|
||||
if let TypeOrConstParamData::TypeParamData(p) = p {
|
||||
if p.provenance == TypeParamProvenance::TraitSelf {
|
||||
Some(id)
|
||||
|
@ -451,7 +459,7 @@ impl HasChildSource<LocalTypeOrConstParamId> for GenericDefId {
|
|||
db: &dyn DefDatabase,
|
||||
) -> InFile<ArenaMap<LocalTypeOrConstParamId, Self::Value>> {
|
||||
let generic_params = db.generic_params(*self);
|
||||
let mut idx_iter = generic_params.tocs.iter().map(|(idx, _)| idx);
|
||||
let mut idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx);
|
||||
|
||||
let (file_id, generic_params_list) = file_id_and_params_of(*self, db);
|
||||
|
||||
|
@ -505,7 +513,7 @@ impl ChildBySource for GenericDefId {
|
|||
}
|
||||
|
||||
let generic_params = db.generic_params(*self);
|
||||
let mut toc_idx_iter = generic_params.tocs.iter().map(|(idx, _)| idx);
|
||||
let mut toc_idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx);
|
||||
let lts_idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx);
|
||||
|
||||
// For traits the first type index is `Self`, skip it.
|
||||
|
|
|
@ -582,7 +582,7 @@ impl<'a> Ctx<'a> {
|
|||
}
|
||||
GenericsOwner::Trait(trait_def) => {
|
||||
// traits get the Self type as an implicit first type parameter
|
||||
generics.tocs.alloc(
|
||||
generics.type_or_consts.alloc(
|
||||
TypeParamData {
|
||||
name: Some(name![Self]),
|
||||
default: None,
|
||||
|
|
|
@ -621,12 +621,13 @@ impl<'a> Printer<'a> {
|
|||
fn print_generic_arg(&mut self, arg: &GenericArg) {
|
||||
match arg {
|
||||
GenericArg::Type(ty) => self.print_type_ref(ty),
|
||||
GenericArg::Const(c) => w!(self, "{}", c),
|
||||
GenericArg::Lifetime(lt) => w!(self, "{}", lt.name),
|
||||
}
|
||||
}
|
||||
|
||||
fn print_generic_params(&mut self, params: &GenericParams) {
|
||||
if params.tocs.is_empty() && params.lifetimes.is_empty() {
|
||||
if params.type_or_consts.is_empty() && params.lifetimes.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -639,7 +640,7 @@ impl<'a> Printer<'a> {
|
|||
first = false;
|
||||
w!(self, "{}", lt.name);
|
||||
}
|
||||
for (idx, x) in params.tocs.iter() {
|
||||
for (idx, x) in params.type_or_consts.iter() {
|
||||
if !first {
|
||||
w!(self, ", ");
|
||||
}
|
||||
|
@ -701,7 +702,7 @@ impl<'a> Printer<'a> {
|
|||
match target {
|
||||
WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
|
||||
WherePredicateTypeTarget::TypeOrConstParam(id) => {
|
||||
match ¶ms.tocs[*id].name() {
|
||||
match ¶ms.type_or_consts[*id].name() {
|
||||
Some(name) => w!(this, "{}", name),
|
||||
None => w!(this, "_anon_{}", id.into_raw()),
|
||||
}
|
||||
|
|
|
@ -343,11 +343,13 @@ impl TypeParamId {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<TypeOrConstParamId> for TypeParamId {
|
||||
fn from(x: TypeOrConstParamId) -> Self {
|
||||
impl TypeParamId {
|
||||
/// Caller should check if this toc id really belongs to a type
|
||||
pub fn from_unchecked(x: TypeOrConstParamId) -> Self {
|
||||
Self(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TypeParamId> for TypeOrConstParamId {
|
||||
fn from(x: TypeParamId) -> Self {
|
||||
x.0
|
||||
|
@ -367,11 +369,13 @@ impl ConstParamId {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<TypeOrConstParamId> for ConstParamId {
|
||||
fn from(x: TypeOrConstParamId) -> Self {
|
||||
impl ConstParamId {
|
||||
/// Caller should check if this toc id really belongs to a const
|
||||
pub fn from_unchecked(x: TypeOrConstParamId) -> Self {
|
||||
Self(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConstParamId> for TypeOrConstParamId {
|
||||
fn from(x: ConstParamId) -> Self {
|
||||
x.0
|
||||
|
|
|
@ -6,7 +6,11 @@ use std::{
|
|||
iter,
|
||||
};
|
||||
|
||||
use crate::{body::LowerCtx, intern::Interned, type_ref::LifetimeRef};
|
||||
use crate::{
|
||||
body::LowerCtx,
|
||||
intern::Interned,
|
||||
type_ref::{ConstScalarOrPath, LifetimeRef},
|
||||
};
|
||||
use hir_expand::name::{name, Name};
|
||||
use syntax::ast;
|
||||
|
||||
|
@ -78,6 +82,7 @@ pub struct AssociatedTypeBinding {
|
|||
pub enum GenericArg {
|
||||
Type(TypeRef),
|
||||
Lifetime(LifetimeRef),
|
||||
Const(ConstScalarOrPath),
|
||||
}
|
||||
|
||||
impl Path {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Transforms syntax into `Path` objects, ideally with accounting for hygiene
|
||||
|
||||
use crate::intern::Interned;
|
||||
use crate::{intern::Interned, type_ref::ConstScalarOrPath};
|
||||
|
||||
use either::Either;
|
||||
use hir_expand::name::{name, AsName};
|
||||
|
@ -180,8 +180,10 @@ pub(super) fn lower_generic_args(
|
|||
args.push(GenericArg::Lifetime(lifetime_ref))
|
||||
}
|
||||
}
|
||||
// constants are ignored for now.
|
||||
ast::GenericArg::ConstArg(_) => (),
|
||||
ast::GenericArg::ConstArg(arg) => {
|
||||
let arg = ConstScalarOrPath::from_expr_opt(arg.expr());
|
||||
args.push(GenericArg::Const(arg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -189,14 +189,9 @@ impl Resolver {
|
|||
Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue,
|
||||
|
||||
Scope::GenericParams { params, def } => {
|
||||
if let Some(local_id) = params.find_type_by_name(first_name) {
|
||||
if let Some(id) = params.find_type_by_name(first_name, *def) {
|
||||
let idx = if path.segments().len() == 1 { None } else { Some(1) };
|
||||
return Some((
|
||||
TypeNs::GenericParam(
|
||||
TypeOrConstParamId { local_id, parent: *def }.into(),
|
||||
),
|
||||
idx,
|
||||
));
|
||||
return Some((TypeNs::GenericParam(id), idx));
|
||||
}
|
||||
}
|
||||
Scope::ImplDefScope(impl_) => {
|
||||
|
@ -284,18 +279,14 @@ impl Resolver {
|
|||
Scope::ExprScope(_) => continue,
|
||||
|
||||
Scope::GenericParams { params, def } if n_segments > 1 => {
|
||||
if let Some(local_id) = params.find_type_or_const_by_name(first_name) {
|
||||
let ty = TypeNs::GenericParam(
|
||||
TypeOrConstParamId { local_id, parent: *def }.into(),
|
||||
);
|
||||
if let Some(id) = params.find_type_by_name(first_name, *def) {
|
||||
let ty = TypeNs::GenericParam(id);
|
||||
return Some(ResolveValueResult::Partial(ty, 1));
|
||||
}
|
||||
}
|
||||
Scope::GenericParams { params, def } if n_segments == 1 => {
|
||||
if let Some(local_id) = params.find_type_or_const_by_name(first_name) {
|
||||
let val = ValueNs::GenericParam(
|
||||
TypeOrConstParamId { local_id, parent: *def }.into(),
|
||||
);
|
||||
if let Some(id) = params.find_const_by_name(first_name, *def) {
|
||||
let val = ValueNs::GenericParam(id);
|
||||
return Some(ResolveValueResult::ValueNs(val));
|
||||
}
|
||||
}
|
||||
|
@ -518,18 +509,18 @@ impl Scope {
|
|||
}
|
||||
Scope::GenericParams { params, def: parent } => {
|
||||
let parent = *parent;
|
||||
for (local_id, param) in params.tocs.iter() {
|
||||
for (local_id, param) in params.type_or_consts.iter() {
|
||||
if let Some(name) = ¶m.name() {
|
||||
let id = TypeOrConstParamId { parent, local_id };
|
||||
let data = &db.generic_params(parent).tocs[local_id];
|
||||
let data = &db.generic_params(parent).type_or_consts[local_id];
|
||||
acc.add(
|
||||
name,
|
||||
ScopeDef::GenericParam(match data {
|
||||
TypeOrConstParamData::TypeParamData(_) => {
|
||||
GenericParamId::TypeParamId(id.into())
|
||||
GenericParamId::TypeParamId(TypeParamId::from_unchecked(id))
|
||||
}
|
||||
TypeOrConstParamData::ConstParamData(_) => {
|
||||
GenericParamId::ConstParamId(id.into())
|
||||
GenericParamId::ConstParamId(ConstParamId::from_unchecked(id))
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -89,7 +89,7 @@ pub enum TypeRef {
|
|||
Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
|
||||
// FIXME: for full const generics, the latter element (length) here is going to have to be an
|
||||
// expression that is further lowered later in hir_ty.
|
||||
Array(Box<TypeRef>, ConstScalar),
|
||||
Array(Box<TypeRef>, ConstScalarOrPath),
|
||||
Slice(Box<TypeRef>),
|
||||
/// A fn pointer. Last element of the vector is the return type.
|
||||
Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/),
|
||||
|
@ -162,10 +162,7 @@ impl TypeRef {
|
|||
// `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the
|
||||
// `hir_ty` level, which would allow knowing the type of:
|
||||
// let v: [u8; 2 + 2] = [0u8; 4];
|
||||
let len = inner
|
||||
.expr()
|
||||
.map(ConstScalar::usize_from_literal_expr)
|
||||
.unwrap_or(ConstScalar::Unknown);
|
||||
let len = ConstScalarOrPath::from_expr_opt(inner.expr());
|
||||
|
||||
TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len)
|
||||
}
|
||||
|
@ -278,7 +275,8 @@ impl TypeRef {
|
|||
crate::path::GenericArg::Type(type_ref) => {
|
||||
go(type_ref, f);
|
||||
}
|
||||
crate::path::GenericArg::Lifetime(_) => {}
|
||||
crate::path::GenericArg::Const(_)
|
||||
| crate::path::GenericArg::Lifetime(_) => {}
|
||||
}
|
||||
}
|
||||
for binding in &args_and_bindings.bindings {
|
||||
|
@ -357,6 +355,60 @@ impl TypeBound {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum ConstScalarOrPath {
|
||||
Scalar(ConstScalar),
|
||||
Path(Name),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ConstScalarOrPath {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ConstScalarOrPath::Scalar(s) => write!(f, "{}", s),
|
||||
ConstScalarOrPath::Path(n) => write!(f, "{}", n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConstScalarOrPath {
|
||||
pub(crate) fn from_expr_opt(expr: Option<ast::Expr>) -> Self {
|
||||
match expr {
|
||||
Some(x) => Self::from_expr(x),
|
||||
None => Self::Scalar(ConstScalar::Unknown),
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this
|
||||
// parse stage.
|
||||
fn from_expr(expr: ast::Expr) -> Self {
|
||||
match expr {
|
||||
ast::Expr::PathExpr(p) => {
|
||||
match p.path().and_then(|x| x.segment()).and_then(|x| x.name_ref()) {
|
||||
Some(x) => Self::Path(x.as_name()),
|
||||
None => Self::Scalar(ConstScalar::Unknown),
|
||||
}
|
||||
}
|
||||
ast::Expr::Literal(lit) => {
|
||||
let lkind = lit.kind();
|
||||
match lkind {
|
||||
ast::LiteralKind::IntNumber(num)
|
||||
if num.suffix() == None || num.suffix() == Some("usize") =>
|
||||
{
|
||||
Self::Scalar(
|
||||
num.value()
|
||||
.and_then(|v| v.try_into().ok())
|
||||
.map(ConstScalar::Usize)
|
||||
.unwrap_or(ConstScalar::Unknown),
|
||||
)
|
||||
}
|
||||
_ => Self::Scalar(ConstScalar::Unknown),
|
||||
}
|
||||
}
|
||||
_ => Self::Scalar(ConstScalar::Unknown),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A concrete constant value
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ConstScalar {
|
||||
|
@ -389,25 +441,4 @@ impl ConstScalar {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this
|
||||
// parse stage.
|
||||
fn usize_from_literal_expr(expr: ast::Expr) -> ConstScalar {
|
||||
match expr {
|
||||
ast::Expr::Literal(lit) => {
|
||||
let lkind = lit.kind();
|
||||
match lkind {
|
||||
ast::LiteralKind::IntNumber(num)
|
||||
if num.suffix() == None || num.suffix() == Some("usize") =>
|
||||
{
|
||||
num.value().and_then(|v| v.try_into().ok())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
.map(ConstScalar::Usize)
|
||||
.unwrap_or(ConstScalar::Unknown)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ ena = "0.14.0"
|
|||
tracing = "0.1"
|
||||
rustc-hash = "1.1.0"
|
||||
scoped-tls = "1"
|
||||
chalk-solve = { version = "0.76", default-features = false }
|
||||
chalk-ir = "0.76"
|
||||
chalk-recursive = { version = "0.76", default-features = false }
|
||||
chalk-solve = { version = "0.79", default-features = false }
|
||||
chalk-ir = "0.79"
|
||||
chalk-recursive = { version = "0.79", default-features = false }
|
||||
la-arena = { version = "0.3.0", path = "../../lib/arena" }
|
||||
once_cell = { version = "1.5.0" }
|
||||
typed-arena = "2.0.1"
|
||||
|
|
|
@ -8,67 +8,136 @@ use chalk_ir::{
|
|||
interner::HasInterner,
|
||||
AdtId, BoundVar, DebruijnIndex, Scalar,
|
||||
};
|
||||
use hir_def::{builtin_type::BuiltinType, GenericDefId, TraitId, TypeAliasId};
|
||||
use hir_def::{
|
||||
builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, GenericDefId, TraitId,
|
||||
TypeAliasId,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders,
|
||||
CallableSig, GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt,
|
||||
TyKind, ValueTyDefId,
|
||||
consteval::unknown_const_as_generic, db::HirDatabase, primitive, to_assoc_type_id,
|
||||
to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData, ConstValue, GenericArg,
|
||||
GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
|
||||
ValueTyDefId,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ParamKind {
|
||||
Type,
|
||||
Const(Ty),
|
||||
}
|
||||
|
||||
/// This is a builder for `Ty` or anything that needs a `Substitution`.
|
||||
pub struct TyBuilder<D> {
|
||||
/// The `data` field is used to keep track of what we're building (e.g. an
|
||||
/// ADT, a `TraitRef`, ...).
|
||||
data: D,
|
||||
vec: SmallVec<[GenericArg; 2]>,
|
||||
param_count: usize,
|
||||
param_kinds: SmallVec<[ParamKind; 2]>,
|
||||
}
|
||||
|
||||
impl<A> TyBuilder<A> {
|
||||
fn with_data<B>(self, data: B) -> TyBuilder<B> {
|
||||
TyBuilder { data, param_kinds: self.param_kinds, vec: self.vec }
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> TyBuilder<D> {
|
||||
fn new(data: D, param_count: usize) -> TyBuilder<D> {
|
||||
TyBuilder { data, param_count, vec: SmallVec::with_capacity(param_count) }
|
||||
fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder<D> {
|
||||
TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds }
|
||||
}
|
||||
|
||||
fn build_internal(self) -> (D, Substitution) {
|
||||
assert_eq!(self.vec.len(), self.param_count);
|
||||
assert_eq!(self.vec.len(), self.param_kinds.len());
|
||||
for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
|
||||
self.assert_match_kind(a, e);
|
||||
}
|
||||
let subst = Substitution::from_iter(Interner, self.vec);
|
||||
(self.data, subst)
|
||||
}
|
||||
|
||||
pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
|
||||
self.vec.push(arg.cast(Interner));
|
||||
let arg = arg.cast(Interner);
|
||||
let expected_kind = &self.param_kinds[self.vec.len()];
|
||||
let arg_kind = match arg.data(Interner) {
|
||||
chalk_ir::GenericArgData::Ty(_) => ParamKind::Type,
|
||||
chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
|
||||
chalk_ir::GenericArgData::Const(c) => {
|
||||
let c = c.data(Interner);
|
||||
ParamKind::Const(c.ty.clone())
|
||||
}
|
||||
};
|
||||
assert_eq!(*expected_kind, arg_kind);
|
||||
self.vec.push(arg);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn remaining(&self) -> usize {
|
||||
self.param_count - self.vec.len()
|
||||
self.param_kinds.len() - self.vec.len()
|
||||
}
|
||||
|
||||
pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
|
||||
self.fill(
|
||||
(starting_from..)
|
||||
.map(|idx| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner)),
|
||||
// self.fill is inlined to make borrow checker happy
|
||||
let mut this = self;
|
||||
let other = this.param_kinds.iter().skip(this.vec.len());
|
||||
let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
|
||||
ParamKind::Type => {
|
||||
GenericArgData::Ty(TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner))
|
||||
.intern(Interner)
|
||||
}
|
||||
ParamKind::Const(ty) => GenericArgData::Const(
|
||||
ConstData {
|
||||
value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
|
||||
ty: ty.clone(),
|
||||
}
|
||||
.intern(Interner),
|
||||
)
|
||||
.intern(Interner),
|
||||
});
|
||||
this.vec.extend(filler.take(this.remaining()).casted(Interner));
|
||||
assert_eq!(this.remaining(), 0);
|
||||
this
|
||||
}
|
||||
|
||||
pub fn fill_with_unknown(self) -> Self {
|
||||
self.fill(iter::repeat(TyKind::Error.intern(Interner)))
|
||||
// self.fill is inlined to make borrow checker happy
|
||||
let mut this = self;
|
||||
let filler = this.param_kinds.iter().skip(this.vec.len()).map(|x| match x {
|
||||
ParamKind::Type => GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner),
|
||||
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
|
||||
});
|
||||
this.vec.extend(filler.casted(Interner));
|
||||
assert_eq!(this.remaining(), 0);
|
||||
this
|
||||
}
|
||||
|
||||
pub fn fill(mut self, filler: impl Iterator<Item = impl CastTo<GenericArg>>) -> Self {
|
||||
self.vec.extend(filler.take(self.remaining()).casted(Interner));
|
||||
pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
|
||||
self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler));
|
||||
assert_eq!(self.remaining(), 0);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
|
||||
assert!(self.vec.is_empty());
|
||||
assert!(parent_substs.len(Interner) <= self.param_count);
|
||||
self.vec.extend(parent_substs.iter(Interner).cloned());
|
||||
assert!(parent_substs.len(Interner) <= self.param_kinds.len());
|
||||
self.extend(parent_substs.iter(Interner).cloned());
|
||||
self
|
||||
}
|
||||
|
||||
fn extend(&mut self, it: impl Iterator<Item = GenericArg> + Clone) {
|
||||
for x in it.clone().zip(self.param_kinds.iter().skip(self.vec.len())) {
|
||||
self.assert_match_kind(&x.0, &x.1);
|
||||
}
|
||||
self.vec.extend(it);
|
||||
}
|
||||
|
||||
fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
|
||||
match (a.data(Interner), e) {
|
||||
(chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
|
||||
| (chalk_ir::GenericArgData::Const(_), ParamKind::Const(_)) => (),
|
||||
_ => panic!("Mismatched kinds: {:?}, {:?}, {:?}", a, self.vec, self.param_kinds),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TyBuilder<()> {
|
||||
|
@ -101,16 +170,26 @@ impl TyBuilder<()> {
|
|||
TyKind::Slice(argument).intern(Interner)
|
||||
}
|
||||
|
||||
pub fn type_params_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
|
||||
pub fn placeholder_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
|
||||
let params = generics(db.upcast(), def.into());
|
||||
params.type_params_subst(db)
|
||||
params.placeholder_subst(db)
|
||||
}
|
||||
|
||||
pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> {
|
||||
let def = def.into();
|
||||
let params = generics(db.upcast(), def);
|
||||
let param_count = params.len();
|
||||
TyBuilder::new((), param_count)
|
||||
TyBuilder::new(
|
||||
(),
|
||||
params
|
||||
.iter()
|
||||
.map(|(id, data)| match data {
|
||||
TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
|
||||
TypeOrConstParamData::ConstParamData(_) => {
|
||||
ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn build(self) -> Substitution {
|
||||
|
@ -120,10 +199,8 @@ impl TyBuilder<()> {
|
|||
}
|
||||
|
||||
impl TyBuilder<hir_def::AdtId> {
|
||||
pub fn adt(db: &dyn HirDatabase, adt: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
|
||||
let generics = generics(db.upcast(), adt.into());
|
||||
let param_count = generics.len();
|
||||
TyBuilder::new(adt, param_count)
|
||||
pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
|
||||
TyBuilder::subst_for_def(db, def).with_data(def)
|
||||
}
|
||||
|
||||
pub fn fill_with_defaults(
|
||||
|
@ -133,14 +210,15 @@ impl TyBuilder<hir_def::AdtId> {
|
|||
) -> Self {
|
||||
let defaults = db.generic_defaults(self.data.into());
|
||||
for default_ty in defaults.iter().skip(self.vec.len()) {
|
||||
if default_ty.skip_binders().is_unknown() {
|
||||
if let GenericArgData::Ty(x) = default_ty.skip_binders().data(Interner) {
|
||||
if x.is_unknown() {
|
||||
self.vec.push(fallback().cast(Interner));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
// each default can depend on the previous parameters
|
||||
let subst_so_far = Substitution::from_iter(Interner, self.vec.clone());
|
||||
self.vec
|
||||
.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
|
||||
}
|
||||
self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
|
||||
}
|
||||
self
|
||||
}
|
||||
|
@ -154,7 +232,7 @@ impl TyBuilder<hir_def::AdtId> {
|
|||
pub struct Tuple(usize);
|
||||
impl TyBuilder<Tuple> {
|
||||
pub fn tuple(size: usize) -> TyBuilder<Tuple> {
|
||||
TyBuilder::new(Tuple(size), size)
|
||||
TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect())
|
||||
}
|
||||
|
||||
pub fn build(self) -> Ty {
|
||||
|
@ -164,10 +242,8 @@ impl TyBuilder<Tuple> {
|
|||
}
|
||||
|
||||
impl TyBuilder<TraitId> {
|
||||
pub fn trait_ref(db: &dyn HirDatabase, trait_id: TraitId) -> TyBuilder<TraitId> {
|
||||
let generics = generics(db.upcast(), trait_id.into());
|
||||
let param_count = generics.len();
|
||||
TyBuilder::new(trait_id, param_count)
|
||||
pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
|
||||
TyBuilder::subst_for_def(db, def).with_data(def)
|
||||
}
|
||||
|
||||
pub fn build(self) -> TraitRef {
|
||||
|
@ -177,13 +253,8 @@ impl TyBuilder<TraitId> {
|
|||
}
|
||||
|
||||
impl TyBuilder<TypeAliasId> {
|
||||
pub fn assoc_type_projection(
|
||||
db: &dyn HirDatabase,
|
||||
type_alias: TypeAliasId,
|
||||
) -> TyBuilder<TypeAliasId> {
|
||||
let generics = generics(db.upcast(), type_alias.into());
|
||||
let param_count = generics.len();
|
||||
TyBuilder::new(type_alias, param_count)
|
||||
pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder<TypeAliasId> {
|
||||
TyBuilder::subst_for_def(db, def).with_data(def)
|
||||
}
|
||||
|
||||
pub fn build(self) -> ProjectionTy {
|
||||
|
@ -194,8 +265,16 @@ impl TyBuilder<TypeAliasId> {
|
|||
|
||||
impl<T: HasInterner<Interner = Interner> + Fold<Interner>> TyBuilder<Binders<T>> {
|
||||
fn subst_binders(b: Binders<T>) -> Self {
|
||||
let param_count = b.binders.len(Interner);
|
||||
TyBuilder::new(b, param_count)
|
||||
let param_kinds = b
|
||||
.binders
|
||||
.iter(Interner)
|
||||
.map(|x| match x {
|
||||
chalk_ir::VariableKind::Ty(_) => ParamKind::Type,
|
||||
chalk_ir::VariableKind::Lifetime => panic!("Got lifetime parameter"),
|
||||
chalk_ir::VariableKind::Const(ty) => ParamKind::Const(ty.clone()),
|
||||
})
|
||||
.collect();
|
||||
TyBuilder::new(b, param_kinds)
|
||||
}
|
||||
|
||||
pub fn build(self) -> <T as Fold<Interner>>::Result {
|
||||
|
|
|
@ -19,7 +19,8 @@ use hir_expand::name::name;
|
|||
use crate::{
|
||||
db::HirDatabase,
|
||||
display::HirDisplay,
|
||||
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_only_type_binders,
|
||||
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_binders,
|
||||
make_single_type_binders,
|
||||
mapping::{from_chalk, ToChalk, TypeAliasAsValue},
|
||||
method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
|
||||
to_assoc_type_id, to_chalk_trait_id,
|
||||
|
@ -206,8 +207,8 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
|||
let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders();
|
||||
let data = &datas.impl_traits[idx as usize];
|
||||
let bound = OpaqueTyDatumBound {
|
||||
bounds: make_only_type_binders(1, data.bounds.skip_binders().to_vec()),
|
||||
where_clauses: make_only_type_binders(0, vec![]),
|
||||
bounds: make_single_type_binders(data.bounds.skip_binders().to_vec()),
|
||||
where_clauses: chalk_ir::Binders::empty(Interner, vec![]),
|
||||
};
|
||||
chalk_ir::Binders::new(binders, bound)
|
||||
}
|
||||
|
@ -255,25 +256,22 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
|||
.intern(Interner),
|
||||
});
|
||||
let bound = OpaqueTyDatumBound {
|
||||
bounds: make_only_type_binders(
|
||||
1,
|
||||
vec![
|
||||
bounds: make_single_type_binders(vec![
|
||||
crate::wrap_empty_binders(impl_bound),
|
||||
crate::wrap_empty_binders(proj_bound),
|
||||
],
|
||||
),
|
||||
where_clauses: make_only_type_binders(0, vec![]),
|
||||
]),
|
||||
where_clauses: chalk_ir::Binders::empty(Interner, vec![]),
|
||||
};
|
||||
// The opaque type has 1 parameter.
|
||||
make_only_type_binders(1, bound)
|
||||
make_single_type_binders(bound)
|
||||
} else {
|
||||
// If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback.
|
||||
let bound = OpaqueTyDatumBound {
|
||||
bounds: make_only_type_binders(0, vec![]),
|
||||
where_clauses: make_only_type_binders(0, vec![]),
|
||||
bounds: chalk_ir::Binders::empty(Interner, vec![]),
|
||||
where_clauses: chalk_ir::Binders::empty(Interner, vec![]),
|
||||
};
|
||||
// The opaque type has 1 parameter.
|
||||
make_only_type_binders(1, bound)
|
||||
make_single_type_binders(bound)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -310,7 +308,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
|||
argument_types: sig.params().to_vec(),
|
||||
return_type: sig.ret().clone(),
|
||||
};
|
||||
make_only_type_binders(0, io.shifted_in(Interner))
|
||||
chalk_ir::Binders::empty(Interner, io.shifted_in(Interner))
|
||||
}
|
||||
fn closure_upvars(
|
||||
&self,
|
||||
|
@ -318,7 +316,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
|
|||
_substs: &chalk_ir::Substitution<Interner>,
|
||||
) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> {
|
||||
let ty = TyBuilder::unit();
|
||||
make_only_type_binders(0, ty)
|
||||
chalk_ir::Binders::empty(Interner, ty)
|
||||
}
|
||||
fn closure_fn_substitution(
|
||||
&self,
|
||||
|
@ -407,7 +405,7 @@ pub(crate) fn associated_ty_data_query(
|
|||
// let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
|
||||
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
|
||||
let ctx = crate::TyLoweringContext::new(db, &resolver)
|
||||
.with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable);
|
||||
.with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
|
||||
let self_ty =
|
||||
TyKind::BoundVar(BoundVar::new(crate::DebruijnIndex::INNERMOST, 0)).intern(Interner);
|
||||
let mut bounds: Vec<_> = type_alias_data
|
||||
|
@ -440,7 +438,7 @@ pub(crate) fn associated_ty_data_query(
|
|||
trait_id: to_chalk_trait_id(trait_),
|
||||
id,
|
||||
name: type_alias,
|
||||
binders: make_only_type_binders(generic_params.len(), bound_data),
|
||||
binders: make_binders(db, &generic_params, bound_data),
|
||||
};
|
||||
Arc::new(datum)
|
||||
}
|
||||
|
@ -455,7 +453,7 @@ pub(crate) fn trait_datum_query(
|
|||
let trait_data = db.trait_data(trait_);
|
||||
debug!("trait {:?} = {:?}", trait_id, trait_data.name);
|
||||
let generic_params = generics(db.upcast(), trait_.into());
|
||||
let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
|
||||
let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
|
||||
let flags = rust_ir::TraitFlags {
|
||||
auto: trait_data.is_auto,
|
||||
upstream: trait_.lookup(db.upcast()).container.krate() != krate,
|
||||
|
@ -472,7 +470,7 @@ pub(crate) fn trait_datum_query(
|
|||
lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name));
|
||||
let trait_datum = TraitDatum {
|
||||
id: trait_id,
|
||||
binders: make_only_type_binders(bound_vars.len(Interner), trait_datum_bound),
|
||||
binders: make_binders(db, &generic_params, trait_datum_bound),
|
||||
flags,
|
||||
associated_ty_ids,
|
||||
well_known,
|
||||
|
@ -520,11 +518,11 @@ pub(crate) fn struct_datum_query(
|
|||
) -> Arc<StructDatum> {
|
||||
debug!("struct_datum {:?}", struct_id);
|
||||
let chalk_ir::AdtId(adt_id) = struct_id;
|
||||
let num_params = generics(db.upcast(), adt_id.into()).len();
|
||||
let generic_params = generics(db.upcast(), adt_id.into());
|
||||
let upstream = adt_id.module(db.upcast()).krate() != krate;
|
||||
let where_clauses = {
|
||||
let generic_params = generics(db.upcast(), adt_id.into());
|
||||
let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
|
||||
let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
|
||||
convert_where_clauses(db, adt_id.into(), &bound_vars)
|
||||
};
|
||||
let flags = rust_ir::AdtFlags {
|
||||
|
@ -542,7 +540,7 @@ pub(crate) fn struct_datum_query(
|
|||
// FIXME set ADT kind
|
||||
kind: rust_ir::AdtKind::Struct,
|
||||
id: struct_id,
|
||||
binders: make_only_type_binders(num_params, struct_datum_bound),
|
||||
binders: make_binders(db, &generic_params, struct_datum_bound),
|
||||
flags,
|
||||
};
|
||||
Arc::new(struct_datum)
|
||||
|
@ -574,7 +572,7 @@ fn impl_def_datum(
|
|||
let impl_data = db.impl_data(impl_id);
|
||||
|
||||
let generic_params = generics(db.upcast(), impl_id.into());
|
||||
let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
|
||||
let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
|
||||
let trait_ = trait_ref.hir_trait_id();
|
||||
let impl_type = if impl_id.lookup(db.upcast()).container.krate() == krate {
|
||||
rust_ir::ImplType::Local
|
||||
|
@ -611,7 +609,7 @@ fn impl_def_datum(
|
|||
.collect();
|
||||
debug!("impl_datum: {:?}", impl_datum_bound);
|
||||
let impl_datum = ImplDatum {
|
||||
binders: make_only_type_binders(bound_vars.len(Interner), impl_datum_bound),
|
||||
binders: make_binders(db, &generic_params, impl_datum_bound),
|
||||
impl_type,
|
||||
polarity,
|
||||
associated_ty_value_ids,
|
||||
|
@ -667,12 +665,12 @@ pub(crate) fn fn_def_datum_query(
|
|||
let callable_def: CallableDefId = from_chalk(db, fn_def_id);
|
||||
let generic_params = generics(db.upcast(), callable_def.into());
|
||||
let (sig, binders) = db.callable_item_signature(callable_def).into_value_and_skipped_binders();
|
||||
let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
|
||||
let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
|
||||
let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars);
|
||||
let bound = rust_ir::FnDefDatumBound {
|
||||
// Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway
|
||||
inputs_and_output: make_only_type_binders(
|
||||
0,
|
||||
inputs_and_output: chalk_ir::Binders::empty(
|
||||
Interner,
|
||||
rust_ir::FnDefInputsAndOutputDatum {
|
||||
argument_types: sig.params().to_vec(),
|
||||
return_type: sig.ret().clone(),
|
||||
|
|
|
@ -237,11 +237,11 @@ impl TyExt for Ty {
|
|||
TyKind::Placeholder(idx) => {
|
||||
let id = from_placeholder_idx(db, *idx);
|
||||
let generic_params = db.generic_params(id.parent);
|
||||
let param_data = &generic_params.tocs[id.local_id];
|
||||
let param_data = &generic_params.type_or_consts[id.local_id];
|
||||
match param_data {
|
||||
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
|
||||
hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
|
||||
let substs = TyBuilder::type_params_subst(db, id.parent);
|
||||
let substs = TyBuilder::placeholder_subst(db, id.parent);
|
||||
let predicates = db
|
||||
.generic_predicates(id.parent)
|
||||
.iter()
|
||||
|
|
|
@ -2,15 +2,25 @@
|
|||
|
||||
use std::{collections::HashMap, convert::TryInto, fmt::Display};
|
||||
|
||||
use chalk_ir::{IntTy, Scalar};
|
||||
use chalk_ir::{BoundVar, DebruijnIndex, GenericArgData, IntTy, Scalar};
|
||||
use hir_def::{
|
||||
expr::{ArithOp, BinaryOp, Expr, Literal, Pat},
|
||||
path::ModPath,
|
||||
resolver::{Resolver, ValueNs},
|
||||
type_ref::ConstScalar,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use la_arena::{Arena, Idx};
|
||||
use stdx::never;
|
||||
|
||||
use crate::{Const, ConstData, ConstValue, Interner, Ty, TyKind};
|
||||
use crate::{
|
||||
db::HirDatabase,
|
||||
infer::{Expectation, InferenceContext},
|
||||
lower::ParamLoweringMode,
|
||||
to_placeholder_idx,
|
||||
utils::Generics,
|
||||
Const, ConstData, ConstValue, GenericArg, Interner, Ty, TyKind,
|
||||
};
|
||||
|
||||
/// Extension trait for [`Const`]
|
||||
pub trait ConstExt {
|
||||
|
@ -303,6 +313,57 @@ pub fn eval_usize(expr: Idx<Expr>, mut ctx: ConstEvalCtx<'_>) -> Option<u64> {
|
|||
None
|
||||
}
|
||||
|
||||
pub(crate) fn path_to_const(
|
||||
db: &dyn HirDatabase,
|
||||
resolver: &Resolver,
|
||||
path: &ModPath,
|
||||
mode: ParamLoweringMode,
|
||||
args_lazy: impl FnOnce() -> Generics,
|
||||
debruijn: DebruijnIndex,
|
||||
) -> Option<Const> {
|
||||
match resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
|
||||
Some(ValueNs::GenericParam(p)) => {
|
||||
let ty = db.const_param_ty(p);
|
||||
let args = args_lazy();
|
||||
let value = match mode {
|
||||
ParamLoweringMode::Placeholder => {
|
||||
ConstValue::Placeholder(to_placeholder_idx(db, p.into()))
|
||||
}
|
||||
ParamLoweringMode::Variable => match args.param_idx(p.into()) {
|
||||
Some(x) => ConstValue::BoundVar(BoundVar::new(debruijn, x)),
|
||||
None => {
|
||||
never!(
|
||||
"Generic list doesn't contain this param: {:?}, {}, {:?}",
|
||||
args,
|
||||
path,
|
||||
p
|
||||
);
|
||||
return None;
|
||||
}
|
||||
},
|
||||
};
|
||||
Some(ConstData { ty, value }.intern(Interner))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unknown_const(ty: Ty) -> Const {
|
||||
ConstData {
|
||||
ty,
|
||||
value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: ConstScalar::Unknown }),
|
||||
}
|
||||
.intern(Interner)
|
||||
}
|
||||
|
||||
pub fn unknown_const_usize() -> Const {
|
||||
unknown_const(TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner))
|
||||
}
|
||||
|
||||
pub fn unknown_const_as_generic(ty: Ty) -> GenericArg {
|
||||
GenericArgData::Const(unknown_const(ty)).intern(Interner)
|
||||
}
|
||||
|
||||
/// Interns a possibly-unknown target usize
|
||||
pub fn usize_const(value: Option<u64>) -> Const {
|
||||
ConstData {
|
||||
|
@ -313,3 +374,27 @@ pub fn usize_const(value: Option<u64>) -> Const {
|
|||
}
|
||||
.intern(Interner)
|
||||
}
|
||||
|
||||
pub(crate) fn eval_to_const(
|
||||
expr: Idx<Expr>,
|
||||
mode: ParamLoweringMode,
|
||||
ctx: &mut InferenceContext,
|
||||
args: impl FnOnce() -> Generics,
|
||||
debruijn: DebruijnIndex,
|
||||
) -> Const {
|
||||
if let Expr::Path(p) = &ctx.body.exprs[expr] {
|
||||
let db = ctx.db;
|
||||
let resolver = &ctx.resolver;
|
||||
if let Some(c) = path_to_const(db, resolver, p.mod_path(), mode, args, debruijn) {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
let body = ctx.body.clone();
|
||||
let ctx = ConstEvalCtx {
|
||||
exprs: &body.exprs,
|
||||
pats: &body.pats,
|
||||
local_data: HashMap::default(),
|
||||
infer: &mut |x| ctx.infer_expr(x, &Expectation::None),
|
||||
};
|
||||
usize_const(eval_usize(expr, ctx))
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use la_arena::ArenaMap;
|
|||
use crate::{
|
||||
chalk_db,
|
||||
method_resolution::{InherentImpls, TraitImpls},
|
||||
Binders, CallableDefId, FnDefId, ImplTraitId, InferenceResult, Interner, PolyFnSig,
|
||||
Binders, CallableDefId, FnDefId, GenericArg, ImplTraitId, InferenceResult, Interner, PolyFnSig,
|
||||
QuantifiedWhereClause, ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
|
@ -73,7 +73,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
|
||||
#[salsa::invoke(crate::lower::generic_defaults_query)]
|
||||
#[salsa::cycle(crate::lower::generic_defaults_recover)]
|
||||
fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>;
|
||||
fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<GenericArg>]>;
|
||||
|
||||
#[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
|
||||
fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
|
||||
|
|
|
@ -14,7 +14,7 @@ use hir_def::{
|
|||
intern::{Internable, Interned},
|
||||
item_scope::ItemInNs,
|
||||
path::{Path, PathKind},
|
||||
type_ref::{TraitBoundModifier, TypeBound, TypeRef},
|
||||
type_ref::{ConstScalar, TraitBoundModifier, TypeBound, TypeRef},
|
||||
visibility::Visibility,
|
||||
HasModule, ItemContainerId, Lookup, ModuleId, TraitId,
|
||||
};
|
||||
|
@ -28,10 +28,10 @@ use crate::{
|
|||
mapping::from_chalk,
|
||||
primitive, subst_prefix, to_assoc_type_id,
|
||||
utils::{self, generics},
|
||||
AdtId, AliasEq, AliasTy, CallableDefId, CallableSig, Const, ConstValue, DomainGoal, GenericArg,
|
||||
ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability, OpaqueTy,
|
||||
ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar, TraitRef, TraitRefExt, Ty, TyExt,
|
||||
TyKind, WhereClause,
|
||||
AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstValue, DomainGoal,
|
||||
GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability,
|
||||
OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar, Substitution, TraitRef,
|
||||
TraitRefExt, Ty, TyExt, TyKind, WhereClause,
|
||||
};
|
||||
|
||||
pub struct HirFormatter<'a> {
|
||||
|
@ -316,11 +316,11 @@ impl HirDisplay for Const {
|
|||
let data = self.interned();
|
||||
match data.value {
|
||||
ConstValue::BoundVar(idx) => idx.hir_fmt(f),
|
||||
ConstValue::InferenceVar(..) => write!(f, "_"),
|
||||
ConstValue::InferenceVar(..) => write!(f, "#c#"),
|
||||
ConstValue::Placeholder(idx) => {
|
||||
let id = from_placeholder_idx(f.db, idx);
|
||||
let generics = generics(f.db.upcast(), id.parent);
|
||||
let param_data = &generics.params.tocs[id.local_id];
|
||||
let param_data = &generics.params.type_or_consts[id.local_id];
|
||||
write!(f, "{}", param_data.name().unwrap())
|
||||
}
|
||||
ConstValue::Concrete(c) => write!(f, "{}", c.interned),
|
||||
|
@ -544,26 +544,39 @@ impl HirDisplay for Ty {
|
|||
{
|
||||
None => parameters.as_slice(Interner),
|
||||
Some(default_parameters) => {
|
||||
let mut default_from = 0;
|
||||
for (i, parameter) in parameters.iter(Interner).enumerate() {
|
||||
match (
|
||||
parameter.assert_ty_ref(Interner).kind(Interner),
|
||||
default_parameters.get(i),
|
||||
) {
|
||||
(&TyKind::Error, _) | (_, None) => {
|
||||
default_from = i + 1;
|
||||
fn should_show(
|
||||
parameter: &GenericArg,
|
||||
default_parameters: &[Binders<GenericArg>],
|
||||
i: usize,
|
||||
parameters: &Substitution,
|
||||
) -> bool {
|
||||
if parameter.ty(Interner).map(|x| x.kind(Interner))
|
||||
== Some(&TyKind::Error)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
(_, Some(default_parameter)) => {
|
||||
if let Some(ConstValue::Concrete(c)) =
|
||||
parameter.constant(Interner).map(|x| x.data(Interner).value)
|
||||
{
|
||||
if c.interned == ConstScalar::Unknown {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
let default_parameter = match default_parameters.get(i) {
|
||||
Some(x) => x,
|
||||
None => return true,
|
||||
};
|
||||
let actual_default = default_parameter
|
||||
.clone()
|
||||
.substitute(Interner, &subst_prefix(parameters, i));
|
||||
if parameter.assert_ty_ref(Interner) != &actual_default
|
||||
{
|
||||
parameter != &actual_default
|
||||
}
|
||||
let mut default_from = 0;
|
||||
for (i, parameter) in parameters.iter(Interner).enumerate() {
|
||||
if should_show(parameter, &default_parameters, i, parameters) {
|
||||
default_from = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
¶meters.as_slice(Interner)[0..default_from]
|
||||
}
|
||||
}
|
||||
|
@ -680,14 +693,14 @@ impl HirDisplay for Ty {
|
|||
TyKind::Placeholder(idx) => {
|
||||
let id = from_placeholder_idx(f.db, *idx);
|
||||
let generics = generics(f.db.upcast(), id.parent);
|
||||
let param_data = &generics.params.tocs[id.local_id];
|
||||
let param_data = &generics.params.type_or_consts[id.local_id];
|
||||
match param_data {
|
||||
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
|
||||
TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
|
||||
write!(f, "{}", p.name.clone().unwrap_or_else(Name::missing))?
|
||||
}
|
||||
TypeParamProvenance::ArgumentImplTrait => {
|
||||
let substs = generics.type_params_subst(f.db);
|
||||
let substs = generics.placeholder_subst(f.db);
|
||||
let bounds =
|
||||
f.db.generic_predicates(id.parent)
|
||||
.iter()
|
||||
|
@ -1281,6 +1294,7 @@ impl HirDisplay for hir_def::path::GenericArg {
|
|||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
match self {
|
||||
hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
|
||||
hir_def::path::GenericArg::Const(c) => write!(f, "{}", c),
|
||||
hir_def::path::GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
use std::ops::Index;
|
||||
use std::sync::Arc;
|
||||
|
||||
use chalk_ir::{cast::Cast, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
|
||||
use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
|
||||
use hir_def::{
|
||||
body::Body,
|
||||
data::{ConstData, FunctionData, StaticData},
|
||||
|
@ -29,14 +29,16 @@ use hir_def::{
|
|||
TraitId, TypeAliasId, VariantId,
|
||||
};
|
||||
use hir_expand::name::{name, Name};
|
||||
use itertools::Either;
|
||||
use la_arena::ArenaMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
use stdx::impl_from;
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode,
|
||||
to_assoc_type_id, AliasEq, AliasTy, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy,
|
||||
Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
|
||||
builder::ParamKind, db::HirDatabase, fold_tys_and_consts, infer::coerce::CoerceMany,
|
||||
lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal,
|
||||
GenericArg, GenericArgData, Goal, InEnvironment, Interner, ProjectionTy, Substitution,
|
||||
TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
|
||||
};
|
||||
|
||||
// This lint has a false positive here. See the link below for details.
|
||||
|
@ -354,11 +356,11 @@ impl Index<PatId> for InferenceResult {
|
|||
|
||||
/// The inference context contains all information needed during type inference.
|
||||
#[derive(Clone, Debug)]
|
||||
struct InferenceContext<'a> {
|
||||
db: &'a dyn HirDatabase,
|
||||
pub(crate) struct InferenceContext<'a> {
|
||||
pub(crate) db: &'a dyn HirDatabase,
|
||||
owner: DefWithBodyId,
|
||||
body: Arc<Body>,
|
||||
resolver: Resolver,
|
||||
pub(crate) body: Arc<Body>,
|
||||
pub(crate) resolver: Resolver,
|
||||
table: unify::InferenceTable<'a>,
|
||||
trait_env: Arc<TraitEnvironment>,
|
||||
result: InferenceResult,
|
||||
|
@ -488,6 +490,20 @@ impl<'a> InferenceContext<'a> {
|
|||
self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed)
|
||||
}
|
||||
|
||||
/// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it.
|
||||
fn insert_const_vars_shallow(&mut self, c: Const) -> Const {
|
||||
let data = c.data(Interner);
|
||||
match data.value {
|
||||
ConstValue::Concrete(cc) => match cc.interned {
|
||||
hir_def::type_ref::ConstScalar::Usize(_) => c,
|
||||
hir_def::type_ref::ConstScalar::Unknown => {
|
||||
self.table.new_const_var(data.ty.clone())
|
||||
}
|
||||
},
|
||||
_ => c,
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
|
||||
fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
|
||||
match ty.kind(Interner) {
|
||||
|
@ -505,7 +521,14 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
|
||||
fn insert_type_vars(&mut self, ty: Ty) -> Ty {
|
||||
fold_tys(ty, |ty, _| self.insert_type_vars_shallow(ty), DebruijnIndex::INNERMOST)
|
||||
fold_tys_and_consts(
|
||||
ty,
|
||||
|x, _| match x {
|
||||
Either::Left(ty) => Either::Left(self.insert_type_vars_shallow(ty)),
|
||||
Either::Right(c) => Either::Right(self.insert_const_vars_shallow(c)),
|
||||
},
|
||||
DebruijnIndex::INNERMOST,
|
||||
)
|
||||
}
|
||||
|
||||
fn resolve_obligations_as_possible(&mut self) {
|
||||
|
@ -533,7 +556,7 @@ impl<'a> InferenceContext<'a> {
|
|||
&mut self,
|
||||
inner_ty: Ty,
|
||||
assoc_ty: Option<TypeAliasId>,
|
||||
params: &[Ty],
|
||||
params: &[GenericArg],
|
||||
) -> Ty {
|
||||
match assoc_ty {
|
||||
Some(res_assoc_ty) => {
|
||||
|
@ -542,9 +565,10 @@ impl<'a> InferenceContext<'a> {
|
|||
_ => panic!("resolve_associated_type called with non-associated type"),
|
||||
};
|
||||
let ty = self.table.new_type_var();
|
||||
let mut param_iter = params.iter().cloned();
|
||||
let trait_ref = TyBuilder::trait_ref(self.db, trait_)
|
||||
.push(inner_ty)
|
||||
.fill(params.iter().cloned())
|
||||
.fill(|_| param_iter.next().unwrap())
|
||||
.build();
|
||||
let alias_eq = AliasEq {
|
||||
alias: AliasTy::Projection(ProjectionTy {
|
||||
|
@ -627,13 +651,21 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
TypeNs::SelfType(impl_id) => {
|
||||
let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
|
||||
let substs = generics.type_params_subst(self.db);
|
||||
let substs = generics.placeholder_subst(self.db);
|
||||
let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
|
||||
self.resolve_variant_on_alias(ty, unresolved, path)
|
||||
}
|
||||
TypeNs::TypeAliasId(it) => {
|
||||
let ty = TyBuilder::def_ty(self.db, it.into())
|
||||
.fill(std::iter::repeat_with(|| self.table.new_type_var()))
|
||||
.fill(|x| match x {
|
||||
ParamKind::Type => {
|
||||
GenericArgData::Ty(self.table.new_type_var()).intern(Interner)
|
||||
}
|
||||
ParamKind::Const(ty) => {
|
||||
GenericArgData::Const(self.table.new_const_var(ty.clone()))
|
||||
.intern(Interner)
|
||||
}
|
||||
})
|
||||
.build();
|
||||
self.resolve_variant_on_alias(ty, unresolved, path)
|
||||
}
|
||||
|
@ -827,7 +859,7 @@ impl<'a> InferenceContext<'a> {
|
|||
/// When inferring an expression, we propagate downward whatever type hint we
|
||||
/// are able in the form of an `Expectation`.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
enum Expectation {
|
||||
pub(crate) enum Expectation {
|
||||
None,
|
||||
HasType(Ty),
|
||||
// Castable(Ty), // rustc has this, we currently just don't propagate an expectation for casts
|
||||
|
|
|
@ -7,13 +7,15 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
|
||||
use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
|
||||
use chalk_ir::{
|
||||
cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
|
||||
};
|
||||
use hir_def::{
|
||||
expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Ordering, Statement, UnaryOp},
|
||||
generics::TypeOrConstParamData,
|
||||
path::{GenericArg, GenericArgs},
|
||||
resolver::resolver_for_expr,
|
||||
FieldId, FunctionId, ItemContainerId, Lookup,
|
||||
ConstParamId, FieldId, FunctionId, ItemContainerId, Lookup,
|
||||
};
|
||||
use hir_expand::name::{name, Name};
|
||||
use stdx::always;
|
||||
|
@ -23,7 +25,9 @@ use crate::{
|
|||
autoderef::{self, Autoderef},
|
||||
consteval,
|
||||
infer::coerce::CoerceMany,
|
||||
lower::lower_to_chalk_mutability,
|
||||
lower::{
|
||||
const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
|
||||
},
|
||||
mapping::from_chalk,
|
||||
method_resolution,
|
||||
primitive::{self, UintTy},
|
||||
|
@ -39,7 +43,7 @@ use super::{
|
|||
};
|
||||
|
||||
impl<'a> InferenceContext<'a> {
|
||||
pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
|
||||
pub(crate) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
|
||||
let ty = self.infer_expr_inner(tgt_expr, expected);
|
||||
if self.resolve_ty_shallow(&ty).is_never() {
|
||||
// Any expression that produces a value of type `!` must have diverged
|
||||
|
@ -662,7 +666,7 @@ impl<'a> InferenceContext<'a> {
|
|||
self.resolve_associated_type_with_params(
|
||||
self_ty,
|
||||
self.resolve_ops_index_output(),
|
||||
&[index_ty],
|
||||
&[GenericArgData::Ty(index_ty).intern(Interner)],
|
||||
)
|
||||
} else {
|
||||
self.err_ty()
|
||||
|
@ -704,7 +708,7 @@ impl<'a> InferenceContext<'a> {
|
|||
let cur_elem_ty = self.infer_expr_inner(expr, &expected);
|
||||
coerce.coerce(self, Some(expr), &cur_elem_ty);
|
||||
}
|
||||
Some(items.len() as u64)
|
||||
consteval::usize_const(Some(items.len() as u64))
|
||||
}
|
||||
&Array::Repeat { initializer, repeat } => {
|
||||
self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty));
|
||||
|
@ -715,19 +719,22 @@ impl<'a> InferenceContext<'a> {
|
|||
),
|
||||
);
|
||||
|
||||
consteval::eval_usize(
|
||||
if let Some(g_def) = self.owner.as_generic_def_id() {
|
||||
let generics = generics(self.db.upcast(), g_def);
|
||||
consteval::eval_to_const(
|
||||
repeat,
|
||||
consteval::ConstEvalCtx {
|
||||
exprs: &body.exprs,
|
||||
pats: &body.pats,
|
||||
local_data: Default::default(),
|
||||
infer: &mut |x| self.infer_expr(x, &expected),
|
||||
},
|
||||
ParamLoweringMode::Placeholder,
|
||||
self,
|
||||
|| generics,
|
||||
DebruijnIndex::INNERMOST,
|
||||
)
|
||||
} else {
|
||||
consteval::usize_const(None)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TyKind::Array(coerce.complete(), consteval::usize_const(len)).intern(Interner)
|
||||
TyKind::Array(coerce.complete(), len).intern(Interner)
|
||||
}
|
||||
Expr::Literal(lit) => match lit {
|
||||
Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(Interner),
|
||||
|
@ -1038,38 +1045,52 @@ impl<'a> InferenceContext<'a> {
|
|||
let total_len = parent_params + type_params + const_params + impl_trait_params;
|
||||
let mut substs = Vec::with_capacity(total_len);
|
||||
// Parent arguments are unknown
|
||||
for (_id, param) in def_generics.iter_parent() {
|
||||
for (id, param) in def_generics.iter_parent() {
|
||||
match param {
|
||||
TypeOrConstParamData::TypeParamData(_) => {
|
||||
substs.push(self.table.new_type_var());
|
||||
substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner));
|
||||
}
|
||||
TypeOrConstParamData::ConstParamData(_) => {
|
||||
// FIXME: here we should do something else
|
||||
substs.push(self.table.new_type_var());
|
||||
let ty = self.db.const_param_ty(ConstParamId::from_unchecked(id));
|
||||
substs
|
||||
.push(GenericArgData::Const(self.table.new_const_var(ty)).intern(Interner));
|
||||
}
|
||||
}
|
||||
}
|
||||
// handle provided type arguments
|
||||
// handle provided arguments
|
||||
if let Some(generic_args) = generic_args {
|
||||
// if args are provided, it should be all of them, but we can't rely on that
|
||||
for arg in generic_args
|
||||
for (arg, kind_id) in generic_args
|
||||
.args
|
||||
.iter()
|
||||
.filter(|arg| matches!(arg, GenericArg::Type(_)))
|
||||
.take(type_params)
|
||||
.filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
|
||||
.take(type_params + const_params)
|
||||
.zip(def_generics.iter_id().skip(parent_params))
|
||||
{
|
||||
match arg {
|
||||
GenericArg::Type(type_ref) => {
|
||||
let ty = self.make_ty(type_ref);
|
||||
substs.push(ty);
|
||||
}
|
||||
GenericArg::Lifetime(_) => {}
|
||||
if let Some(g) = generic_arg_to_chalk(
|
||||
self.db,
|
||||
kind_id,
|
||||
arg,
|
||||
self,
|
||||
|this, type_ref| this.make_ty(type_ref),
|
||||
|this, c| {
|
||||
const_or_path_to_chalk(
|
||||
this.db,
|
||||
&this.resolver,
|
||||
c,
|
||||
ParamLoweringMode::Placeholder,
|
||||
|| generics(this.db.upcast(), (&this.resolver).generic_def().unwrap()),
|
||||
DebruijnIndex::INNERMOST,
|
||||
)
|
||||
},
|
||||
) {
|
||||
substs.push(g);
|
||||
}
|
||||
}
|
||||
};
|
||||
let supplied_params = substs.len();
|
||||
for _ in supplied_params..total_len {
|
||||
substs.push(self.table.new_type_var());
|
||||
substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner));
|
||||
}
|
||||
assert_eq!(substs.len(), total_len);
|
||||
Substitution::from_iter(Interner, substs)
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
//! Path expression resolution.
|
||||
|
||||
use std::iter;
|
||||
|
||||
use chalk_ir::cast::Cast;
|
||||
use hir_def::{
|
||||
path::{Path, PathSegment},
|
||||
|
@ -11,8 +9,8 @@ use hir_def::{
|
|||
use hir_expand::name::Name;
|
||||
|
||||
use crate::{
|
||||
method_resolution, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
|
||||
ValueTyDefId,
|
||||
builder::ParamKind, consteval, method_resolution, GenericArgData, Interner, Substitution,
|
||||
TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
|
||||
};
|
||||
|
||||
use super::{ExprOrPatId, InferenceContext, TraitRef};
|
||||
|
@ -82,7 +80,7 @@ impl<'a> InferenceContext<'a> {
|
|||
}
|
||||
ValueNs::ImplSelf(impl_id) => {
|
||||
let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
|
||||
let substs = generics.type_params_subst(self.db);
|
||||
let substs = generics.placeholder_subst(self.db);
|
||||
let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
|
||||
if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() {
|
||||
let ty = self.db.value_ty(struct_id.into()).substitute(Interner, &substs);
|
||||
|
@ -98,9 +96,19 @@ impl<'a> InferenceContext<'a> {
|
|||
let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(Interner));
|
||||
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
|
||||
let substs = ctx.substs_from_path(path, typable, true);
|
||||
let mut it = substs.as_slice(Interner)[parent_substs.len(Interner)..].iter().cloned();
|
||||
let ty = TyBuilder::value_ty(self.db, typable)
|
||||
.use_parent_substs(&parent_substs)
|
||||
.fill(substs.as_slice(Interner)[parent_substs.len(Interner)..].iter().cloned())
|
||||
.fill(|x| {
|
||||
it.next().unwrap_or_else(|| match x {
|
||||
ParamKind::Type => {
|
||||
GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
|
||||
}
|
||||
ParamKind::Const(_) => {
|
||||
GenericArgData::Const(consteval::usize_const(None)).intern(Interner)
|
||||
}
|
||||
})
|
||||
})
|
||||
.build();
|
||||
Some(ty)
|
||||
}
|
||||
|
@ -241,7 +249,15 @@ impl<'a> InferenceContext<'a> {
|
|||
let substs = match container {
|
||||
ItemContainerId::ImplId(impl_id) => {
|
||||
let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
|
||||
.fill(iter::repeat_with(|| self.table.new_type_var()))
|
||||
.fill(|x| match x {
|
||||
ParamKind::Type => {
|
||||
GenericArgData::Ty(self.table.new_type_var()).intern(Interner)
|
||||
}
|
||||
ParamKind::Const(ty) => {
|
||||
GenericArgData::Const(self.table.new_const_var(ty.clone()))
|
||||
.intern(Interner)
|
||||
}
|
||||
})
|
||||
.build();
|
||||
let impl_self_ty =
|
||||
self.db.impl_self_ty(impl_id).substitute(Interner, &impl_substs);
|
||||
|
@ -252,7 +268,15 @@ impl<'a> InferenceContext<'a> {
|
|||
// we're picking this method
|
||||
let trait_ref = TyBuilder::trait_ref(self.db, trait_)
|
||||
.push(ty.clone())
|
||||
.fill(std::iter::repeat_with(|| self.table.new_type_var()))
|
||||
.fill(|x| match x {
|
||||
ParamKind::Type => {
|
||||
GenericArgData::Ty(self.table.new_type_var()).intern(Interner)
|
||||
}
|
||||
ParamKind::Const(ty) => {
|
||||
GenericArgData::Const(self.table.new_const_var(ty.clone()))
|
||||
.intern(Interner)
|
||||
}
|
||||
})
|
||||
.build();
|
||||
self.push_obligation(trait_ref.clone().cast(Interner));
|
||||
Some(trait_ref.substitution)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Unification and canonicalization logic.
|
||||
|
||||
use std::{fmt, iter, mem, sync::Arc};
|
||||
use std::{fmt, mem, sync::Arc};
|
||||
|
||||
use chalk_ir::{
|
||||
cast::Cast, fold::Fold, interner::HasInterner, zip::Zip, FloatTy, IntTy, NoSolution,
|
||||
|
@ -9,13 +9,14 @@ use chalk_ir::{
|
|||
use chalk_solve::infer::ParameterEnaVariableExt;
|
||||
use ena::unify::UnifyKey;
|
||||
use hir_expand::name;
|
||||
use stdx::never;
|
||||
|
||||
use super::{InferOk, InferResult, InferenceContext, TypeError};
|
||||
use crate::{
|
||||
db::HirDatabase, fold_tys, static_lifetime, traits::FnTrait, AliasEq, AliasTy, BoundVar,
|
||||
Canonical, Const, DebruijnIndex, GenericArg, Goal, Guidance, InEnvironment, InferenceVar,
|
||||
Interner, Lifetime, ProjectionTy, ProjectionTyExt, Scalar, Solution, Substitution,
|
||||
TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind,
|
||||
Canonical, Const, DebruijnIndex, GenericArg, GenericArgData, Goal, Guidance, InEnvironment,
|
||||
InferenceVar, Interner, Lifetime, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution,
|
||||
Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind,
|
||||
};
|
||||
|
||||
impl<'a> InferenceContext<'a> {
|
||||
|
@ -48,13 +49,13 @@ impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
|
|||
// the solution may contain new variables, which we need to convert to new inference vars
|
||||
let new_vars = Substitution::from_iter(
|
||||
Interner,
|
||||
solution.binders.iter(Interner).map(|k| match k.kind {
|
||||
solution.binders.iter(Interner).map(|k| match &k.kind {
|
||||
VariableKind::Ty(TyVariableKind::General) => ctx.new_type_var().cast(Interner),
|
||||
VariableKind::Ty(TyVariableKind::Integer) => ctx.new_integer_var().cast(Interner),
|
||||
VariableKind::Ty(TyVariableKind::Float) => ctx.new_float_var().cast(Interner),
|
||||
// Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere
|
||||
VariableKind::Lifetime => static_lifetime().cast(Interner),
|
||||
_ => panic!("const variable in solution"),
|
||||
VariableKind::Const(ty) => ctx.new_const_var(ty.clone()).cast(Interner),
|
||||
}),
|
||||
);
|
||||
for (i, v) in solution.value.iter(Interner).enumerate() {
|
||||
|
@ -87,11 +88,17 @@ pub(crate) fn unify(
|
|||
let mut table = InferenceTable::new(db, env);
|
||||
let vars = Substitution::from_iter(
|
||||
Interner,
|
||||
tys.binders
|
||||
.iter(Interner)
|
||||
// we always use type vars here because we want everything to
|
||||
// fallback to Unknown in the end (kind of hacky, as below)
|
||||
.map(|_| table.new_type_var()),
|
||||
tys.binders.iter(Interner).map(|x| match &x.kind {
|
||||
chalk_ir::VariableKind::Ty(_) => {
|
||||
GenericArgData::Ty(table.new_type_var()).intern(Interner)
|
||||
}
|
||||
chalk_ir::VariableKind::Lifetime => {
|
||||
GenericArgData::Ty(table.new_type_var()).intern(Interner)
|
||||
} // FIXME: maybe wrong?
|
||||
chalk_ir::VariableKind::Const(ty) => {
|
||||
GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
|
||||
}
|
||||
}),
|
||||
);
|
||||
let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner);
|
||||
let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner);
|
||||
|
@ -117,8 +124,7 @@ pub(crate) fn unify(
|
|||
};
|
||||
Some(Substitution::from_iter(
|
||||
Interner,
|
||||
vars.iter(Interner)
|
||||
.map(|v| table.resolve_with_fallback(v.assert_ty_ref(Interner).clone(), &fallback)),
|
||||
vars.iter(Interner).map(|v| table.resolve_with_fallback(v.clone(), &fallback)),
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -552,11 +558,18 @@ impl<'a> InferenceTable<'a> {
|
|||
|
||||
let mut arg_tys = vec![];
|
||||
let arg_ty = TyBuilder::tuple(num_args)
|
||||
.fill(iter::repeat_with(|| {
|
||||
let arg = self.new_type_var();
|
||||
.fill(|x| {
|
||||
let arg = match x {
|
||||
ParamKind::Type => self.new_type_var(),
|
||||
ParamKind::Const(ty) => {
|
||||
never!("Tuple with const parameter");
|
||||
return GenericArgData::Const(self.new_const_var(ty.clone()))
|
||||
.intern(Interner);
|
||||
}
|
||||
};
|
||||
arg_tys.push(arg.clone());
|
||||
arg
|
||||
}))
|
||||
GenericArgData::Ty(arg).intern(Interner)
|
||||
})
|
||||
.build();
|
||||
|
||||
let projection = {
|
||||
|
|
|
@ -42,11 +42,13 @@ use hir_def::{
|
|||
type_ref::{ConstScalar, Rawness},
|
||||
TypeOrConstParamId,
|
||||
};
|
||||
use itertools::Either;
|
||||
use utils::Generics;
|
||||
|
||||
use crate::{db::HirDatabase, utils::generics};
|
||||
|
||||
pub use autoderef::autoderef;
|
||||
pub use builder::TyBuilder;
|
||||
pub use builder::{ParamKind, TyBuilder};
|
||||
pub use chalk_ext::*;
|
||||
pub use infer::{could_unify, InferenceDiagnostic, InferenceResult};
|
||||
pub use interner::Interner;
|
||||
|
@ -140,20 +142,58 @@ where
|
|||
Binders::empty(Interner, value.shifted_in_from(Interner, DebruijnIndex::ONE))
|
||||
}
|
||||
|
||||
pub(crate) fn make_only_type_binders<T: HasInterner<Interner = Interner>>(
|
||||
num_vars: usize,
|
||||
pub(crate) fn make_type_and_const_binders<T: HasInterner<Interner = Interner>>(
|
||||
which_is_const: impl Iterator<Item = Option<Ty>>,
|
||||
value: T,
|
||||
) -> Binders<T> {
|
||||
Binders::new(
|
||||
VariableKinds::from_iter(
|
||||
Interner,
|
||||
std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General))
|
||||
.take(num_vars),
|
||||
which_is_const.map(|x| {
|
||||
if let Some(ty) = x {
|
||||
chalk_ir::VariableKind::Const(ty)
|
||||
} else {
|
||||
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
|
||||
}
|
||||
}),
|
||||
),
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn make_single_type_binders<T: HasInterner<Interner = Interner>>(
|
||||
value: T,
|
||||
) -> Binders<T> {
|
||||
Binders::new(
|
||||
VariableKinds::from_iter(
|
||||
Interner,
|
||||
std::iter::once(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)),
|
||||
),
|
||||
value,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn make_binders_with_count<T: HasInterner<Interner = Interner>>(
|
||||
db: &dyn HirDatabase,
|
||||
count: usize,
|
||||
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)
|
||||
}
|
||||
|
||||
pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
|
||||
db: &dyn HirDatabase,
|
||||
generics: &Generics,
|
||||
value: T,
|
||||
) -> Binders<T> {
|
||||
make_binders_with_count(db, usize::MAX, generics, value)
|
||||
}
|
||||
|
||||
// FIXME: get rid of this
|
||||
pub fn make_canonical<T: HasInterner<Interner = Interner>>(
|
||||
value: T,
|
||||
|
@ -288,11 +328,17 @@ pub fn dummy_usize_const() -> Const {
|
|||
|
||||
pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + Fold<Interner>>(
|
||||
t: T,
|
||||
f: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
|
||||
for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
|
||||
for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
|
||||
) -> T::Result {
|
||||
use chalk_ir::{fold::Folder, Fallible};
|
||||
struct FreeVarFolder<F>(F);
|
||||
impl<'i, F: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i> Folder<Interner> for FreeVarFolder<F> {
|
||||
struct FreeVarFolder<F1, F2>(F1, F2);
|
||||
impl<
|
||||
'i,
|
||||
F1: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i,
|
||||
F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const + 'i,
|
||||
> Folder<Interner> for FreeVarFolder<F1, F2>
|
||||
{
|
||||
type Error = NoSolution;
|
||||
|
||||
fn as_dyn(&mut self) -> &mut dyn Folder<Interner, Error = Self::Error> {
|
||||
|
@ -310,13 +356,38 @@ pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + Fold<Interner
|
|||
) -> Fallible<Ty> {
|
||||
Ok(self.0(bound_var, outer_binder))
|
||||
}
|
||||
|
||||
fn fold_free_var_const(
|
||||
&mut self,
|
||||
ty: Ty,
|
||||
bound_var: BoundVar,
|
||||
outer_binder: DebruijnIndex,
|
||||
) -> Fallible<Const> {
|
||||
Ok(self.1(ty, bound_var, outer_binder))
|
||||
}
|
||||
t.fold_with(&mut FreeVarFolder(f), DebruijnIndex::INNERMOST).expect("fold failed unexpectedly")
|
||||
}
|
||||
t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST)
|
||||
.expect("fold failed unexpectedly")
|
||||
}
|
||||
|
||||
pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
|
||||
t: T,
|
||||
f: impl FnMut(Ty, DebruijnIndex) -> Ty,
|
||||
mut for_ty: impl FnMut(Ty, DebruijnIndex) -> Ty,
|
||||
binders: DebruijnIndex,
|
||||
) -> T::Result {
|
||||
fold_tys_and_consts(
|
||||
t,
|
||||
|x, d| match x {
|
||||
Either::Left(x) => Either::Left(for_ty(x, d)),
|
||||
Either::Right(x) => Either::Right(x),
|
||||
},
|
||||
binders,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + Fold<Interner>>(
|
||||
t: T,
|
||||
f: impl FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>,
|
||||
binders: DebruijnIndex,
|
||||
) -> T::Result {
|
||||
use chalk_ir::{
|
||||
|
@ -324,7 +395,9 @@ pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
|
|||
Fallible,
|
||||
};
|
||||
struct TyFolder<F>(F);
|
||||
impl<'i, F: FnMut(Ty, DebruijnIndex) -> Ty + 'i> Folder<Interner> for TyFolder<F> {
|
||||
impl<'i, F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const> + 'i> Folder<Interner>
|
||||
for TyFolder<F>
|
||||
{
|
||||
type Error = NoSolution;
|
||||
|
||||
fn as_dyn(&mut self) -> &mut dyn Folder<Interner, Error = Self::Error> {
|
||||
|
@ -337,7 +410,11 @@ pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
|
|||
|
||||
fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
|
||||
let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
|
||||
Ok(self.0(ty, outer_binder))
|
||||
Ok(self.0(Either::Left(ty), outer_binder).left().unwrap())
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Fallible<Const> {
|
||||
Ok(self.0(Either::Right(c), outer_binder).right().unwrap())
|
||||
}
|
||||
}
|
||||
t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
|
||||
|
|
|
@ -9,9 +9,11 @@ use std::cell::{Cell, RefCell};
|
|||
use std::{iter, sync::Arc};
|
||||
|
||||
use base_db::CrateId;
|
||||
use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety};
|
||||
use chalk_ir::{cast::Cast, fold::Shift, Mutability, Safety};
|
||||
use hir_def::generics::TypeOrConstParamData;
|
||||
use hir_def::intern::Interned;
|
||||
use hir_def::path::{ModPath, PathKind};
|
||||
use hir_def::type_ref::ConstScalarOrPath;
|
||||
use hir_def::{
|
||||
adt::StructKind,
|
||||
body::{Expander, LowerCtx},
|
||||
|
@ -24,23 +26,25 @@ use hir_def::{
|
|||
ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId,
|
||||
UnionId, VariantId,
|
||||
};
|
||||
use hir_def::{ConstParamId, TypeOrConstParamId};
|
||||
use hir_def::{ConstParamId, TypeOrConstParamId, TypeParamId};
|
||||
use hir_expand::{name::Name, ExpandResult};
|
||||
use itertools::Either;
|
||||
use la_arena::ArenaMap;
|
||||
use rustc_hash::FxHashSet;
|
||||
use smallvec::SmallVec;
|
||||
use stdx::{impl_from, never};
|
||||
use syntax::{ast, SmolStr};
|
||||
|
||||
use crate::all_super_traits;
|
||||
use crate::consteval::{path_to_const, unknown_const_as_generic, unknown_const_usize, usize_const};
|
||||
use crate::method_resolution::fallback_bound_vars;
|
||||
use crate::utils::Generics;
|
||||
use crate::{all_super_traits, make_binders, Const, GenericArgData, ParamKind};
|
||||
use crate::{
|
||||
consteval,
|
||||
db::HirDatabase,
|
||||
mapping::ToChalk,
|
||||
static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
|
||||
utils::{
|
||||
all_super_trait_refs, associated_type_by_name_including_super_traits, generics, Generics,
|
||||
},
|
||||
utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics},
|
||||
AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig,
|
||||
FnSubst, ImplTraitId, Interner, PolyFnSig, ProjectionTy, QuantifiedWhereClause,
|
||||
QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution,
|
||||
|
@ -56,7 +60,7 @@ pub struct TyLoweringContext<'a> {
|
|||
/// some type params should be represented as placeholders, and others
|
||||
/// should be converted to variables. I think in practice, this isn't
|
||||
/// possible currently, so this should be fine for now.
|
||||
pub type_param_mode: TypeParamLoweringMode,
|
||||
pub type_param_mode: ParamLoweringMode,
|
||||
pub impl_trait_mode: ImplTraitLoweringMode,
|
||||
impl_trait_counter: Cell<u16>,
|
||||
/// When turning `impl Trait` into opaque types, we have to collect the
|
||||
|
@ -77,7 +81,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self {
|
||||
let impl_trait_counter = Cell::new(0);
|
||||
let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
|
||||
let type_param_mode = TypeParamLoweringMode::Placeholder;
|
||||
let type_param_mode = ParamLoweringMode::Placeholder;
|
||||
let in_binders = DebruijnIndex::INNERMOST;
|
||||
let opaque_type_data = RefCell::new(Vec::new());
|
||||
Self {
|
||||
|
@ -129,7 +133,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
Self { impl_trait_mode, ..self }
|
||||
}
|
||||
|
||||
pub fn with_type_param_mode(self, type_param_mode: TypeParamLoweringMode) -> Self {
|
||||
pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self {
|
||||
Self { type_param_mode, ..self }
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +159,7 @@ pub enum ImplTraitLoweringMode {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum TypeParamLoweringMode {
|
||||
pub enum ParamLoweringMode {
|
||||
Placeholder,
|
||||
Variable,
|
||||
}
|
||||
|
@ -165,6 +169,15 @@ impl<'a> TyLoweringContext<'a> {
|
|||
self.lower_ty_ext(type_ref).0
|
||||
}
|
||||
|
||||
fn generics(&self) -> Generics {
|
||||
generics(
|
||||
self.db.upcast(),
|
||||
self.resolver
|
||||
.generic_def()
|
||||
.expect("there should be generics if there's a generic param"),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
|
||||
let mut res = None;
|
||||
let ty = match type_ref {
|
||||
|
@ -185,8 +198,14 @@ impl<'a> TyLoweringContext<'a> {
|
|||
}
|
||||
TypeRef::Array(inner, len) => {
|
||||
let inner_ty = self.lower_ty(inner);
|
||||
|
||||
let const_len = consteval::usize_const(len.as_usize());
|
||||
let const_len = const_or_path_to_chalk(
|
||||
self.db,
|
||||
self.resolver,
|
||||
len,
|
||||
self.type_param_mode,
|
||||
|| self.generics(),
|
||||
DebruijnIndex::INNERMOST,
|
||||
);
|
||||
|
||||
TyKind::Array(inner_ty, const_len).intern(Interner)
|
||||
}
|
||||
|
@ -221,7 +240,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
|
||||
)
|
||||
});
|
||||
let bounds = crate::make_only_type_binders(1, bounds);
|
||||
let bounds = crate::make_single_type_binders(bounds);
|
||||
TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
|
||||
}
|
||||
TypeRef::ImplTrait(bounds) => {
|
||||
|
@ -239,7 +258,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
// place even if we encounter more opaque types while
|
||||
// lowering the bounds
|
||||
self.opaque_type_data.borrow_mut().push(ReturnTypeImplTrait {
|
||||
bounds: crate::make_only_type_binders(1, Vec::new()),
|
||||
bounds: crate::make_single_type_binders(Vec::new()),
|
||||
});
|
||||
// We don't want to lower the bounds inside the binders
|
||||
// we're currently in, because they don't end up inside
|
||||
|
@ -259,7 +278,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx);
|
||||
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
|
||||
let generics = generics(self.db.upcast(), func.into());
|
||||
let parameters = generics.bound_vars_subst(self.in_binders);
|
||||
let parameters = generics.bound_vars_subst(self.db, self.in_binders);
|
||||
TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner)
|
||||
}
|
||||
ImplTraitLoweringMode::Param => {
|
||||
|
@ -449,8 +468,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
)
|
||||
});
|
||||
let dyn_ty = DynTy {
|
||||
bounds: crate::make_only_type_binders(
|
||||
1,
|
||||
bounds: crate::make_single_type_binders(
|
||||
QuantifiedWhereClauses::from_iter(
|
||||
Interner,
|
||||
Some(crate::wrap_empty_binders(WhereClause::Implemented(
|
||||
|
@ -475,10 +493,10 @@ impl<'a> TyLoweringContext<'a> {
|
|||
self.resolver.generic_def().expect("generics in scope"),
|
||||
);
|
||||
match self.type_param_mode {
|
||||
TypeParamLoweringMode::Placeholder => {
|
||||
ParamLoweringMode::Placeholder => {
|
||||
TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
|
||||
}
|
||||
TypeParamLoweringMode::Variable => {
|
||||
ParamLoweringMode::Variable => {
|
||||
let idx = generics.param_idx(param_id.into()).expect("matching generics");
|
||||
TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
|
||||
}
|
||||
|
@ -488,16 +506,20 @@ impl<'a> TyLoweringContext<'a> {
|
|||
TypeNs::SelfType(impl_id) => {
|
||||
let generics = generics(self.db.upcast(), impl_id.into());
|
||||
let substs = match self.type_param_mode {
|
||||
TypeParamLoweringMode::Placeholder => generics.type_params_subst(self.db),
|
||||
TypeParamLoweringMode::Variable => generics.bound_vars_subst(self.in_binders),
|
||||
ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
|
||||
ParamLoweringMode::Variable => {
|
||||
generics.bound_vars_subst(self.db, self.in_binders)
|
||||
}
|
||||
};
|
||||
self.db.impl_self_ty(impl_id).substitute(Interner, &substs)
|
||||
}
|
||||
TypeNs::AdtSelfType(adt) => {
|
||||
let generics = generics(self.db.upcast(), adt.into());
|
||||
let substs = match self.type_param_mode {
|
||||
TypeParamLoweringMode::Placeholder => generics.type_params_subst(self.db),
|
||||
TypeParamLoweringMode::Variable => generics.bound_vars_subst(self.in_binders),
|
||||
ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
|
||||
ParamLoweringMode::Variable => {
|
||||
generics.bound_vars_subst(self.db, self.in_binders)
|
||||
}
|
||||
};
|
||||
self.db.ty(adt.into()).substitute(Interner, &substs)
|
||||
}
|
||||
|
@ -549,7 +571,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
move |name, t, associated_ty| {
|
||||
if name == segment.name {
|
||||
let substs = match self.type_param_mode {
|
||||
TypeParamLoweringMode::Placeholder => {
|
||||
ParamLoweringMode::Placeholder => {
|
||||
// if we're lowering to placeholders, we have to put
|
||||
// them in now
|
||||
let generics = generics(
|
||||
|
@ -558,10 +580,10 @@ impl<'a> TyLoweringContext<'a> {
|
|||
.generic_def()
|
||||
.expect("there should be generics if there's a generic param"),
|
||||
);
|
||||
let s = generics.type_params_subst(self.db);
|
||||
let s = generics.placeholder_subst(self.db);
|
||||
s.apply(t.substitution.clone(), Interner)
|
||||
}
|
||||
TypeParamLoweringMode::Variable => t.substitution.clone(),
|
||||
ParamLoweringMode::Variable => t.substitution.clone(),
|
||||
};
|
||||
// We need to shift in the bound vars, since
|
||||
// associated_type_shorthand_candidates does not do that
|
||||
|
@ -642,47 +664,75 @@ impl<'a> TyLoweringContext<'a> {
|
|||
explicit_self_ty: Option<Ty>,
|
||||
) -> Substitution {
|
||||
let mut substs = Vec::new();
|
||||
let def_generics = def_generic.map(|def| generics(self.db.upcast(), def));
|
||||
|
||||
let def_generics = if let Some(def) = def_generic {
|
||||
generics(self.db.upcast(), def)
|
||||
} else {
|
||||
return Substitution::empty(Interner);
|
||||
};
|
||||
let (parent_params, self_params, type_params, const_params, impl_trait_params) =
|
||||
def_generics.map_or((0, 0, 0, 0, 0), |g| g.provenance_split());
|
||||
def_generics.provenance_split();
|
||||
let total_len =
|
||||
parent_params + self_params + type_params + const_params + impl_trait_params;
|
||||
|
||||
substs.extend(iter::repeat(TyKind::Error.intern(Interner)).take(parent_params));
|
||||
let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
|
||||
let const_error = GenericArgData::Const(consteval::usize_const(None)).intern(Interner);
|
||||
|
||||
for (_, data) in def_generics.iter().take(parent_params) {
|
||||
match data {
|
||||
TypeOrConstParamData::TypeParamData(_) => substs.push(ty_error.clone()),
|
||||
TypeOrConstParamData::ConstParamData(_) => substs.push(const_error.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
let fill_self_params = || {
|
||||
substs.extend(
|
||||
explicit_self_ty
|
||||
.into_iter()
|
||||
.chain(iter::repeat(TyKind::Error.intern(Interner)))
|
||||
.map(|x| GenericArgData::Ty(x).intern(Interner))
|
||||
.chain(iter::repeat(ty_error.clone()))
|
||||
.take(self_params),
|
||||
)
|
||||
};
|
||||
let mut had_explicit_type_args = false;
|
||||
let mut had_explicit_args = false;
|
||||
|
||||
if let Some(generic_args) = &segment.args_and_bindings {
|
||||
if !generic_args.has_self_type {
|
||||
fill_self_params();
|
||||
}
|
||||
let expected_num =
|
||||
if generic_args.has_self_type { self_params + type_params } else { type_params };
|
||||
let expected_num = if generic_args.has_self_type {
|
||||
self_params + type_params + const_params
|
||||
} else {
|
||||
type_params + const_params
|
||||
};
|
||||
let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 };
|
||||
// if args are provided, it should be all of them, but we can't rely on that
|
||||
for arg in generic_args
|
||||
for (arg, id) in generic_args
|
||||
.args
|
||||
.iter()
|
||||
.filter(|arg| matches!(arg, GenericArg::Type(_)))
|
||||
.filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
|
||||
.skip(skip)
|
||||
.take(expected_num)
|
||||
.zip(def_generics.iter_id().skip(skip))
|
||||
{
|
||||
match arg {
|
||||
GenericArg::Type(type_ref) => {
|
||||
had_explicit_type_args = true;
|
||||
let ty = self.lower_ty(type_ref);
|
||||
substs.push(ty);
|
||||
}
|
||||
GenericArg::Lifetime(_) => {}
|
||||
if let Some(x) = generic_arg_to_chalk(
|
||||
self.db,
|
||||
id,
|
||||
arg,
|
||||
&mut (),
|
||||
|_, type_ref| self.lower_ty(type_ref),
|
||||
|_, c| {
|
||||
const_or_path_to_chalk(
|
||||
self.db,
|
||||
&self.resolver,
|
||||
c,
|
||||
self.type_param_mode,
|
||||
|| self.generics(),
|
||||
DebruijnIndex::INNERMOST,
|
||||
)
|
||||
},
|
||||
) {
|
||||
had_explicit_args = true;
|
||||
substs.push(x);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -692,7 +742,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
// handle defaults. In expression or pattern path segments without
|
||||
// explicitly specified type arguments, missing type arguments are inferred
|
||||
// (i.e. defaults aren't used).
|
||||
if !infer_args || had_explicit_type_args {
|
||||
if !infer_args || had_explicit_args {
|
||||
if let Some(def_generic) = def_generic {
|
||||
let defaults = self.db.generic_defaults(def_generic);
|
||||
assert_eq!(total_len, defaults.len());
|
||||
|
@ -707,8 +757,11 @@ impl<'a> TyLoweringContext<'a> {
|
|||
|
||||
// add placeholders for args that were not provided
|
||||
// FIXME: emit diagnostics in contexts where this is not allowed
|
||||
for _ in substs.len()..total_len {
|
||||
substs.push(TyKind::Error.intern(Interner));
|
||||
for (_, data) in def_generics.iter().skip(substs.len()) {
|
||||
match data {
|
||||
TypeOrConstParamData::TypeParamData(_) => substs.push(ty_error.clone()),
|
||||
TypeOrConstParamData::ConstParamData(_) => substs.push(const_error.clone()),
|
||||
}
|
||||
}
|
||||
assert_eq!(substs.len(), total_len);
|
||||
|
||||
|
@ -775,8 +828,8 @@ impl<'a> TyLoweringContext<'a> {
|
|||
};
|
||||
let placeholder = to_placeholder_idx(self.db, param_id);
|
||||
match self.type_param_mode {
|
||||
TypeParamLoweringMode::Placeholder => TyKind::Placeholder(placeholder),
|
||||
TypeParamLoweringMode::Variable => {
|
||||
ParamLoweringMode::Placeholder => TyKind::Placeholder(placeholder),
|
||||
ParamLoweringMode::Variable => {
|
||||
let idx = generics.param_idx(param_id).expect("matching generics");
|
||||
TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, idx))
|
||||
}
|
||||
|
@ -919,8 +972,7 @@ impl<'a> TyLoweringContext<'a> {
|
|||
}
|
||||
predicates
|
||||
});
|
||||
|
||||
ReturnTypeImplTrait { bounds: crate::make_only_type_binders(1, predicates) }
|
||||
ReturnTypeImplTrait { bounds: crate::make_single_type_binders(predicates) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -999,7 +1051,7 @@ fn named_associated_type_shorthand_candidates<R>(
|
|||
// Handle `Self::Type` referring to own associated type in trait definitions
|
||||
if let GenericDefId::TraitId(trait_id) = param_id.parent() {
|
||||
let generics = generics(db.upcast(), trait_id.into());
|
||||
if generics.params.tocs[param_id.local_id()].is_trait_self() {
|
||||
if generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
|
||||
let trait_ref = TyBuilder::trait_ref(db, trait_id)
|
||||
.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
|
||||
.build();
|
||||
|
@ -1026,9 +1078,9 @@ pub(crate) fn field_types_query(
|
|||
let generics = generics(db.upcast(), def);
|
||||
let mut res = ArenaMap::default();
|
||||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
|
||||
for (field_id, field_data) in var_data.fields().iter() {
|
||||
res.insert(field_id, make_binders(&generics, ctx.lower_ty(&field_data.type_ref)))
|
||||
res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref)))
|
||||
}
|
||||
Arc::new(res)
|
||||
}
|
||||
|
@ -1049,7 +1101,7 @@ pub(crate) fn generic_predicates_for_param_query(
|
|||
) -> Arc<[Binders<QuantifiedWhereClause>]> {
|
||||
let resolver = def.resolver(db.upcast());
|
||||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
|
||||
let generics = generics(db.upcast(), def);
|
||||
let mut predicates: Vec<_> = resolver
|
||||
.where_predicates_in_scope()
|
||||
|
@ -1097,14 +1149,16 @@ pub(crate) fn generic_predicates_for_param_query(
|
|||
}
|
||||
WherePredicate::Lifetime { .. } => false,
|
||||
})
|
||||
.flat_map(|pred| ctx.lower_where_predicate(pred, true).map(|p| make_binders(&generics, p)))
|
||||
.flat_map(|pred| {
|
||||
ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let subst = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
|
||||
let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
|
||||
let explicitly_unsized_tys = ctx.unsized_types.into_inner();
|
||||
let implicitly_sized_predicates =
|
||||
implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &subst, &resolver)
|
||||
.map(|p| make_binders(&generics, crate::wrap_empty_binders(p)));
|
||||
.map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p)));
|
||||
predicates.extend(implicitly_sized_predicates);
|
||||
predicates.into()
|
||||
}
|
||||
|
@ -1124,8 +1178,8 @@ pub(crate) fn trait_environment_query(
|
|||
def: GenericDefId,
|
||||
) -> Arc<TraitEnvironment> {
|
||||
let resolver = def.resolver(db.upcast());
|
||||
let ctx = TyLoweringContext::new(db, &resolver)
|
||||
.with_type_param_mode(TypeParamLoweringMode::Placeholder);
|
||||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Placeholder);
|
||||
let mut traits_in_scope = Vec::new();
|
||||
let mut clauses = Vec::new();
|
||||
for pred in resolver.where_predicates_in_scope() {
|
||||
|
@ -1153,14 +1207,14 @@ pub(crate) fn trait_environment_query(
|
|||
// function default implementations (and speculative code
|
||||
// inside consts or type aliases)
|
||||
cov_mark::hit!(trait_self_implements_self);
|
||||
let substs = TyBuilder::type_params_subst(db, trait_id);
|
||||
let substs = TyBuilder::placeholder_subst(db, trait_id);
|
||||
let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
|
||||
let pred = WhereClause::Implemented(trait_ref);
|
||||
let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
|
||||
clauses.push(program_clause.into_from_env_clause(Interner));
|
||||
}
|
||||
|
||||
let subst = generics(db.upcast(), def).type_params_subst(db);
|
||||
let subst = generics(db.upcast(), def).placeholder_subst(db);
|
||||
let explicitly_unsized_tys = ctx.unsized_types.into_inner();
|
||||
let implicitly_sized_clauses =
|
||||
implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver).map(|pred| {
|
||||
|
@ -1183,19 +1237,21 @@ pub(crate) fn generic_predicates_query(
|
|||
) -> Arc<[Binders<QuantifiedWhereClause>]> {
|
||||
let resolver = def.resolver(db.upcast());
|
||||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
|
||||
let generics = generics(db.upcast(), def);
|
||||
|
||||
let mut predicates = resolver
|
||||
.where_predicates_in_scope()
|
||||
.flat_map(|pred| ctx.lower_where_predicate(pred, false).map(|p| make_binders(&generics, p)))
|
||||
.flat_map(|pred| {
|
||||
ctx.lower_where_predicate(pred, false).map(|p| make_binders(db, &generics, p))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let subst = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
|
||||
let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
|
||||
let explicitly_unsized_tys = ctx.unsized_types.into_inner();
|
||||
let implicitly_sized_predicates =
|
||||
implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
|
||||
.map(|p| make_binders(&generics, crate::wrap_empty_binders(p)));
|
||||
.map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p)));
|
||||
predicates.extend(implicitly_sized_predicates);
|
||||
predicates.into()
|
||||
}
|
||||
|
@ -1234,40 +1290,36 @@ fn implicitly_sized_clauses<'a>(
|
|||
pub(crate) fn generic_defaults_query(
|
||||
db: &dyn HirDatabase,
|
||||
def: GenericDefId,
|
||||
) -> Arc<[Binders<Ty>]> {
|
||||
) -> Arc<[Binders<chalk_ir::GenericArg<Interner>>]> {
|
||||
let resolver = def.resolver(db.upcast());
|
||||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
|
||||
let generic_params = generics(db.upcast(), def);
|
||||
|
||||
let defaults = generic_params
|
||||
.toc_iter()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, (_, p))| {
|
||||
.map(|(idx, (id, p))| {
|
||||
let p = match p {
|
||||
TypeOrConstParamData::TypeParamData(p) => p,
|
||||
TypeOrConstParamData::ConstParamData(_) => {
|
||||
// FIXME: here we should add const generic parameters
|
||||
let ty = TyKind::Error.intern(Interner);
|
||||
return crate::make_only_type_binders(idx, ty);
|
||||
// FIXME: implement const generic defaults
|
||||
let val = unknown_const_as_generic(
|
||||
db.const_param_ty(ConstParamId::from_unchecked(id)),
|
||||
);
|
||||
return crate::make_binders_with_count(db, idx, &generic_params, val);
|
||||
}
|
||||
};
|
||||
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.
|
||||
ty = crate::fold_free_vars(ty, |bound, binders| {
|
||||
if bound.index >= idx && bound.debruijn == DebruijnIndex::INNERMOST {
|
||||
// type variable default referring to parameter coming
|
||||
// after it. This is forbidden (FIXME: report
|
||||
// diagnostic)
|
||||
TyKind::Error.intern(Interner)
|
||||
} else {
|
||||
bound.shifted_in_from(binders).to_ty(Interner)
|
||||
}
|
||||
});
|
||||
|
||||
crate::make_only_type_binders(idx, ty)
|
||||
ty = fallback_bound_vars(ty, idx);
|
||||
let val = GenericArgData::Ty(ty).intern(Interner);
|
||||
crate::make_binders_with_count(db, idx, &generic_params, val)
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -1278,17 +1330,21 @@ pub(crate) fn generic_defaults_recover(
|
|||
db: &dyn HirDatabase,
|
||||
_cycle: &[String],
|
||||
def: &GenericDefId,
|
||||
) -> Arc<[Binders<Ty>]> {
|
||||
) -> Arc<[Binders<crate::GenericArg>]> {
|
||||
let generic_params = generics(db.upcast(), *def);
|
||||
|
||||
// FIXME: this code is not covered in tests.
|
||||
// we still need one default per parameter
|
||||
let defaults = generic_params
|
||||
.toc_iter()
|
||||
.iter_id()
|
||||
.enumerate()
|
||||
.map(|(idx, _)| {
|
||||
let ty = TyKind::Error.intern(Interner);
|
||||
|
||||
crate::make_only_type_binders(idx, ty)
|
||||
.map(|(count, id)| {
|
||||
let val = match id {
|
||||
itertools::Either::Left(_) => {
|
||||
GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
|
||||
}
|
||||
itertools::Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
|
||||
};
|
||||
crate::make_binders_with_count(db, count, &generic_params, val)
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -1300,26 +1356,27 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
|
|||
let resolver = def.resolver(db.upcast());
|
||||
let ctx_params = TyLoweringContext::new(db, &resolver)
|
||||
.with_impl_trait_mode(ImplTraitLoweringMode::Variable)
|
||||
.with_type_param_mode(TypeParamLoweringMode::Variable);
|
||||
.with_type_param_mode(ParamLoweringMode::Variable);
|
||||
let params = data.params.iter().map(|(_, tr)| ctx_params.lower_ty(tr)).collect::<Vec<_>>();
|
||||
let ctx_ret = TyLoweringContext::new(db, &resolver)
|
||||
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
|
||||
.with_type_param_mode(TypeParamLoweringMode::Variable);
|
||||
.with_type_param_mode(ParamLoweringMode::Variable);
|
||||
let ret = ctx_ret.lower_ty(&data.ret_type);
|
||||
let generics = generics(db.upcast(), def.into());
|
||||
let mut sig = CallableSig::from_params_and_return(params, ret, data.is_varargs());
|
||||
if !data.legacy_const_generics_indices.is_empty() {
|
||||
sig.set_legacy_const_generics_indices(&data.legacy_const_generics_indices);
|
||||
}
|
||||
make_binders(&generics, sig)
|
||||
make_binders(db, &generics, sig)
|
||||
}
|
||||
|
||||
/// Build the declared type of a function. This should not need to look at the
|
||||
/// function body.
|
||||
fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> {
|
||||
let generics = generics(db.upcast(), def.into());
|
||||
let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
|
||||
let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
|
||||
make_binders(
|
||||
db,
|
||||
&generics,
|
||||
TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(Interner),
|
||||
)
|
||||
|
@ -1331,9 +1388,9 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> {
|
|||
let generics = generics(db.upcast(), def.into());
|
||||
let resolver = def.resolver(db.upcast());
|
||||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
|
||||
|
||||
make_binders(&generics, ctx.lower_ty(&data.type_ref))
|
||||
make_binders(db, &generics, ctx.lower_ty(&data.type_ref))
|
||||
}
|
||||
|
||||
/// Build the declared type of a static.
|
||||
|
@ -1350,7 +1407,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
|
|||
let fields = struct_data.variant_data.fields();
|
||||
let resolver = def.resolver(db.upcast());
|
||||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
|
||||
let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
|
||||
let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
|
||||
Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
|
||||
|
@ -1363,8 +1420,9 @@ fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders<T
|
|||
return type_for_adt(db, def.into());
|
||||
}
|
||||
let generics = generics(db.upcast(), def.into());
|
||||
let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
|
||||
let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
|
||||
make_binders(
|
||||
db,
|
||||
&generics,
|
||||
TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(Interner),
|
||||
)
|
||||
|
@ -1376,7 +1434,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
|
|||
let fields = var_data.variant_data.fields();
|
||||
let resolver = def.parent.resolver(db.upcast());
|
||||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
|
||||
let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
|
||||
let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders();
|
||||
Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
|
||||
|
@ -1390,8 +1448,9 @@ fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -
|
|||
return type_for_adt(db, def.parent.into());
|
||||
}
|
||||
let generics = generics(db.upcast(), def.parent.into());
|
||||
let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
|
||||
let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
|
||||
make_binders(
|
||||
db,
|
||||
&generics,
|
||||
TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs).intern(Interner),
|
||||
)
|
||||
|
@ -1399,22 +1458,22 @@ fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -
|
|||
|
||||
fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
|
||||
let generics = generics(db.upcast(), adt.into());
|
||||
let b = TyBuilder::adt(db, adt);
|
||||
let ty = b.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build();
|
||||
make_binders(&generics, ty)
|
||||
let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
|
||||
let ty = TyKind::Adt(crate::AdtId(adt), subst).intern(Interner);
|
||||
make_binders(db, &generics, ty)
|
||||
}
|
||||
|
||||
fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
|
||||
let generics = generics(db.upcast(), t.into());
|
||||
let resolver = t.resolver(db.upcast());
|
||||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
|
||||
if db.type_alias_data(t).is_extern {
|
||||
Binders::empty(Interner, TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner))
|
||||
} else {
|
||||
let type_ref = &db.type_alias_data(t).type_ref;
|
||||
let inner = ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error));
|
||||
make_binders(&generics, inner)
|
||||
make_binders(db, &generics, inner)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1485,7 +1544,7 @@ pub(crate) fn ty_recover(db: &dyn HirDatabase, _cycle: &[String], def: &TyDefId)
|
|||
TyDefId::AdtId(it) => generics(db.upcast(), it.into()),
|
||||
TyDefId::TypeAliasId(it) => generics(db.upcast(), it.into()),
|
||||
};
|
||||
make_binders(&generics, TyKind::Error.intern(Interner))
|
||||
make_binders(db, &generics, TyKind::Error.intern(Interner))
|
||||
}
|
||||
|
||||
pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders<Ty> {
|
||||
|
@ -1509,14 +1568,14 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde
|
|||
));
|
||||
let generics = generics(db.upcast(), impl_id.into());
|
||||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
|
||||
make_binders(&generics, ctx.lower_ty(&impl_data.self_ty))
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
|
||||
make_binders(db, &generics, ctx.lower_ty(&impl_data.self_ty))
|
||||
}
|
||||
|
||||
// returns None if def is a type arg
|
||||
pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
|
||||
let parent_data = db.generic_params(def.parent());
|
||||
let data = &parent_data.tocs[def.local_id()];
|
||||
let data = &parent_data.type_or_consts[def.local_id()];
|
||||
let resolver = def.parent().resolver(db.upcast());
|
||||
let ctx = TyLoweringContext::new(db, &resolver);
|
||||
match data {
|
||||
|
@ -1534,7 +1593,7 @@ pub(crate) fn impl_self_ty_recover(
|
|||
impl_id: &ImplId,
|
||||
) -> Binders<Ty> {
|
||||
let generics = generics(db.upcast(), (*impl_id).into());
|
||||
make_binders(&generics, TyKind::Error.intern(Interner))
|
||||
make_binders(db, &generics, TyKind::Error.intern(Interner))
|
||||
}
|
||||
|
||||
pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
|
||||
|
@ -1546,7 +1605,7 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<
|
|||
impl_id, impl_loc, impl_data
|
||||
));
|
||||
let ctx =
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
|
||||
TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
|
||||
let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
|
||||
let target_trait = impl_data.target_trait.as_ref()?;
|
||||
Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, Some(self_ty))?))
|
||||
|
@ -1561,7 +1620,7 @@ pub(crate) fn return_type_impl_traits(
|
|||
let resolver = def.resolver(db.upcast());
|
||||
let ctx_ret = TyLoweringContext::new(db, &resolver)
|
||||
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
|
||||
.with_type_param_mode(TypeParamLoweringMode::Variable);
|
||||
.with_type_param_mode(ParamLoweringMode::Variable);
|
||||
let _ret = (&ctx_ret).lower_ty(&data.ret_type);
|
||||
let generics = generics(db.upcast(), def.into());
|
||||
let return_type_impl_traits =
|
||||
|
@ -1569,7 +1628,7 @@ pub(crate) fn return_type_impl_traits(
|
|||
if return_type_impl_traits.impl_traits.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Arc::new(make_binders(&generics, return_type_impl_traits)))
|
||||
Some(Arc::new(make_binders(db, &generics, return_type_impl_traits)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1580,6 +1639,65 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut
|
|||
}
|
||||
}
|
||||
|
||||
fn make_binders<T: HasInterner<Interner = Interner>>(generics: &Generics, value: T) -> Binders<T> {
|
||||
crate::make_only_type_binders(generics.len(), value)
|
||||
pub(crate) fn generic_arg_to_chalk<'a, T>(
|
||||
db: &dyn HirDatabase,
|
||||
kind_id: Either<TypeParamId, ConstParamId>,
|
||||
arg: &'a GenericArg,
|
||||
this: &mut T,
|
||||
for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
|
||||
for_const: impl FnOnce(&mut T, &ConstScalarOrPath) -> Const + 'a,
|
||||
) -> Option<crate::GenericArg> {
|
||||
let kind = match kind_id {
|
||||
Either::Left(_) => ParamKind::Type,
|
||||
Either::Right(id) => {
|
||||
let ty = db.const_param_ty(id);
|
||||
ParamKind::Const(ty)
|
||||
}
|
||||
};
|
||||
Some(match (arg, kind) {
|
||||
(GenericArg::Type(type_ref), ParamKind::Type) => {
|
||||
let ty = for_type(this, type_ref);
|
||||
GenericArgData::Ty(ty).intern(Interner)
|
||||
}
|
||||
(GenericArg::Const(c), ParamKind::Const(_)) => {
|
||||
GenericArgData::Const(for_const(this, c)).intern(Interner)
|
||||
}
|
||||
(GenericArg::Const(_), ParamKind::Type) => {
|
||||
GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
|
||||
}
|
||||
(GenericArg::Type(t), ParamKind::Const(ty)) => {
|
||||
// We want to recover simple idents, which parser detects them
|
||||
// as types. Maybe here is not the best place to do it, but
|
||||
// it works.
|
||||
if let TypeRef::Path(p) = t {
|
||||
let p = p.mod_path();
|
||||
if p.kind == PathKind::Plain {
|
||||
if let [n] = p.segments() {
|
||||
let c = ConstScalarOrPath::Path(n.clone());
|
||||
return Some(GenericArgData::Const(for_const(this, &c)).intern(Interner));
|
||||
}
|
||||
}
|
||||
}
|
||||
unknown_const_as_generic(ty)
|
||||
}
|
||||
(GenericArg::Lifetime(_), _) => return None,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn const_or_path_to_chalk(
|
||||
db: &dyn HirDatabase,
|
||||
resolver: &Resolver,
|
||||
value: &ConstScalarOrPath,
|
||||
mode: ParamLoweringMode,
|
||||
args: impl FnOnce() -> Generics,
|
||||
debruijn: DebruijnIndex,
|
||||
) -> Const {
|
||||
match value {
|
||||
ConstScalarOrPath::Scalar(s) => usize_const(s.as_usize()),
|
||||
ConstScalarOrPath::Path(n) => {
|
||||
let path = ModPath::from_segments(PathKind::Plain, Some(n.clone()));
|
||||
path_to_const(db, resolver, &path, mode, args, debruijn)
|
||||
.unwrap_or_else(|| unknown_const_usize())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::{iter, ops::ControlFlow, sync::Arc};
|
|||
|
||||
use arrayvec::ArrayVec;
|
||||
use base_db::{CrateId, Edition};
|
||||
use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
|
||||
use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, Mutability, UniverseIndex};
|
||||
use hir_def::{
|
||||
item_scope::ItemScope, lang_item::LangItemTarget, nameres::DefMap, AssocItemId, BlockId,
|
||||
ConstId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId,
|
||||
|
@ -25,8 +25,9 @@ use crate::{
|
|||
primitive::{self, FloatTy, IntTy, UintTy},
|
||||
static_lifetime,
|
||||
utils::all_super_traits,
|
||||
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
|
||||
Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
|
||||
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, GenericArgData,
|
||||
InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder,
|
||||
TyExt, TyKind,
|
||||
};
|
||||
|
||||
/// This is used as a key for indexing impls.
|
||||
|
@ -1087,13 +1088,14 @@ pub(crate) fn inherent_impl_substs(
|
|||
.build();
|
||||
let self_ty_with_vars = db.impl_self_ty(impl_id).substitute(Interner, &vars);
|
||||
let mut kinds = self_ty.binders.interned().to_vec();
|
||||
kinds.extend(
|
||||
iter::repeat(chalk_ir::WithKind::new(
|
||||
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
|
||||
UniverseIndex::ROOT,
|
||||
))
|
||||
.take(vars.len(Interner)),
|
||||
);
|
||||
kinds.extend(vars.iter(Interner).map(|x| {
|
||||
let kind = match x.data(Interner) {
|
||||
GenericArgData::Ty(_) => chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
|
||||
GenericArgData::Const(c) => chalk_ir::VariableKind::Const(c.data(Interner).ty.clone()),
|
||||
GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
|
||||
};
|
||||
chalk_ir::WithKind::new(kind, UniverseIndex::ROOT)
|
||||
}));
|
||||
let tys = Canonical {
|
||||
binders: CanonicalVarKinds::from_iter(Interner, kinds),
|
||||
value: (self_ty_with_vars, self_ty.value.clone()),
|
||||
|
@ -1111,14 +1113,27 @@ pub(crate) fn inherent_impl_substs(
|
|||
|
||||
/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
|
||||
/// num_vars_to_keep) by `TyKind::Unknown`.
|
||||
fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution {
|
||||
crate::fold_free_vars(s, |bound, binders| {
|
||||
pub(crate) fn fallback_bound_vars<T: Fold<Interner> + HasInterner<Interner = Interner>>(
|
||||
s: T,
|
||||
num_vars_to_keep: usize,
|
||||
) -> T::Result {
|
||||
crate::fold_free_vars(
|
||||
s,
|
||||
|bound, binders| {
|
||||
if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
|
||||
TyKind::Error.intern(Interner)
|
||||
} else {
|
||||
bound.shifted_in_from(binders).to_ty(Interner)
|
||||
}
|
||||
})
|
||||
},
|
||||
|ty, bound, binders| {
|
||||
if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
|
||||
consteval::usize_const(None)
|
||||
} else {
|
||||
bound.shifted_in_from(binders).to_const(Interner, ty)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn transform_receiver_ty(
|
||||
|
@ -1183,13 +1198,18 @@ fn generic_implements_goal(
|
|||
.push(self_ty.value.clone())
|
||||
.fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
|
||||
.build();
|
||||
kinds.extend(
|
||||
iter::repeat(chalk_ir::WithKind::new(
|
||||
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
|
||||
UniverseIndex::ROOT,
|
||||
))
|
||||
.take(trait_ref.substitution.len(Interner) - 1),
|
||||
);
|
||||
kinds.extend(trait_ref.substitution.iter(Interner).skip(1).map(|x| {
|
||||
let vk = match x.data(Interner) {
|
||||
chalk_ir::GenericArgData::Ty(_) => {
|
||||
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
|
||||
}
|
||||
chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
|
||||
chalk_ir::GenericArgData::Const(c) => {
|
||||
chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
|
||||
}
|
||||
};
|
||||
chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
|
||||
}));
|
||||
let obligation = trait_ref.cast(Interner);
|
||||
Canonical {
|
||||
binders: CanonicalVarKinds::from_iter(Interner, kinds),
|
||||
|
|
|
@ -1359,7 +1359,69 @@ impl<T> [T] {
|
|||
fn f() {
|
||||
let v = [1, 2].map::<_, usize>(|x| -> x * 2);
|
||||
v;
|
||||
//^ [usize; _]
|
||||
//^ [usize; 2]
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_const_generic_method() {
|
||||
check_types(
|
||||
r#"
|
||||
struct Const<const N: usize>;
|
||||
|
||||
#[lang = "array"]
|
||||
impl<T, const N: usize> [T; N] {
|
||||
pub fn my_map<F, U, const X: usize>(self, f: F, c: Const<X>) -> [U; X]
|
||||
where
|
||||
F: FnMut(T) -> U,
|
||||
{ loop {} }
|
||||
}
|
||||
|
||||
#[lang = "slice"]
|
||||
impl<T> [T] {
|
||||
pub fn my_map<F, const X: usize, U>(self, f: F, c: Const<X>) -> &[U]
|
||||
where
|
||||
F: FnMut(T) -> U,
|
||||
{ loop {} }
|
||||
}
|
||||
|
||||
fn f<const C: usize, P>() {
|
||||
let v = [1, 2].my_map::<_, (), 12>(|x| -> x * 2, Const::<12>);
|
||||
v;
|
||||
//^ [(); 12]
|
||||
let v = [1, 2].my_map::<_, P, C>(|x| -> x * 2, Const::<C>);
|
||||
v;
|
||||
//^ [P; C]
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_generic_type_alias() {
|
||||
check_types(
|
||||
r#"
|
||||
struct Const<const N: usize>;
|
||||
type U2 = Const<2>;
|
||||
type U5 = Const<5>;
|
||||
|
||||
impl U2 {
|
||||
fn f(self) -> Const<12> {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl U5 {
|
||||
fn f(self) -> Const<15> {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
fn f(x: U2) {
|
||||
let y = x.f();
|
||||
//^ Const<12>
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
|
|
@ -1301,7 +1301,7 @@ impl<I: Iterator> IntoIterator for I {
|
|||
|
||||
#[test]
|
||||
fn bug_11659() {
|
||||
check_infer(
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
struct LinkArray<const N: usize, LD>(LD);
|
||||
fn f<const N: usize, LD>(x: LD) -> LinkArray<N, LD> {
|
||||
|
@ -1314,26 +1314,8 @@ fn test() {
|
|||
let y = LinkArray::<52, LinkArray<2, i32>>(x);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
67..68 'x': LD
|
||||
94..138 '{ ... r }': LinkArray<{unknown}, LD>
|
||||
104..105 'r': LinkArray<{unknown}, LD>
|
||||
108..126 'LinkAr...N, LD>': LinkArray<{unknown}, LD>(LD) -> LinkArray<{unknown}, LD>
|
||||
108..129 'LinkAr...LD>(x)': LinkArray<{unknown}, LD>
|
||||
127..128 'x': LD
|
||||
135..136 'r': LinkArray<{unknown}, LD>
|
||||
150..232 '{ ...(x); }': ()
|
||||
160..161 'x': LinkArray<{unknown}, {unknown}>
|
||||
164..175 'f::<2, i32>': fn f<i32, i32>(i32) -> LinkArray<{unknown}, {unknown}>
|
||||
164..178 'f::<2, i32>(5)': LinkArray<{unknown}, {unknown}>
|
||||
176..177 '5': i32
|
||||
188..189 'y': LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>
|
||||
192..226 'LinkAr... i32>>': LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>(LinkArray<{unknown}, {unknown}>) -> LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>
|
||||
192..229 'LinkAr...2>>(x)': LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>
|
||||
227..228 'x': LinkArray<{unknown}, {unknown}>
|
||||
"#]],
|
||||
);
|
||||
check_infer(
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
struct LinkArray<LD, const N: usize>(LD);
|
||||
fn f<const N: usize, LD>(x: LD) -> LinkArray<LD, N> {
|
||||
|
@ -1346,23 +1328,106 @@ fn test() {
|
|||
let y = LinkArray::<LinkArray<i32, 2>, 52>(x);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
67..68 'x': LD
|
||||
94..138 '{ ... r }': LinkArray<LD, {unknown}>
|
||||
104..105 'r': LinkArray<LD, {unknown}>
|
||||
108..126 'LinkAr...LD, N>': LinkArray<LD, {unknown}>(LD) -> LinkArray<LD, {unknown}>
|
||||
108..129 'LinkAr... N>(x)': LinkArray<LD, {unknown}>
|
||||
127..128 'x': LD
|
||||
135..136 'r': LinkArray<LD, {unknown}>
|
||||
150..232 '{ ...(x); }': ()
|
||||
160..161 'x': LinkArray<i32, {unknown}>
|
||||
164..175 'f::<i32, 2>': fn f<i32, i32>(i32) -> LinkArray<i32, {unknown}>
|
||||
164..178 'f::<i32, 2>(5)': LinkArray<i32, {unknown}>
|
||||
176..177 '5': i32
|
||||
188..189 'y': LinkArray<LinkArray<i32, {unknown}>, {unknown}>
|
||||
192..226 'LinkAr...>, 52>': LinkArray<LinkArray<i32, {unknown}>, {unknown}>(LinkArray<i32, {unknown}>) -> LinkArray<LinkArray<i32, {unknown}>, {unknown}>
|
||||
192..229 'LinkAr...52>(x)': LinkArray<LinkArray<i32, {unknown}>, {unknown}>
|
||||
227..228 'x': LinkArray<i32, {unknown}>
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_generic_error_tolerance() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
#[lang = "sized"]
|
||||
pub trait Sized {}
|
||||
|
||||
struct CT<const N: usize, T>(T);
|
||||
struct TC<T, const N: usize>(T);
|
||||
fn f<const N: usize, T>(x: T) -> (CT<N, T>, TC<T, N>) {
|
||||
let l = CT::<N, T>(x);
|
||||
let r = TC::<N, T>(x);
|
||||
(l, r)
|
||||
}
|
||||
|
||||
trait TR1<const N: usize>;
|
||||
trait TR2<const N: usize>;
|
||||
|
||||
impl<const N: usize, T> TR1<N> for CT<N, T>;
|
||||
impl<const N: usize, T> TR1<5> for TC<T, N>;
|
||||
impl<const N: usize, T> TR2<N> for CT<T, N>;
|
||||
|
||||
trait TR3<const N: usize> {
|
||||
fn tr3(&self) -> &Self;
|
||||
}
|
||||
|
||||
impl<const N: usize, T> TR3<5> for TC<T, N> {
|
||||
fn tr3(&self) -> &Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize, T> TR3<Item = 5> for TC<T, N> {}
|
||||
impl<const N: usize, T> TR3<T> for TC<T, N> {}
|
||||
|
||||
fn impl_trait<const N: usize>(inp: impl TR1<N>) {}
|
||||
fn dyn_trait<const N: usize>(inp: &dyn TR2<N>) {}
|
||||
fn impl_trait_bad<'a, const N: usize>(inp: impl TR1<i32>) -> impl TR1<'a, i32> {}
|
||||
fn impl_trait_very_bad<const N: usize>(inp: impl TR1<Item = i32>) -> impl TR1<'a, Item = i32, 5, Foo = N> {}
|
||||
|
||||
fn test() {
|
||||
f::<2, i32>(5);
|
||||
f::<2, 2>(5);
|
||||
f(5);
|
||||
f::<i32>(5);
|
||||
CT::<52, CT<2, i32>>(x);
|
||||
CT::<CT<2, i32>>(x);
|
||||
impl_trait_bad(5);
|
||||
impl_trait_bad(12);
|
||||
TR3<5>::tr3();
|
||||
TR3<{ 2+3 }>::tr3();
|
||||
TC::<i32, 10>(5).tr3();
|
||||
TC::<i32, 20>(5).tr3();
|
||||
TC::<i32, i32>(5).tr3();
|
||||
TC::<i32, { 7 + 3 }>(5).tr3();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_generic_impl_trait() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
//- minicore: from
|
||||
|
||||
struct Foo<T, const M: usize>;
|
||||
|
||||
trait Tr<T> {
|
||||
fn f(T) -> Self;
|
||||
}
|
||||
|
||||
impl<T, const M: usize> Tr<[T; M]> for Foo<T, M> {
|
||||
fn f(_: [T; M]) -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
fn test() {
|
||||
Foo::f([1, 2, 7, 10]);
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nalgebra_factorial() {
|
||||
check_no_mismatches(
|
||||
r#"
|
||||
const FACTORIAL: [u128; 4] = [1, 1, 2, 6];
|
||||
|
||||
fn factorial(n: usize) -> u128 {
|
||||
match FACTORIAL.get(n) {
|
||||
Some(f) => *f,
|
||||
None => panic!("{}! is greater than u128::MAX", n),
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1202,14 +1202,13 @@ fn infer_array() {
|
|||
|
||||
let b = [a, ["b"]];
|
||||
let x: [u8; 0] = [];
|
||||
// FIXME: requires const evaluation/taking type from rhs somehow
|
||||
let y: [u8; 2+2] = [1,2,3,4];
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
8..9 'x': &str
|
||||
17..18 'y': isize
|
||||
27..395 '{ ...,4]; }': ()
|
||||
27..326 '{ ...,4]; }': ()
|
||||
37..38 'a': [&str; 1]
|
||||
41..44 '[x]': [&str; 1]
|
||||
42..43 'x': &str
|
||||
|
@ -1259,12 +1258,12 @@ fn infer_array() {
|
|||
259..262 '"b"': &str
|
||||
274..275 'x': [u8; 0]
|
||||
287..289 '[]': [u8; 0]
|
||||
368..369 'y': [u8; _]
|
||||
383..392 '[1,2,3,4]': [u8; 4]
|
||||
384..385 '1': u8
|
||||
386..387 '2': u8
|
||||
388..389 '3': u8
|
||||
390..391 '4': u8
|
||||
299..300 'y': [u8; 4]
|
||||
314..323 '[1,2,3,4]': [u8; 4]
|
||||
315..316 '1': u8
|
||||
317..318 '2': u8
|
||||
319..320 '3': u8
|
||||
321..322 '4': u8
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3394,7 +3394,6 @@ fn main() {
|
|||
)
|
||||
}
|
||||
|
||||
// FIXME: We should infer the length of the returned array :)
|
||||
#[test]
|
||||
fn const_generics() {
|
||||
check_infer(
|
||||
|
@ -3418,18 +3417,18 @@ fn main() {
|
|||
"#,
|
||||
expect![[r#"
|
||||
44..48 'self': &Self
|
||||
151..155 'self': &[u8; _]
|
||||
173..194 '{ ... }': [u8; _]
|
||||
183..188 '*self': [u8; _]
|
||||
184..188 'self': &[u8; _]
|
||||
151..155 'self': &[u8; L]
|
||||
173..194 '{ ... }': [u8; L]
|
||||
183..188 '*self': [u8; L]
|
||||
184..188 'self': &[u8; L]
|
||||
208..260 '{ ...g(); }': ()
|
||||
218..219 'v': [u8; 2]
|
||||
222..230 '[0u8; 2]': [u8; 2]
|
||||
223..226 '0u8': u8
|
||||
228..229 '2': usize
|
||||
240..242 'v2': [u8; _]
|
||||
240..242 'v2': [u8; 2]
|
||||
245..246 'v': [u8; 2]
|
||||
245..257 'v.do_thing()': [u8; _]
|
||||
245..257 'v.do_thing()': [u8; 2]
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
|
|
@ -15,16 +15,18 @@ use hir_def::{
|
|||
path::Path,
|
||||
resolver::{HasResolver, TypeNs},
|
||||
type_ref::{TraitBoundModifier, TypeRef},
|
||||
GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId,
|
||||
ConstParamId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId,
|
||||
TypeParamId,
|
||||
};
|
||||
use hir_expand::name::{name, Name};
|
||||
use itertools::Either;
|
||||
use rustc_hash::FxHashSet;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use syntax::SmolStr;
|
||||
|
||||
use crate::{
|
||||
db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, TyKind,
|
||||
WhereClause,
|
||||
db::HirDatabase, ChalkTraitId, ConstData, ConstValue, GenericArgData, Interner, Substitution,
|
||||
TraitRef, TraitRefExt, TyKind, WhereClause,
|
||||
};
|
||||
|
||||
pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> {
|
||||
|
@ -203,30 +205,43 @@ impl Generics {
|
|||
)
|
||||
}
|
||||
|
||||
pub(crate) fn toc_iter<'a>(
|
||||
pub(crate) fn iter_id<'a>(
|
||||
&'a self,
|
||||
) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
||||
) -> impl Iterator<Item = Either<TypeParamId, ConstParamId>> + 'a {
|
||||
self.iter().map(|(id, data)| match data {
|
||||
TypeOrConstParamData::TypeParamData(_) => Either::Left(TypeParamId::from_unchecked(id)),
|
||||
TypeOrConstParamData::ConstParamData(_) => {
|
||||
Either::Right(ConstParamId::from_unchecked(id))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Iterator over types and const params of parent, then self.
|
||||
pub(crate) fn iter<'a>(
|
||||
&'a self,
|
||||
) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
||||
self.parent_generics
|
||||
.as_ref()
|
||||
.into_iter()
|
||||
.flat_map(|it| {
|
||||
it.params
|
||||
.toc_iter()
|
||||
.iter()
|
||||
.map(move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p))
|
||||
})
|
||||
.chain(
|
||||
self.params.toc_iter().map(move |(local_id, p)| {
|
||||
self.params.iter().map(move |(local_id, p)| {
|
||||
(TypeOrConstParamId { parent: self.def, local_id }, p)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/// Iterator over types and const params of parent.
|
||||
pub(crate) fn iter_parent<'a>(
|
||||
&'a self,
|
||||
) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
|
||||
self.parent_generics.as_ref().into_iter().flat_map(|it| {
|
||||
it.params
|
||||
.tocs
|
||||
.type_or_consts
|
||||
.iter()
|
||||
.map(move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p))
|
||||
})
|
||||
|
@ -239,7 +254,7 @@ impl Generics {
|
|||
/// (total, parents, child)
|
||||
pub(crate) fn len_split(&self) -> (usize, usize, usize) {
|
||||
let parent = self.parent_generics.as_ref().map_or(0, |p| p.len());
|
||||
let child = self.params.tocs.len();
|
||||
let child = self.params.type_or_consts.len();
|
||||
(parent + child, parent, child)
|
||||
}
|
||||
|
||||
|
@ -248,22 +263,20 @@ impl Generics {
|
|||
let parent = self.parent_generics.as_ref().map_or(0, |p| p.len());
|
||||
let self_params = self
|
||||
.params
|
||||
.tocs
|
||||
.iter()
|
||||
.filter_map(|x| x.1.type_param())
|
||||
.filter(|p| p.provenance == TypeParamProvenance::TraitSelf)
|
||||
.count();
|
||||
let type_params = self
|
||||
.params
|
||||
.tocs
|
||||
.type_or_consts
|
||||
.iter()
|
||||
.filter_map(|x| x.1.type_param())
|
||||
.filter(|p| p.provenance == TypeParamProvenance::TypeParamList)
|
||||
.count();
|
||||
let const_params = self.params.tocs.iter().filter_map(|x| x.1.const_param()).count();
|
||||
let const_params = self.params.iter().filter_map(|x| x.1.const_param()).count();
|
||||
let impl_trait_params = self
|
||||
.params
|
||||
.tocs
|
||||
.iter()
|
||||
.filter_map(|x| x.1.type_param())
|
||||
.filter(|p| p.provenance == TypeParamProvenance::ArgumentImplTrait)
|
||||
|
@ -279,7 +292,7 @@ impl Generics {
|
|||
if param.parent == self.def {
|
||||
let (idx, (_local_id, data)) = self
|
||||
.params
|
||||
.tocs
|
||||
.type_or_consts
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, (idx, _))| *idx == param.local_id)
|
||||
|
@ -292,21 +305,47 @@ impl Generics {
|
|||
}
|
||||
|
||||
/// Returns a Substitution that replaces each parameter by a bound variable.
|
||||
pub(crate) fn bound_vars_subst(&self, debruijn: DebruijnIndex) -> Substitution {
|
||||
pub(crate) fn bound_vars_subst(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
debruijn: DebruijnIndex,
|
||||
) -> Substitution {
|
||||
Substitution::from_iter(
|
||||
Interner,
|
||||
self.toc_iter()
|
||||
.enumerate()
|
||||
.map(|(idx, _)| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner)),
|
||||
self.iter_id().enumerate().map(|(idx, id)| match id {
|
||||
Either::Left(_) => GenericArgData::Ty(
|
||||
TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner),
|
||||
)
|
||||
.intern(Interner),
|
||||
Either::Right(id) => GenericArgData::Const(
|
||||
ConstData {
|
||||
value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
|
||||
ty: db.const_param_ty(id),
|
||||
}
|
||||
.intern(Interner),
|
||||
)
|
||||
.intern(Interner),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`).
|
||||
pub(crate) fn type_params_subst(&self, db: &dyn HirDatabase) -> Substitution {
|
||||
pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution {
|
||||
Substitution::from_iter(
|
||||
Interner,
|
||||
self.toc_iter().map(|(id, _)| {
|
||||
TyKind::Placeholder(crate::to_placeholder_idx(db, id)).intern(Interner)
|
||||
self.iter_id().map(|id| match id {
|
||||
Either::Left(id) => GenericArgData::Ty(
|
||||
TyKind::Placeholder(crate::to_placeholder_idx(db, id.into())).intern(Interner),
|
||||
)
|
||||
.intern(Interner),
|
||||
Either::Right(id) => GenericArgData::Const(
|
||||
ConstData {
|
||||
value: ConstValue::Placeholder(crate::to_placeholder_idx(db, id.into())),
|
||||
ty: db.const_param_ty(id),
|
||||
}
|
||||
.intern(Interner),
|
||||
)
|
||||
.intern(Interner),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3361,6 +3361,27 @@ fn foo<T$0: Sized + ?Sized + Sized + Trait>() {}
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hover_const_generic_type_alias() {
|
||||
check(
|
||||
r#"
|
||||
struct Foo<const LEN: usize>;
|
||||
type Fo$0o2 = Foo<2>;
|
||||
"#,
|
||||
expect![[r#"
|
||||
*Foo2*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
type Foo2 = Foo<2>
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hover_const_param() {
|
||||
check(
|
||||
|
|
Loading…
Reference in a new issue