11688: Add const generics r=HKalbasi a=HKalbasi

#7434 is not in this PR, so there is no evaluation of constants and no default const argument. But the rest (type inference and method resolution with chalk) should work.

Chalk is pedantic about kind of generic arguments, and will panic in case of mixing type and const arguments. I tried to add test that, but I'm not sure if it covers all cases.


Co-authored-by: hkalbasi <hamidrezakalbasi@protonmail.com>
This commit is contained in:
bors[bot] 2022-03-14 11:15:00 +00:00 committed by GitHub
commit 20fa7cbcad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1272 additions and 527 deletions

16
Cargo.lock generated
View File

@ -171,9 +171,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "chalk-derive" name = "chalk-derive"
version = "0.76.0" version = "0.79.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58c24b8052ea1e3adbb6f9ab7ba5fcc18b9d12591c042de4c833f709ce81e0e0" checksum = "0b14364774396379d5c488e73d88e0a6d2b51acd0dac9c8359e2f84c58cf3a16"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -183,9 +183,9 @@ dependencies = [
[[package]] [[package]]
name = "chalk-ir" name = "chalk-ir"
version = "0.76.0" version = "0.79.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cad5c3f1edd4b4a2c9bda24ae558ceb4f88336f88f944c2e35d0bfeb13c818" checksum = "cd571e8931d3075f562a2d460bfe3028a9c7b343876765cce95b6143a76b882e"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"chalk-derive", "chalk-derive",
@ -194,9 +194,9 @@ dependencies = [
[[package]] [[package]]
name = "chalk-recursive" name = "chalk-recursive"
version = "0.76.0" version = "0.79.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e68ba0c7219f34738b66c0c992438c644ca33f4d8a29da3d41604299c7eaf419" checksum = "54ceedab35607f4680d02de80f8be005af0ad5c1dcfec56cfd849d33da5fe736"
dependencies = [ dependencies = [
"chalk-derive", "chalk-derive",
"chalk-ir", "chalk-ir",
@ -207,9 +207,9 @@ dependencies = [
[[package]] [[package]]
name = "chalk-solve" name = "chalk-solve"
version = "0.76.0" version = "0.79.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94533188d3452bc72cbd5618d166f45fc7646b674ad3fe9667d557bc25236dee" checksum = "9e31bb853cf921365759346db05d833f969e330462432bf38c9c2be1e78a9abd"
dependencies = [ dependencies = [
"chalk-derive", "chalk-derive",
"chalk-ir", "chalk-ir",

View File

@ -256,7 +256,7 @@ impl HirDisplay for TypeParam {
} }
let bounds = f.db.generic_predicates_for_param(self.id.parent(), self.id.into(), None); 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<_> = let predicates: Vec<_> =
bounds.iter().cloned().map(|b| b.substitute(Interner, &substs)).collect(); bounds.iter().cloned().map(|b| b.substitute(Interner, &substs)).collect();
let krate = self.id.parent().krate(f.db).id; 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> { fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
let params = f.db.generic_params(def); let params = f.db.generic_params(def);
if params.lifetimes.is_empty() if params.lifetimes.is_empty()
&& params.type_or_consts.iter().all(|x| x.1.const_param().is_none())
&& params && params
.tocs .type_or_consts
.iter() .iter()
.filter_map(|x| x.1.type_param()) .filter_map(|x| x.1.type_param())
.all(|param| !matches!(param.provenance, TypeParamProvenance::TypeParamList)) .all(|param| !matches!(param.provenance, TypeParamProvenance::TypeParamList))
@ -315,7 +316,7 @@ fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), H
delim(f)?; delim(f)?;
write!(f, "{}", lifetime.name)?; write!(f, "{}", lifetime.name)?;
} }
for (_, ty) in params.tocs.iter() { for (_, ty) in params.type_or_consts.iter() {
if let Some(name) = &ty.name() { if let Some(name) = &ty.name() {
match ty { match ty {
TypeOrConstParamData::TypeParamData(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`. // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
let is_unnamed_type_target = |target: &WherePredicateTypeTarget| match target { let is_unnamed_type_target = |target: &WherePredicateTypeTarget| match target {
WherePredicateTypeTarget::TypeRef(_) => false, 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 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 { let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter| match target {
WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f), WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
WherePredicateTypeTarget::TypeOrConstParam(id) => match &params.tocs[*id].name() { WherePredicateTypeTarget::TypeOrConstParam(id) => {
Some(name) => write!(f, "{}", name), match &params.type_or_consts[*id].name() {
None => write!(f, "{{unnamed}}"), Some(name) => write!(f, "{}", name),
}, None => write!(f, "{{unnamed}}"),
}
}
}; };
write!(f, "\nwhere")?; write!(f, "\nwhere")?;

View File

@ -55,7 +55,9 @@ use hir_def::{
use hir_expand::{name::name, MacroCallKind}; use hir_expand::{name::name, MacroCallKind};
use hir_ty::{ use hir_ty::{
autoderef, autoderef,
consteval::{eval_const, ComputedExpr, ConstEvalCtx, ConstEvalError, ConstExt}, consteval::{
eval_const, unknown_const_as_generic, ComputedExpr, ConstEvalCtx, ConstEvalError, ConstExt,
},
could_unify, could_unify,
diagnostics::BodyValidationDiagnostic, diagnostics::BodyValidationDiagnostic,
method_resolution::{self, TyFingerprint}, method_resolution::{self, TyFingerprint},
@ -63,9 +65,9 @@ use hir_ty::{
subst_prefix, subst_prefix,
traits::FnTrait, traits::FnTrait,
AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, Substitution, DebruijnIndex, GenericArgData, InEnvironment, Interner, ParamKind, QuantifiedWhereClause,
TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind, Scalar, Solution, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt,
WhereClause, TyKind, TyVariableKind, WhereClause,
}; };
use itertools::Itertools; use itertools::Itertools;
use nameres::diagnostics::DefDiagnosticKind; use nameres::diagnostics::DefDiagnosticKind;
@ -796,7 +798,7 @@ impl Field {
VariantDef::Union(it) => it.id.into(), VariantDef::Union(it) => it.id.into(),
VariantDef::Variant(it) => it.parent.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); 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) 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 { impl Adt {
pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
let subst = db.generic_defaults(self.into()); 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 /// Turns this ADT into a type. Any type parameters of the ADT will be
@ -1680,7 +1685,10 @@ pub struct TypeAlias {
impl TypeAlias { impl TypeAlias {
pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
let subst = db.generic_defaults(self.id.into()); 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 { pub fn module(self, db: &dyn HirDatabase) -> Module {
@ -2047,7 +2055,7 @@ impl_from!(
impl GenericDef { impl GenericDef {
pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> { pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
let generics = db.generic_params(self.into()); 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 } }; let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } };
match toc.split(db) { match toc.split(db) {
Either::Left(x) => GenericParam::ConstParam(x), Either::Left(x) => GenericParam::ConstParam(x),
@ -2067,7 +2075,7 @@ impl GenericDef {
pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> { pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
let generics = db.generic_params(self.into()); let generics = db.generic_params(self.into());
generics generics
.tocs .type_or_consts
.iter() .iter()
.map(|(local_id, _)| TypeOrConstParam { .map(|(local_id, _)| TypeOrConstParam {
id: TypeOrConstParamId { parent: self.into(), local_id }, id: TypeOrConstParamId { parent: self.into(), local_id },
@ -2351,9 +2359,14 @@ impl TypeParam {
let resolver = self.id.parent().resolver(db.upcast()); let resolver = self.id.parent().resolver(db.upcast());
let krate = self.id.parent().module(db.upcast()).krate(); let krate = self.id.parent().module(db.upcast()).krate();
let ty = params.get(local_idx)?.clone(); 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)); 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 { pub fn name(self, db: &dyn HirDatabase) -> Name {
let params = db.generic_params(self.id.parent()); 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(), Some(x) => x.clone(),
None => { None => {
never!(); never!();
@ -2421,7 +2434,7 @@ pub struct TypeOrConstParam {
impl TypeOrConstParam { impl TypeOrConstParam {
pub fn name(self, db: &dyn HirDatabase) -> Name { pub fn name(self, db: &dyn HirDatabase) -> Name {
let params = db.generic_params(self.id.parent); 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(), Some(n) => n.clone(),
_ => Name::missing(), _ => Name::missing(),
} }
@ -2437,12 +2450,12 @@ impl TypeOrConstParam {
pub fn split(self, db: &dyn HirDatabase) -> Either<ConstParam, TypeParam> { pub fn split(self, db: &dyn HirDatabase) -> Either<ConstParam, TypeParam> {
let params = db.generic_params(self.id.parent); let params = db.generic_params(self.id.parent);
match &params.tocs[self.id.local_id] { match &params.type_or_consts[self.id.local_id] {
hir_def::generics::TypeOrConstParamData::TypeParamData(_) => { 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(_) => { 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 { 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) let trait_ref = TyBuilder::trait_ref(db, trait_.id)
.push(self.ty.clone()) .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(); .build();
let goal = Canonical { let goal = Canonical {
@ -2707,9 +2730,18 @@ impl Type {
args: &[Type], args: &[Type],
alias: TypeAlias, alias: TypeAlias,
) -> Option<Type> { ) -> Option<Type> {
let mut args = args.iter();
let projection = TyBuilder::assoc_type_projection(db, alias.id) let projection = TyBuilder::assoc_type_projection(db, alias.id)
.push(self.ty.clone()) .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(); .build();
let goal = hir_ty::make_canonical( let goal = hir_ty::make_canonical(
InEnvironment::new( InEnvironment::new(

View File

@ -279,7 +279,7 @@ impl SourceToDefCtx<'_, '_> {
pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> { 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 container: ChildContainer = self.find_generic_param_container(src.syntax())?.into();
let dyn_map = self.cache_for(container, src.file_id); 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( pub(super) fn lifetime_param_to_def(
@ -297,7 +297,7 @@ impl SourceToDefCtx<'_, '_> {
) -> Option<ConstParamId> { ) -> Option<ConstParamId> {
let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into(); let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into();
let dyn_map = self.cache_for(container, src.file_id); 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( pub(super) fn generic_param_to_def(

View File

@ -24,8 +24,8 @@ use crate::{
keys, keys,
src::{HasChildSource, HasSource}, src::{HasChildSource, HasSource},
type_ref::{LifetimeRef, TypeBound, TypeRef}, type_ref::{LifetimeRef, TypeBound, TypeRef},
AdtId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId, LocalTypeOrConstParamId, AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId,
Lookup, TypeOrConstParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
}; };
/// Data about a generic type parameter (to a function, struct, impl, ...). /// 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. /// Data about the generic parameters of a function, struct, impl, etc.
#[derive(Clone, PartialEq, Eq, Debug, Default, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Default, Hash)]
pub struct GenericParams { pub struct GenericParams {
pub tocs: Arena<TypeOrConstParamData>, pub type_or_consts: Arena<TypeOrConstParamData>,
pub lifetimes: Arena<LifetimeParamData>, pub lifetimes: Arena<LifetimeParamData>,
pub where_predicates: Vec<WherePredicate>, pub where_predicates: Vec<WherePredicate>,
} }
@ -138,13 +138,14 @@ impl GenericParams {
pub fn type_iter<'a>( pub fn type_iter<'a>(
&'a self, &'a self,
) -> impl Iterator<Item = (Idx<TypeOrConstParamData>, &TypeParamData)> { ) -> 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, &'a self,
) -> impl Iterator<Item = (Idx<TypeOrConstParamData>, &TypeOrConstParamData)> { ) -> impl DoubleEndedIterator<Item = (Idx<TypeOrConstParamData>, &TypeOrConstParamData)> {
self.tocs.iter() self.type_or_consts.iter()
} }
pub(crate) fn generic_params_query( pub(crate) fn generic_params_query(
@ -251,7 +252,7 @@ impl GenericParams {
default, default,
provenance: TypeParamProvenance::TypeParamList, provenance: TypeParamProvenance::TypeParamList,
}; };
self.tocs.alloc(param.into()); self.type_or_consts.alloc(param.into());
let type_ref = TypeRef::Path(name.into()); let type_ref = TypeRef::Path(name.into());
self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref)); self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref));
} }
@ -261,7 +262,7 @@ impl GenericParams {
.ty() .ty()
.map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it)); .map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
let param = ConstParamData { name, ty: Interned::new(ty) }; 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, default: None,
provenance: TypeParamProvenance::ArgumentImplTrait, 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 { for bound in bounds {
self.where_predicates.push(WherePredicate::TypeBound { self.where_predicates.push(WherePredicate::TypeBound {
target: WherePredicateTypeTarget::TypeOrConstParam(param_id), target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
@ -372,27 +373,34 @@ impl GenericParams {
} }
pub(crate) fn shrink_to_fit(&mut self) { 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(); lifetimes.shrink_to_fit();
types.shrink_to_fit(); types.shrink_to_fit();
where_predicates.shrink_to_fit(); where_predicates.shrink_to_fit();
} }
pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeOrConstParamId> { pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> {
self.tocs self.type_or_consts.iter().find_map(|(id, p)| {
.iter() if p.name().as_ref() == Some(&name) && p.type_param().is_some() {
.filter(|x| matches!(x.1, TypeOrConstParamData::TypeParamData(_))) Some(TypeParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
.find_map(|(id, p)| if p.name().as_ref() == Some(&name) { Some(id) } else { None }) } else {
None
}
})
} }
pub fn find_type_or_const_by_name(&self, name: &Name) -> Option<LocalTypeOrConstParamId> { pub fn find_const_by_name(&self, name: &Name, parent: GenericDefId) -> Option<ConstParamId> {
self.tocs self.type_or_consts.iter().find_map(|(id, p)| {
.iter() if p.name().as_ref() == Some(&name) && p.const_param().is_some() {
.find_map(|(id, p)| if p.name().as_ref() == Some(&name) { Some(id) } else { None }) Some(ConstParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
} else {
None
}
})
} }
pub fn find_trait_self_param(&self) -> Option<LocalTypeOrConstParamId> { 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 let TypeOrConstParamData::TypeParamData(p) = p {
if p.provenance == TypeParamProvenance::TraitSelf { if p.provenance == TypeParamProvenance::TraitSelf {
Some(id) Some(id)
@ -451,7 +459,7 @@ impl HasChildSource<LocalTypeOrConstParamId> for GenericDefId {
db: &dyn DefDatabase, db: &dyn DefDatabase,
) -> InFile<ArenaMap<LocalTypeOrConstParamId, Self::Value>> { ) -> InFile<ArenaMap<LocalTypeOrConstParamId, Self::Value>> {
let generic_params = db.generic_params(*self); 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); 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 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); let lts_idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx);
// For traits the first type index is `Self`, skip it. // For traits the first type index is `Self`, skip it.

View File

@ -582,7 +582,7 @@ impl<'a> Ctx<'a> {
} }
GenericsOwner::Trait(trait_def) => { GenericsOwner::Trait(trait_def) => {
// traits get the Self type as an implicit first type parameter // traits get the Self type as an implicit first type parameter
generics.tocs.alloc( generics.type_or_consts.alloc(
TypeParamData { TypeParamData {
name: Some(name![Self]), name: Some(name![Self]),
default: None, default: None,

View File

@ -621,12 +621,13 @@ impl<'a> Printer<'a> {
fn print_generic_arg(&mut self, arg: &GenericArg) { fn print_generic_arg(&mut self, arg: &GenericArg) {
match arg { match arg {
GenericArg::Type(ty) => self.print_type_ref(ty), GenericArg::Type(ty) => self.print_type_ref(ty),
GenericArg::Const(c) => w!(self, "{}", c),
GenericArg::Lifetime(lt) => w!(self, "{}", lt.name), GenericArg::Lifetime(lt) => w!(self, "{}", lt.name),
} }
} }
fn print_generic_params(&mut self, params: &GenericParams) { 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; return;
} }
@ -639,7 +640,7 @@ impl<'a> Printer<'a> {
first = false; first = false;
w!(self, "{}", lt.name); w!(self, "{}", lt.name);
} }
for (idx, x) in params.tocs.iter() { for (idx, x) in params.type_or_consts.iter() {
if !first { if !first {
w!(self, ", "); w!(self, ", ");
} }
@ -701,7 +702,7 @@ impl<'a> Printer<'a> {
match target { match target {
WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty), WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
WherePredicateTypeTarget::TypeOrConstParam(id) => { WherePredicateTypeTarget::TypeOrConstParam(id) => {
match &params.tocs[*id].name() { match &params.type_or_consts[*id].name() {
Some(name) => w!(this, "{}", name), Some(name) => w!(this, "{}", name),
None => w!(this, "_anon_{}", id.into_raw()), None => w!(this, "_anon_{}", id.into_raw()),
} }

View File

@ -343,11 +343,13 @@ impl TypeParamId {
} }
} }
impl From<TypeOrConstParamId> for TypeParamId { impl TypeParamId {
fn from(x: TypeOrConstParamId) -> Self { /// Caller should check if this toc id really belongs to a type
pub fn from_unchecked(x: TypeOrConstParamId) -> Self {
Self(x) Self(x)
} }
} }
impl From<TypeParamId> for TypeOrConstParamId { impl From<TypeParamId> for TypeOrConstParamId {
fn from(x: TypeParamId) -> Self { fn from(x: TypeParamId) -> Self {
x.0 x.0
@ -367,11 +369,13 @@ impl ConstParamId {
} }
} }
impl From<TypeOrConstParamId> for ConstParamId { impl ConstParamId {
fn from(x: TypeOrConstParamId) -> Self { /// Caller should check if this toc id really belongs to a const
pub fn from_unchecked(x: TypeOrConstParamId) -> Self {
Self(x) Self(x)
} }
} }
impl From<ConstParamId> for TypeOrConstParamId { impl From<ConstParamId> for TypeOrConstParamId {
fn from(x: ConstParamId) -> Self { fn from(x: ConstParamId) -> Self {
x.0 x.0

View File

@ -6,7 +6,11 @@ use std::{
iter, 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 hir_expand::name::{name, Name};
use syntax::ast; use syntax::ast;
@ -78,6 +82,7 @@ pub struct AssociatedTypeBinding {
pub enum GenericArg { pub enum GenericArg {
Type(TypeRef), Type(TypeRef),
Lifetime(LifetimeRef), Lifetime(LifetimeRef),
Const(ConstScalarOrPath),
} }
impl Path { impl Path {

View File

@ -1,6 +1,6 @@
//! Transforms syntax into `Path` objects, ideally with accounting for hygiene //! 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 either::Either;
use hir_expand::name::{name, AsName}; use hir_expand::name::{name, AsName};
@ -180,8 +180,10 @@ pub(super) fn lower_generic_args(
args.push(GenericArg::Lifetime(lifetime_ref)) args.push(GenericArg::Lifetime(lifetime_ref))
} }
} }
// constants are ignored for now. ast::GenericArg::ConstArg(arg) => {
ast::GenericArg::ConstArg(_) => (), let arg = ConstScalarOrPath::from_expr_opt(arg.expr());
args.push(GenericArg::Const(arg))
}
} }
} }

View File

@ -189,14 +189,9 @@ impl Resolver {
Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue, Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue,
Scope::GenericParams { params, def } => { 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) }; let idx = if path.segments().len() == 1 { None } else { Some(1) };
return Some(( return Some((TypeNs::GenericParam(id), idx));
TypeNs::GenericParam(
TypeOrConstParamId { local_id, parent: *def }.into(),
),
idx,
));
} }
} }
Scope::ImplDefScope(impl_) => { Scope::ImplDefScope(impl_) => {
@ -284,18 +279,14 @@ impl Resolver {
Scope::ExprScope(_) => continue, Scope::ExprScope(_) => continue,
Scope::GenericParams { params, def } if n_segments > 1 => { Scope::GenericParams { params, def } if n_segments > 1 => {
if let Some(local_id) = params.find_type_or_const_by_name(first_name) { if let Some(id) = params.find_type_by_name(first_name, *def) {
let ty = TypeNs::GenericParam( let ty = TypeNs::GenericParam(id);
TypeOrConstParamId { local_id, parent: *def }.into(),
);
return Some(ResolveValueResult::Partial(ty, 1)); return Some(ResolveValueResult::Partial(ty, 1));
} }
} }
Scope::GenericParams { params, def } if n_segments == 1 => { Scope::GenericParams { params, def } if n_segments == 1 => {
if let Some(local_id) = params.find_type_or_const_by_name(first_name) { if let Some(id) = params.find_const_by_name(first_name, *def) {
let val = ValueNs::GenericParam( let val = ValueNs::GenericParam(id);
TypeOrConstParamId { local_id, parent: *def }.into(),
);
return Some(ResolveValueResult::ValueNs(val)); return Some(ResolveValueResult::ValueNs(val));
} }
} }
@ -518,18 +509,18 @@ impl Scope {
} }
Scope::GenericParams { params, def: parent } => { Scope::GenericParams { params, def: parent } => {
let parent = *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) = &param.name() { if let Some(name) = &param.name() {
let id = TypeOrConstParamId { parent, local_id }; 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( acc.add(
name, name,
ScopeDef::GenericParam(match data { ScopeDef::GenericParam(match data {
TypeOrConstParamData::TypeParamData(_) => { TypeOrConstParamData::TypeParamData(_) => {
GenericParamId::TypeParamId(id.into()) GenericParamId::TypeParamId(TypeParamId::from_unchecked(id))
} }
TypeOrConstParamData::ConstParamData(_) => { TypeOrConstParamData::ConstParamData(_) => {
GenericParamId::ConstParamId(id.into()) GenericParamId::ConstParamId(ConstParamId::from_unchecked(id))
} }
}), }),
); );

View File

@ -89,7 +89,7 @@ pub enum TypeRef {
Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability), Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
// FIXME: for full const generics, the latter element (length) here is going to have to be an // 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. // expression that is further lowered later in hir_ty.
Array(Box<TypeRef>, ConstScalar), Array(Box<TypeRef>, ConstScalarOrPath),
Slice(Box<TypeRef>), Slice(Box<TypeRef>),
/// A fn pointer. Last element of the vector is the return type. /// A fn pointer. Last element of the vector is the return type.
Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/), 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_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: // `hir_ty` level, which would allow knowing the type of:
// let v: [u8; 2 + 2] = [0u8; 4]; // let v: [u8; 2 + 2] = [0u8; 4];
let len = inner let len = ConstScalarOrPath::from_expr_opt(inner.expr());
.expr()
.map(ConstScalar::usize_from_literal_expr)
.unwrap_or(ConstScalar::Unknown);
TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len) TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len)
} }
@ -278,7 +275,8 @@ impl TypeRef {
crate::path::GenericArg::Type(type_ref) => { crate::path::GenericArg::Type(type_ref) => {
go(type_ref, f); go(type_ref, f);
} }
crate::path::GenericArg::Lifetime(_) => {} crate::path::GenericArg::Const(_)
| crate::path::GenericArg::Lifetime(_) => {}
} }
} }
for binding in &args_and_bindings.bindings { 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 /// A concrete constant value
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ConstScalar { pub enum ConstScalar {
@ -389,25 +441,4 @@ impl ConstScalar {
_ => None, _ => 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)
}
} }

View File

@ -18,9 +18,9 @@ ena = "0.14.0"
tracing = "0.1" tracing = "0.1"
rustc-hash = "1.1.0" rustc-hash = "1.1.0"
scoped-tls = "1" scoped-tls = "1"
chalk-solve = { version = "0.76", default-features = false } chalk-solve = { version = "0.79", default-features = false }
chalk-ir = "0.76" chalk-ir = "0.79"
chalk-recursive = { version = "0.76", default-features = false } chalk-recursive = { version = "0.79", default-features = false }
la-arena = { version = "0.3.0", path = "../../lib/arena" } la-arena = { version = "0.3.0", path = "../../lib/arena" }
once_cell = { version = "1.5.0" } once_cell = { version = "1.5.0" }
typed-arena = "2.0.1" typed-arena = "2.0.1"

View File

@ -8,67 +8,136 @@ use chalk_ir::{
interner::HasInterner, interner::HasInterner,
AdtId, BoundVar, DebruijnIndex, Scalar, 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 smallvec::SmallVec;
use crate::{ use crate::{
db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, consteval::unknown_const_as_generic, db::HirDatabase, primitive, to_assoc_type_id,
CallableSig, GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData, ConstValue, GenericArg,
TyKind, ValueTyDefId, 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`. /// This is a builder for `Ty` or anything that needs a `Substitution`.
pub struct TyBuilder<D> { pub struct TyBuilder<D> {
/// The `data` field is used to keep track of what we're building (e.g. an /// The `data` field is used to keep track of what we're building (e.g. an
/// ADT, a `TraitRef`, ...). /// ADT, a `TraitRef`, ...).
data: D, data: D,
vec: SmallVec<[GenericArg; 2]>, 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> { impl<D> TyBuilder<D> {
fn new(data: D, param_count: usize) -> TyBuilder<D> { fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder<D> {
TyBuilder { data, param_count, vec: SmallVec::with_capacity(param_count) } TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds }
} }
fn build_internal(self) -> (D, Substitution) { 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); let subst = Substitution::from_iter(Interner, self.vec);
(self.data, subst) (self.data, subst)
} }
pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self { 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 self
} }
pub fn remaining(&self) -> usize { 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 { pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
self.fill( // self.fill is inlined to make borrow checker happy
(starting_from..) let mut this = self;
.map(|idx| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner)), 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 { 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 { pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
self.vec.extend(filler.take(self.remaining()).casted(Interner)); self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler));
assert_eq!(self.remaining(), 0); assert_eq!(self.remaining(), 0);
self self
} }
pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self { pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
assert!(self.vec.is_empty()); assert!(self.vec.is_empty());
assert!(parent_substs.len(Interner) <= self.param_count); assert!(parent_substs.len(Interner) <= self.param_kinds.len());
self.vec.extend(parent_substs.iter(Interner).cloned()); self.extend(parent_substs.iter(Interner).cloned());
self 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<()> { impl TyBuilder<()> {
@ -101,16 +170,26 @@ impl TyBuilder<()> {
TyKind::Slice(argument).intern(Interner) 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()); 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<()> { pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> {
let def = def.into(); let def = def.into();
let params = generics(db.upcast(), def); let params = generics(db.upcast(), def);
let param_count = params.len(); TyBuilder::new(
TyBuilder::new((), param_count) (),
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 { pub fn build(self) -> Substitution {
@ -120,10 +199,8 @@ impl TyBuilder<()> {
} }
impl TyBuilder<hir_def::AdtId> { impl TyBuilder<hir_def::AdtId> {
pub fn adt(db: &dyn HirDatabase, adt: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> { pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
let generics = generics(db.upcast(), adt.into()); TyBuilder::subst_for_def(db, def).with_data(def)
let param_count = generics.len();
TyBuilder::new(adt, param_count)
} }
pub fn fill_with_defaults( pub fn fill_with_defaults(
@ -133,14 +210,15 @@ impl TyBuilder<hir_def::AdtId> {
) -> Self { ) -> Self {
let defaults = db.generic_defaults(self.data.into()); let defaults = db.generic_defaults(self.data.into());
for default_ty in defaults.iter().skip(self.vec.len()) { 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) {
self.vec.push(fallback().cast(Interner)); if x.is_unknown() {
} else { self.vec.push(fallback().cast(Interner));
// each default can depend on the previous parameters continue;
let subst_so_far = Substitution::from_iter(Interner, self.vec.clone()); }
self.vec };
.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner)); // 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 self
} }
@ -154,7 +232,7 @@ impl TyBuilder<hir_def::AdtId> {
pub struct Tuple(usize); pub struct Tuple(usize);
impl TyBuilder<Tuple> { impl TyBuilder<Tuple> {
pub fn tuple(size: usize) -> 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 { pub fn build(self) -> Ty {
@ -164,10 +242,8 @@ impl TyBuilder<Tuple> {
} }
impl TyBuilder<TraitId> { impl TyBuilder<TraitId> {
pub fn trait_ref(db: &dyn HirDatabase, trait_id: TraitId) -> TyBuilder<TraitId> { pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
let generics = generics(db.upcast(), trait_id.into()); TyBuilder::subst_for_def(db, def).with_data(def)
let param_count = generics.len();
TyBuilder::new(trait_id, param_count)
} }
pub fn build(self) -> TraitRef { pub fn build(self) -> TraitRef {
@ -177,13 +253,8 @@ impl TyBuilder<TraitId> {
} }
impl TyBuilder<TypeAliasId> { impl TyBuilder<TypeAliasId> {
pub fn assoc_type_projection( pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder<TypeAliasId> {
db: &dyn HirDatabase, TyBuilder::subst_for_def(db, def).with_data(def)
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 build(self) -> ProjectionTy { pub fn build(self) -> ProjectionTy {
@ -194,8 +265,16 @@ impl TyBuilder<TypeAliasId> {
impl<T: HasInterner<Interner = Interner> + Fold<Interner>> TyBuilder<Binders<T>> { impl<T: HasInterner<Interner = Interner> + Fold<Interner>> TyBuilder<Binders<T>> {
fn subst_binders(b: Binders<T>) -> Self { fn subst_binders(b: Binders<T>) -> Self {
let param_count = b.binders.len(Interner); let param_kinds = b
TyBuilder::new(b, param_count) .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 { pub fn build(self) -> <T as Fold<Interner>>::Result {

View File

@ -19,7 +19,8 @@ use hir_expand::name::name;
use crate::{ use crate::{
db::HirDatabase, db::HirDatabase,
display::HirDisplay, 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}, mapping::{from_chalk, ToChalk, TypeAliasAsValue},
method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
to_assoc_type_id, to_chalk_trait_id, 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 (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders();
let data = &datas.impl_traits[idx as usize]; let data = &datas.impl_traits[idx as usize];
let bound = OpaqueTyDatumBound { let bound = OpaqueTyDatumBound {
bounds: make_only_type_binders(1, data.bounds.skip_binders().to_vec()), bounds: make_single_type_binders(data.bounds.skip_binders().to_vec()),
where_clauses: make_only_type_binders(0, vec![]), where_clauses: chalk_ir::Binders::empty(Interner, vec![]),
}; };
chalk_ir::Binders::new(binders, bound) chalk_ir::Binders::new(binders, bound)
} }
@ -255,25 +256,22 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
.intern(Interner), .intern(Interner),
}); });
let bound = OpaqueTyDatumBound { let bound = OpaqueTyDatumBound {
bounds: make_only_type_binders( bounds: make_single_type_binders(vec![
1, crate::wrap_empty_binders(impl_bound),
vec![ crate::wrap_empty_binders(proj_bound),
crate::wrap_empty_binders(impl_bound), ]),
crate::wrap_empty_binders(proj_bound), where_clauses: chalk_ir::Binders::empty(Interner, vec![]),
],
),
where_clauses: make_only_type_binders(0, vec![]),
}; };
// The opaque type has 1 parameter. // The opaque type has 1 parameter.
make_only_type_binders(1, bound) make_single_type_binders(bound)
} else { } else {
// If failed to find Symbols value as variable is void: Future::Output, return empty bounds as fallback. // If failed to find Symbols value as variable is void: Future::Output, return empty bounds as fallback.
let bound = OpaqueTyDatumBound { let bound = OpaqueTyDatumBound {
bounds: make_only_type_binders(0, vec![]), bounds: chalk_ir::Binders::empty(Interner, vec![]),
where_clauses: make_only_type_binders(0, vec![]), where_clauses: chalk_ir::Binders::empty(Interner, vec![]),
}; };
// The opaque type has 1 parameter. // 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(), argument_types: sig.params().to_vec(),
return_type: sig.ret().clone(), 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( fn closure_upvars(
&self, &self,
@ -318,7 +316,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
_substs: &chalk_ir::Substitution<Interner>, _substs: &chalk_ir::Substitution<Interner>,
) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> { ) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> {
let ty = TyBuilder::unit(); let ty = TyBuilder::unit();
make_only_type_binders(0, ty) chalk_ir::Binders::empty(Interner, ty)
} }
fn closure_fn_substitution( fn closure_fn_substitution(
&self, &self,
@ -407,7 +405,7 @@ pub(crate) fn associated_ty_data_query(
// let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST); // let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
let ctx = crate::TyLoweringContext::new(db, &resolver) 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 = let self_ty =
TyKind::BoundVar(BoundVar::new(crate::DebruijnIndex::INNERMOST, 0)).intern(Interner); TyKind::BoundVar(BoundVar::new(crate::DebruijnIndex::INNERMOST, 0)).intern(Interner);
let mut bounds: Vec<_> = type_alias_data 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_), trait_id: to_chalk_trait_id(trait_),
id, id,
name: type_alias, name: type_alias,
binders: make_only_type_binders(generic_params.len(), bound_data), binders: make_binders(db, &generic_params, bound_data),
}; };
Arc::new(datum) Arc::new(datum)
} }
@ -455,7 +453,7 @@ pub(crate) fn trait_datum_query(
let trait_data = db.trait_data(trait_); let trait_data = db.trait_data(trait_);
debug!("trait {:?} = {:?}", trait_id, trait_data.name); debug!("trait {:?} = {:?}", trait_id, trait_data.name);
let generic_params = generics(db.upcast(), trait_.into()); 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 { let flags = rust_ir::TraitFlags {
auto: trait_data.is_auto, auto: trait_data.is_auto,
upstream: trait_.lookup(db.upcast()).container.krate() != krate, 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)); lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name));
let trait_datum = TraitDatum { let trait_datum = TraitDatum {
id: trait_id, 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, flags,
associated_ty_ids, associated_ty_ids,
well_known, well_known,
@ -520,11 +518,11 @@ pub(crate) fn struct_datum_query(
) -> Arc<StructDatum> { ) -> Arc<StructDatum> {
debug!("struct_datum {:?}", struct_id); debug!("struct_datum {:?}", struct_id);
let chalk_ir::AdtId(adt_id) = 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 upstream = adt_id.module(db.upcast()).krate() != krate;
let where_clauses = { let where_clauses = {
let generic_params = generics(db.upcast(), adt_id.into()); 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) convert_where_clauses(db, adt_id.into(), &bound_vars)
}; };
let flags = rust_ir::AdtFlags { let flags = rust_ir::AdtFlags {
@ -542,7 +540,7 @@ pub(crate) fn struct_datum_query(
// FIXME set ADT kind // FIXME set ADT kind
kind: rust_ir::AdtKind::Struct, kind: rust_ir::AdtKind::Struct,
id: struct_id, id: struct_id,
binders: make_only_type_binders(num_params, struct_datum_bound), binders: make_binders(db, &generic_params, struct_datum_bound),
flags, flags,
}; };
Arc::new(struct_datum) Arc::new(struct_datum)
@ -574,7 +572,7 @@ fn impl_def_datum(
let impl_data = db.impl_data(impl_id); let impl_data = db.impl_data(impl_id);
let generic_params = generics(db.upcast(), impl_id.into()); 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 trait_ = trait_ref.hir_trait_id();
let impl_type = if impl_id.lookup(db.upcast()).container.krate() == krate { let impl_type = if impl_id.lookup(db.upcast()).container.krate() == krate {
rust_ir::ImplType::Local rust_ir::ImplType::Local
@ -611,7 +609,7 @@ fn impl_def_datum(
.collect(); .collect();
debug!("impl_datum: {:?}", impl_datum_bound); debug!("impl_datum: {:?}", impl_datum_bound);
let impl_datum = ImplDatum { 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, impl_type,
polarity, polarity,
associated_ty_value_ids, 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 callable_def: CallableDefId = from_chalk(db, fn_def_id);
let generic_params = generics(db.upcast(), callable_def.into()); let generic_params = generics(db.upcast(), callable_def.into());
let (sig, binders) = db.callable_item_signature(callable_def).into_value_and_skipped_binders(); 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 where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars);
let bound = rust_ir::FnDefDatumBound { 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 // 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( inputs_and_output: chalk_ir::Binders::empty(
0, Interner,
rust_ir::FnDefInputsAndOutputDatum { rust_ir::FnDefInputsAndOutputDatum {
argument_types: sig.params().to_vec(), argument_types: sig.params().to_vec(),
return_type: sig.ret().clone(), return_type: sig.ret().clone(),

View File

@ -237,11 +237,11 @@ impl TyExt for Ty {
TyKind::Placeholder(idx) => { TyKind::Placeholder(idx) => {
let id = from_placeholder_idx(db, *idx); let id = from_placeholder_idx(db, *idx);
let generic_params = db.generic_params(id.parent); 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 { match param_data {
TypeOrConstParamData::TypeParamData(p) => match p.provenance { TypeOrConstParamData::TypeParamData(p) => match p.provenance {
hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { 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 let predicates = db
.generic_predicates(id.parent) .generic_predicates(id.parent)
.iter() .iter()

View File

@ -2,15 +2,25 @@
use std::{collections::HashMap, convert::TryInto, fmt::Display}; use std::{collections::HashMap, convert::TryInto, fmt::Display};
use chalk_ir::{IntTy, Scalar}; use chalk_ir::{BoundVar, DebruijnIndex, GenericArgData, IntTy, Scalar};
use hir_def::{ use hir_def::{
expr::{ArithOp, BinaryOp, Expr, Literal, Pat}, expr::{ArithOp, BinaryOp, Expr, Literal, Pat},
path::ModPath,
resolver::{Resolver, ValueNs},
type_ref::ConstScalar, type_ref::ConstScalar,
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
use la_arena::{Arena, Idx}; 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`] /// Extension trait for [`Const`]
pub trait ConstExt { pub trait ConstExt {
@ -303,6 +313,57 @@ pub fn eval_usize(expr: Idx<Expr>, mut ctx: ConstEvalCtx<'_>) -> Option<u64> {
None 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 /// Interns a possibly-unknown target usize
pub fn usize_const(value: Option<u64>) -> Const { pub fn usize_const(value: Option<u64>) -> Const {
ConstData { ConstData {
@ -313,3 +374,27 @@ pub fn usize_const(value: Option<u64>) -> Const {
} }
.intern(Interner) .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))
}

View File

@ -13,7 +13,7 @@ use la_arena::ArenaMap;
use crate::{ use crate::{
chalk_db, chalk_db,
method_resolution::{InherentImpls, TraitImpls}, 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, QuantifiedWhereClause, ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId,
}; };
use hir_expand::name::Name; use hir_expand::name::Name;
@ -73,7 +73,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::lower::generic_defaults_query)] #[salsa::invoke(crate::lower::generic_defaults_query)]
#[salsa::cycle(crate::lower::generic_defaults_recover)] #[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)] #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>; fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;

View File

@ -14,7 +14,7 @@ use hir_def::{
intern::{Internable, Interned}, intern::{Internable, Interned},
item_scope::ItemInNs, item_scope::ItemInNs,
path::{Path, PathKind}, path::{Path, PathKind},
type_ref::{TraitBoundModifier, TypeBound, TypeRef}, type_ref::{ConstScalar, TraitBoundModifier, TypeBound, TypeRef},
visibility::Visibility, visibility::Visibility,
HasModule, ItemContainerId, Lookup, ModuleId, TraitId, HasModule, ItemContainerId, Lookup, ModuleId, TraitId,
}; };
@ -28,10 +28,10 @@ use crate::{
mapping::from_chalk, mapping::from_chalk,
primitive, subst_prefix, to_assoc_type_id, primitive, subst_prefix, to_assoc_type_id,
utils::{self, generics}, utils::{self, generics},
AdtId, AliasEq, AliasTy, CallableDefId, CallableSig, Const, ConstValue, DomainGoal, GenericArg, AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstValue, DomainGoal,
ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability, OpaqueTy, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability,
ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar, TraitRef, TraitRefExt, Ty, TyExt, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar, Substitution, TraitRef,
TyKind, WhereClause, TraitRefExt, Ty, TyExt, TyKind, WhereClause,
}; };
pub struct HirFormatter<'a> { pub struct HirFormatter<'a> {
@ -316,11 +316,11 @@ impl HirDisplay for Const {
let data = self.interned(); let data = self.interned();
match data.value { match data.value {
ConstValue::BoundVar(idx) => idx.hir_fmt(f), ConstValue::BoundVar(idx) => idx.hir_fmt(f),
ConstValue::InferenceVar(..) => write!(f, "_"), ConstValue::InferenceVar(..) => write!(f, "#c#"),
ConstValue::Placeholder(idx) => { ConstValue::Placeholder(idx) => {
let id = from_placeholder_idx(f.db, idx); let id = from_placeholder_idx(f.db, idx);
let generics = generics(f.db.upcast(), id.parent); 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()) write!(f, "{}", param_data.name().unwrap())
} }
ConstValue::Concrete(c) => write!(f, "{}", c.interned), ConstValue::Concrete(c) => write!(f, "{}", c.interned),
@ -544,24 +544,37 @@ impl HirDisplay for Ty {
{ {
None => parameters.as_slice(Interner), None => parameters.as_slice(Interner),
Some(default_parameters) => { Some(default_parameters) => {
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;
}
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));
parameter != &actual_default
}
let mut default_from = 0; let mut default_from = 0;
for (i, parameter) in parameters.iter(Interner).enumerate() { for (i, parameter) in parameters.iter(Interner).enumerate() {
match ( if should_show(parameter, &default_parameters, i, parameters) {
parameter.assert_ty_ref(Interner).kind(Interner), default_from = i + 1;
default_parameters.get(i),
) {
(&TyKind::Error, _) | (_, None) => {
default_from = i + 1;
}
(_, Some(default_parameter)) => {
let actual_default = default_parameter
.clone()
.substitute(Interner, &subst_prefix(parameters, i));
if parameter.assert_ty_ref(Interner) != &actual_default
{
default_from = i + 1;
}
}
} }
} }
&parameters.as_slice(Interner)[0..default_from] &parameters.as_slice(Interner)[0..default_from]
@ -680,14 +693,14 @@ impl HirDisplay for Ty {
TyKind::Placeholder(idx) => { TyKind::Placeholder(idx) => {
let id = from_placeholder_idx(f.db, *idx); let id = from_placeholder_idx(f.db, *idx);
let generics = generics(f.db.upcast(), id.parent); 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 { match param_data {
TypeOrConstParamData::TypeParamData(p) => match p.provenance { TypeOrConstParamData::TypeParamData(p) => match p.provenance {
TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
write!(f, "{}", p.name.clone().unwrap_or_else(Name::missing))? write!(f, "{}", p.name.clone().unwrap_or_else(Name::missing))?
} }
TypeParamProvenance::ArgumentImplTrait => { TypeParamProvenance::ArgumentImplTrait => {
let substs = generics.type_params_subst(f.db); let substs = generics.placeholder_subst(f.db);
let bounds = let bounds =
f.db.generic_predicates(id.parent) f.db.generic_predicates(id.parent)
.iter() .iter()
@ -1281,6 +1294,7 @@ impl HirDisplay for hir_def::path::GenericArg {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
match self { match self {
hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f), 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), hir_def::path::GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
} }
} }

View File

@ -16,7 +16,7 @@
use std::ops::Index; use std::ops::Index;
use std::sync::Arc; 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::{ use hir_def::{
body::Body, body::Body,
data::{ConstData, FunctionData, StaticData}, data::{ConstData, FunctionData, StaticData},
@ -29,14 +29,16 @@ use hir_def::{
TraitId, TypeAliasId, VariantId, TraitId, TypeAliasId, VariantId,
}; };
use hir_expand::name::{name, Name}; use hir_expand::name::{name, Name};
use itertools::Either;
use la_arena::ArenaMap; use la_arena::ArenaMap;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use stdx::impl_from; use stdx::impl_from;
use crate::{ use crate::{
db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode, builder::ParamKind, db::HirDatabase, fold_tys_and_consts, infer::coerce::CoerceMany,
to_assoc_type_id, AliasEq, AliasTy, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy, lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal,
Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, 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. // 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. /// The inference context contains all information needed during type inference.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct InferenceContext<'a> { pub(crate) struct InferenceContext<'a> {
db: &'a dyn HirDatabase, pub(crate) db: &'a dyn HirDatabase,
owner: DefWithBodyId, owner: DefWithBodyId,
body: Arc<Body>, pub(crate) body: Arc<Body>,
resolver: Resolver, pub(crate) resolver: Resolver,
table: unify::InferenceTable<'a>, table: unify::InferenceTable<'a>,
trait_env: Arc<TraitEnvironment>, trait_env: Arc<TraitEnvironment>,
result: InferenceResult, result: InferenceResult,
@ -488,6 +490,20 @@ impl<'a> InferenceContext<'a> {
self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed) 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. /// 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 { fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
match ty.kind(Interner) { match ty.kind(Interner) {
@ -505,7 +521,14 @@ impl<'a> InferenceContext<'a> {
} }
fn insert_type_vars(&mut self, ty: Ty) -> Ty { 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) { fn resolve_obligations_as_possible(&mut self) {
@ -533,7 +556,7 @@ impl<'a> InferenceContext<'a> {
&mut self, &mut self,
inner_ty: Ty, inner_ty: Ty,
assoc_ty: Option<TypeAliasId>, assoc_ty: Option<TypeAliasId>,
params: &[Ty], params: &[GenericArg],
) -> Ty { ) -> Ty {
match assoc_ty { match assoc_ty {
Some(res_assoc_ty) => { Some(res_assoc_ty) => {
@ -542,9 +565,10 @@ impl<'a> InferenceContext<'a> {
_ => panic!("resolve_associated_type called with non-associated type"), _ => panic!("resolve_associated_type called with non-associated type"),
}; };
let ty = self.table.new_type_var(); let ty = self.table.new_type_var();
let mut param_iter = params.iter().cloned();
let trait_ref = TyBuilder::trait_ref(self.db, trait_) let trait_ref = TyBuilder::trait_ref(self.db, trait_)
.push(inner_ty) .push(inner_ty)
.fill(params.iter().cloned()) .fill(|_| param_iter.next().unwrap())
.build(); .build();
let alias_eq = AliasEq { let alias_eq = AliasEq {
alias: AliasTy::Projection(ProjectionTy { alias: AliasTy::Projection(ProjectionTy {
@ -627,13 +651,21 @@ impl<'a> InferenceContext<'a> {
} }
TypeNs::SelfType(impl_id) => { TypeNs::SelfType(impl_id) => {
let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); 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); let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
self.resolve_variant_on_alias(ty, unresolved, path) self.resolve_variant_on_alias(ty, unresolved, path)
} }
TypeNs::TypeAliasId(it) => { TypeNs::TypeAliasId(it) => {
let ty = TyBuilder::def_ty(self.db, it.into()) 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(); .build();
self.resolve_variant_on_alias(ty, unresolved, path) 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 /// When inferring an expression, we propagate downward whatever type hint we
/// are able in the form of an `Expectation`. /// are able in the form of an `Expectation`.
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
enum Expectation { pub(crate) enum Expectation {
None, None,
HasType(Ty), HasType(Ty),
// Castable(Ty), // rustc has this, we currently just don't propagate an expectation for casts // Castable(Ty), // rustc has this, we currently just don't propagate an expectation for casts

View File

@ -7,13 +7,15 @@ use std::{
sync::Arc, 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::{ use hir_def::{
expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Ordering, Statement, UnaryOp}, expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Ordering, Statement, UnaryOp},
generics::TypeOrConstParamData, generics::TypeOrConstParamData,
path::{GenericArg, GenericArgs}, path::{GenericArg, GenericArgs},
resolver::resolver_for_expr, resolver::resolver_for_expr,
FieldId, FunctionId, ItemContainerId, Lookup, ConstParamId, FieldId, FunctionId, ItemContainerId, Lookup,
}; };
use hir_expand::name::{name, Name}; use hir_expand::name::{name, Name};
use stdx::always; use stdx::always;
@ -23,7 +25,9 @@ use crate::{
autoderef::{self, Autoderef}, autoderef::{self, Autoderef},
consteval, consteval,
infer::coerce::CoerceMany, 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, mapping::from_chalk,
method_resolution, method_resolution,
primitive::{self, UintTy}, primitive::{self, UintTy},
@ -39,7 +43,7 @@ use super::{
}; };
impl<'a> InferenceContext<'a> { 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); let ty = self.infer_expr_inner(tgt_expr, expected);
if self.resolve_ty_shallow(&ty).is_never() { if self.resolve_ty_shallow(&ty).is_never() {
// Any expression that produces a value of type `!` must have diverged // 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.resolve_associated_type_with_params(
self_ty, self_ty,
self.resolve_ops_index_output(), self.resolve_ops_index_output(),
&[index_ty], &[GenericArgData::Ty(index_ty).intern(Interner)],
) )
} else { } else {
self.err_ty() self.err_ty()
@ -704,7 +708,7 @@ impl<'a> InferenceContext<'a> {
let cur_elem_ty = self.infer_expr_inner(expr, &expected); let cur_elem_ty = self.infer_expr_inner(expr, &expected);
coerce.coerce(self, Some(expr), &cur_elem_ty); 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 } => { &Array::Repeat { initializer, repeat } => {
self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty)); 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() {
repeat, let generics = generics(self.db.upcast(), g_def);
consteval::ConstEvalCtx { consteval::eval_to_const(
exprs: &body.exprs, repeat,
pats: &body.pats, ParamLoweringMode::Placeholder,
local_data: Default::default(), self,
infer: &mut |x| self.infer_expr(x, &expected), || 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 { Expr::Literal(lit) => match lit {
Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(Interner), 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 total_len = parent_params + type_params + const_params + impl_trait_params;
let mut substs = Vec::with_capacity(total_len); let mut substs = Vec::with_capacity(total_len);
// Parent arguments are unknown // Parent arguments are unknown
for (_id, param) in def_generics.iter_parent() { for (id, param) in def_generics.iter_parent() {
match param { match param {
TypeOrConstParamData::TypeParamData(_) => { TypeOrConstParamData::TypeParamData(_) => {
substs.push(self.table.new_type_var()); substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner));
} }
TypeOrConstParamData::ConstParamData(_) => { TypeOrConstParamData::ConstParamData(_) => {
// FIXME: here we should do something else let ty = self.db.const_param_ty(ConstParamId::from_unchecked(id));
substs.push(self.table.new_type_var()); 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 let Some(generic_args) = generic_args {
// if args are provided, it should be all of them, but we can't rely on that // 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 .args
.iter() .iter()
.filter(|arg| matches!(arg, GenericArg::Type(_))) .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
.take(type_params) .take(type_params + const_params)
.zip(def_generics.iter_id().skip(parent_params))
{ {
match arg { if let Some(g) = generic_arg_to_chalk(
GenericArg::Type(type_ref) => { self.db,
let ty = self.make_ty(type_ref); kind_id,
substs.push(ty); arg,
} self,
GenericArg::Lifetime(_) => {} |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(); let supplied_params = substs.len();
for _ in supplied_params..total_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); assert_eq!(substs.len(), total_len);
Substitution::from_iter(Interner, substs) Substitution::from_iter(Interner, substs)

View File

@ -1,7 +1,5 @@
//! Path expression resolution. //! Path expression resolution.
use std::iter;
use chalk_ir::cast::Cast; use chalk_ir::cast::Cast;
use hir_def::{ use hir_def::{
path::{Path, PathSegment}, path::{Path, PathSegment},
@ -11,8 +9,8 @@ use hir_def::{
use hir_expand::name::Name; use hir_expand::name::Name;
use crate::{ use crate::{
method_resolution, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, builder::ParamKind, consteval, method_resolution, GenericArgData, Interner, Substitution,
ValueTyDefId, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
}; };
use super::{ExprOrPatId, InferenceContext, TraitRef}; use super::{ExprOrPatId, InferenceContext, TraitRef};
@ -82,7 +80,7 @@ impl<'a> InferenceContext<'a> {
} }
ValueNs::ImplSelf(impl_id) => { ValueNs::ImplSelf(impl_id) => {
let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); 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); let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() {
let ty = self.db.value_ty(struct_id.into()).substitute(Interner, &substs); 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 parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(Interner));
let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
let substs = ctx.substs_from_path(path, typable, true); 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) let ty = TyBuilder::value_ty(self.db, typable)
.use_parent_substs(&parent_substs) .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(); .build();
Some(ty) Some(ty)
} }
@ -241,7 +249,15 @@ impl<'a> InferenceContext<'a> {
let substs = match container { let substs = match container {
ItemContainerId::ImplId(impl_id) => { ItemContainerId::ImplId(impl_id) => {
let impl_substs = TyBuilder::subst_for_def(self.db, 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(); .build();
let impl_self_ty = let impl_self_ty =
self.db.impl_self_ty(impl_id).substitute(Interner, &impl_substs); self.db.impl_self_ty(impl_id).substitute(Interner, &impl_substs);
@ -252,7 +268,15 @@ impl<'a> InferenceContext<'a> {
// we're picking this method // we're picking this method
let trait_ref = TyBuilder::trait_ref(self.db, trait_) let trait_ref = TyBuilder::trait_ref(self.db, trait_)
.push(ty.clone()) .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(); .build();
self.push_obligation(trait_ref.clone().cast(Interner)); self.push_obligation(trait_ref.clone().cast(Interner));
Some(trait_ref.substitution) Some(trait_ref.substitution)

View File

@ -1,6 +1,6 @@
//! Unification and canonicalization logic. //! Unification and canonicalization logic.
use std::{fmt, iter, mem, sync::Arc}; use std::{fmt, mem, sync::Arc};
use chalk_ir::{ use chalk_ir::{
cast::Cast, fold::Fold, interner::HasInterner, zip::Zip, FloatTy, IntTy, NoSolution, cast::Cast, fold::Fold, interner::HasInterner, zip::Zip, FloatTy, IntTy, NoSolution,
@ -9,13 +9,14 @@ use chalk_ir::{
use chalk_solve::infer::ParameterEnaVariableExt; use chalk_solve::infer::ParameterEnaVariableExt;
use ena::unify::UnifyKey; use ena::unify::UnifyKey;
use hir_expand::name; use hir_expand::name;
use stdx::never;
use super::{InferOk, InferResult, InferenceContext, TypeError}; use super::{InferOk, InferResult, InferenceContext, TypeError};
use crate::{ use crate::{
db::HirDatabase, fold_tys, static_lifetime, traits::FnTrait, AliasEq, AliasTy, BoundVar, db::HirDatabase, fold_tys, static_lifetime, traits::FnTrait, AliasEq, AliasTy, BoundVar,
Canonical, Const, DebruijnIndex, GenericArg, Goal, Guidance, InEnvironment, InferenceVar, Canonical, Const, DebruijnIndex, GenericArg, GenericArgData, Goal, Guidance, InEnvironment,
Interner, Lifetime, ProjectionTy, ProjectionTyExt, Scalar, Solution, Substitution, InferenceVar, Interner, Lifetime, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution,
TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind,
}; };
impl<'a> InferenceContext<'a> { 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 // the solution may contain new variables, which we need to convert to new inference vars
let new_vars = Substitution::from_iter( let new_vars = Substitution::from_iter(
Interner, 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::General) => ctx.new_type_var().cast(Interner),
VariableKind::Ty(TyVariableKind::Integer) => ctx.new_integer_var().cast(Interner), VariableKind::Ty(TyVariableKind::Integer) => ctx.new_integer_var().cast(Interner),
VariableKind::Ty(TyVariableKind::Float) => ctx.new_float_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 // Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere
VariableKind::Lifetime => static_lifetime().cast(Interner), 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() { 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 mut table = InferenceTable::new(db, env);
let vars = Substitution::from_iter( let vars = Substitution::from_iter(
Interner, Interner,
tys.binders tys.binders.iter(Interner).map(|x| match &x.kind {
.iter(Interner) chalk_ir::VariableKind::Ty(_) => {
// we always use type vars here because we want everything to GenericArgData::Ty(table.new_type_var()).intern(Interner)
// fallback to Unknown in the end (kind of hacky, as below) }
.map(|_| table.new_type_var()), 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 ty1_with_vars = vars.apply(tys.value.0.clone(), Interner);
let ty2_with_vars = vars.apply(tys.value.1.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( Some(Substitution::from_iter(
Interner, Interner,
vars.iter(Interner) vars.iter(Interner).map(|v| table.resolve_with_fallback(v.clone(), &fallback)),
.map(|v| table.resolve_with_fallback(v.assert_ty_ref(Interner).clone(), &fallback)),
)) ))
} }
@ -552,11 +558,18 @@ impl<'a> InferenceTable<'a> {
let mut arg_tys = vec![]; let mut arg_tys = vec![];
let arg_ty = TyBuilder::tuple(num_args) let arg_ty = TyBuilder::tuple(num_args)
.fill(iter::repeat_with(|| { .fill(|x| {
let arg = self.new_type_var(); 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_tys.push(arg.clone());
arg GenericArgData::Ty(arg).intern(Interner)
})) })
.build(); .build();
let projection = { let projection = {

View File

@ -42,11 +42,13 @@ use hir_def::{
type_ref::{ConstScalar, Rawness}, type_ref::{ConstScalar, Rawness},
TypeOrConstParamId, TypeOrConstParamId,
}; };
use itertools::Either;
use utils::Generics;
use crate::{db::HirDatabase, utils::generics}; use crate::{db::HirDatabase, utils::generics};
pub use autoderef::autoderef; pub use autoderef::autoderef;
pub use builder::TyBuilder; pub use builder::{ParamKind, TyBuilder};
pub use chalk_ext::*; pub use chalk_ext::*;
pub use infer::{could_unify, InferenceDiagnostic, InferenceResult}; pub use infer::{could_unify, InferenceDiagnostic, InferenceResult};
pub use interner::Interner; pub use interner::Interner;
@ -140,20 +142,58 @@ where
Binders::empty(Interner, value.shifted_in_from(Interner, DebruijnIndex::ONE)) Binders::empty(Interner, value.shifted_in_from(Interner, DebruijnIndex::ONE))
} }
pub(crate) fn make_only_type_binders<T: HasInterner<Interner = Interner>>( pub(crate) fn make_type_and_const_binders<T: HasInterner<Interner = Interner>>(
num_vars: usize, which_is_const: impl Iterator<Item = Option<Ty>>,
value: T, value: T,
) -> Binders<T> { ) -> Binders<T> {
Binders::new( Binders::new(
VariableKinds::from_iter( VariableKinds::from_iter(
Interner, Interner,
std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)) which_is_const.map(|x| {
.take(num_vars), if let Some(ty) = x {
chalk_ir::VariableKind::Const(ty)
} else {
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
}
}),
), ),
value, 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 // FIXME: get rid of this
pub fn make_canonical<T: HasInterner<Interner = Interner>>( pub fn make_canonical<T: HasInterner<Interner = Interner>>(
value: T, value: T,
@ -288,11 +328,17 @@ pub fn dummy_usize_const() -> Const {
pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + Fold<Interner>>( pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + Fold<Interner>>(
t: T, 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 { ) -> T::Result {
use chalk_ir::{fold::Folder, Fallible}; use chalk_ir::{fold::Folder, Fallible};
struct FreeVarFolder<F>(F); struct FreeVarFolder<F1, F2>(F1, F2);
impl<'i, F: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i> Folder<Interner> for FreeVarFolder<F> { impl<
'i,
F1: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i,
F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const + 'i,
> Folder<Interner> for FreeVarFolder<F1, F2>
{
type Error = NoSolution; type Error = NoSolution;
fn as_dyn(&mut self) -> &mut dyn Folder<Interner, Error = Self::Error> { 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> { ) -> Fallible<Ty> {
Ok(self.0(bound_var, outer_binder)) 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>>( pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
t: T, 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, binders: DebruijnIndex,
) -> T::Result { ) -> T::Result {
use chalk_ir::{ use chalk_ir::{
@ -324,7 +395,9 @@ pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
Fallible, Fallible,
}; };
struct TyFolder<F>(F); 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; type Error = NoSolution;
fn as_dyn(&mut self) -> &mut dyn Folder<Interner, Error = Self::Error> { 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> { fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?; 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") t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")

View File

@ -9,9 +9,11 @@ use std::cell::{Cell, RefCell};
use std::{iter, sync::Arc}; use std::{iter, sync::Arc};
use base_db::CrateId; 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::generics::TypeOrConstParamData;
use hir_def::intern::Interned; use hir_def::intern::Interned;
use hir_def::path::{ModPath, PathKind};
use hir_def::type_ref::ConstScalarOrPath;
use hir_def::{ use hir_def::{
adt::StructKind, adt::StructKind,
body::{Expander, LowerCtx}, body::{Expander, LowerCtx},
@ -24,23 +26,25 @@ use hir_def::{
ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId,
UnionId, VariantId, UnionId, VariantId,
}; };
use hir_def::{ConstParamId, TypeOrConstParamId}; use hir_def::{ConstParamId, TypeOrConstParamId, TypeParamId};
use hir_expand::{name::Name, ExpandResult}; use hir_expand::{name::Name, ExpandResult};
use itertools::Either;
use la_arena::ArenaMap; use la_arena::ArenaMap;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use smallvec::SmallVec; use smallvec::SmallVec;
use stdx::{impl_from, never}; use stdx::{impl_from, never};
use syntax::{ast, SmolStr}; 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::{ use crate::{
consteval, consteval,
db::HirDatabase, db::HirDatabase,
mapping::ToChalk, mapping::ToChalk,
static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
utils::{ utils::{all_super_trait_refs, associated_type_by_name_including_super_traits, generics},
all_super_trait_refs, associated_type_by_name_including_super_traits, generics, Generics,
},
AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig, AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig,
FnSubst, ImplTraitId, Interner, PolyFnSig, ProjectionTy, QuantifiedWhereClause, FnSubst, ImplTraitId, Interner, PolyFnSig, ProjectionTy, QuantifiedWhereClause,
QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution, QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution,
@ -56,7 +60,7 @@ pub struct TyLoweringContext<'a> {
/// some type params should be represented as placeholders, and others /// some type params should be represented as placeholders, and others
/// should be converted to variables. I think in practice, this isn't /// should be converted to variables. I think in practice, this isn't
/// possible currently, so this should be fine for now. /// possible currently, so this should be fine for now.
pub type_param_mode: TypeParamLoweringMode, pub type_param_mode: ParamLoweringMode,
pub impl_trait_mode: ImplTraitLoweringMode, pub impl_trait_mode: ImplTraitLoweringMode,
impl_trait_counter: Cell<u16>, impl_trait_counter: Cell<u16>,
/// When turning `impl Trait` into opaque types, we have to collect the /// 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 { pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self {
let impl_trait_counter = Cell::new(0); let impl_trait_counter = Cell::new(0);
let impl_trait_mode = ImplTraitLoweringMode::Disallowed; let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
let type_param_mode = TypeParamLoweringMode::Placeholder; let type_param_mode = ParamLoweringMode::Placeholder;
let in_binders = DebruijnIndex::INNERMOST; let in_binders = DebruijnIndex::INNERMOST;
let opaque_type_data = RefCell::new(Vec::new()); let opaque_type_data = RefCell::new(Vec::new());
Self { Self {
@ -129,7 +133,7 @@ impl<'a> TyLoweringContext<'a> {
Self { impl_trait_mode, ..self } 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 } Self { type_param_mode, ..self }
} }
} }
@ -155,7 +159,7 @@ pub enum ImplTraitLoweringMode {
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum TypeParamLoweringMode { pub enum ParamLoweringMode {
Placeholder, Placeholder,
Variable, Variable,
} }
@ -165,6 +169,15 @@ impl<'a> TyLoweringContext<'a> {
self.lower_ty_ext(type_ref).0 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>) { pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
let mut res = None; let mut res = None;
let ty = match type_ref { let ty = match type_ref {
@ -185,8 +198,14 @@ impl<'a> TyLoweringContext<'a> {
} }
TypeRef::Array(inner, len) => { TypeRef::Array(inner, len) => {
let inner_ty = self.lower_ty(inner); let inner_ty = self.lower_ty(inner);
let const_len = const_or_path_to_chalk(
let const_len = consteval::usize_const(len.as_usize()); self.db,
self.resolver,
len,
self.type_param_mode,
|| self.generics(),
DebruijnIndex::INNERMOST,
);
TyKind::Array(inner_ty, const_len).intern(Interner) 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)), 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) TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
} }
TypeRef::ImplTrait(bounds) => { TypeRef::ImplTrait(bounds) => {
@ -239,7 +258,7 @@ impl<'a> TyLoweringContext<'a> {
// place even if we encounter more opaque types while // place even if we encounter more opaque types while
// lowering the bounds // lowering the bounds
self.opaque_type_data.borrow_mut().push(ReturnTypeImplTrait { 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 don't want to lower the bounds inside the binders
// we're currently in, because they don't end up inside // 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 impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx);
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
let generics = generics(self.db.upcast(), func.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) TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner)
} }
ImplTraitLoweringMode::Param => { ImplTraitLoweringMode::Param => {
@ -449,8 +468,7 @@ impl<'a> TyLoweringContext<'a> {
) )
}); });
let dyn_ty = DynTy { let dyn_ty = DynTy {
bounds: crate::make_only_type_binders( bounds: crate::make_single_type_binders(
1,
QuantifiedWhereClauses::from_iter( QuantifiedWhereClauses::from_iter(
Interner, Interner,
Some(crate::wrap_empty_binders(WhereClause::Implemented( Some(crate::wrap_empty_binders(WhereClause::Implemented(
@ -475,10 +493,10 @@ impl<'a> TyLoweringContext<'a> {
self.resolver.generic_def().expect("generics in scope"), self.resolver.generic_def().expect("generics in scope"),
); );
match self.type_param_mode { match self.type_param_mode {
TypeParamLoweringMode::Placeholder => { ParamLoweringMode::Placeholder => {
TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into())) 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"); let idx = generics.param_idx(param_id.into()).expect("matching generics");
TyKind::BoundVar(BoundVar::new(self.in_binders, idx)) TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
} }
@ -488,16 +506,20 @@ impl<'a> TyLoweringContext<'a> {
TypeNs::SelfType(impl_id) => { TypeNs::SelfType(impl_id) => {
let generics = generics(self.db.upcast(), impl_id.into()); let generics = generics(self.db.upcast(), impl_id.into());
let substs = match self.type_param_mode { let substs = match self.type_param_mode {
TypeParamLoweringMode::Placeholder => generics.type_params_subst(self.db), ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
TypeParamLoweringMode::Variable => generics.bound_vars_subst(self.in_binders), ParamLoweringMode::Variable => {
generics.bound_vars_subst(self.db, self.in_binders)
}
}; };
self.db.impl_self_ty(impl_id).substitute(Interner, &substs) self.db.impl_self_ty(impl_id).substitute(Interner, &substs)
} }
TypeNs::AdtSelfType(adt) => { TypeNs::AdtSelfType(adt) => {
let generics = generics(self.db.upcast(), adt.into()); let generics = generics(self.db.upcast(), adt.into());
let substs = match self.type_param_mode { let substs = match self.type_param_mode {
TypeParamLoweringMode::Placeholder => generics.type_params_subst(self.db), ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
TypeParamLoweringMode::Variable => generics.bound_vars_subst(self.in_binders), ParamLoweringMode::Variable => {
generics.bound_vars_subst(self.db, self.in_binders)
}
}; };
self.db.ty(adt.into()).substitute(Interner, &substs) self.db.ty(adt.into()).substitute(Interner, &substs)
} }
@ -549,7 +571,7 @@ impl<'a> TyLoweringContext<'a> {
move |name, t, associated_ty| { move |name, t, associated_ty| {
if name == segment.name { if name == segment.name {
let substs = match self.type_param_mode { let substs = match self.type_param_mode {
TypeParamLoweringMode::Placeholder => { ParamLoweringMode::Placeholder => {
// if we're lowering to placeholders, we have to put // if we're lowering to placeholders, we have to put
// them in now // them in now
let generics = generics( let generics = generics(
@ -558,10 +580,10 @@ impl<'a> TyLoweringContext<'a> {
.generic_def() .generic_def()
.expect("there should be generics if there's a generic param"), .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) 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 // We need to shift in the bound vars, since
// associated_type_shorthand_candidates does not do that // associated_type_shorthand_candidates does not do that
@ -642,47 +664,75 @@ impl<'a> TyLoweringContext<'a> {
explicit_self_ty: Option<Ty>, explicit_self_ty: Option<Ty>,
) -> Substitution { ) -> Substitution {
let mut substs = Vec::new(); 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) = 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 = let total_len =
parent_params + self_params + type_params + const_params + impl_trait_params; 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 = || { let fill_self_params = || {
substs.extend( substs.extend(
explicit_self_ty explicit_self_ty
.into_iter() .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), .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 let Some(generic_args) = &segment.args_and_bindings {
if !generic_args.has_self_type { if !generic_args.has_self_type {
fill_self_params(); fill_self_params();
} }
let expected_num = let expected_num = if generic_args.has_self_type {
if generic_args.has_self_type { self_params + type_params } else { type_params }; 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 }; 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 // 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 .args
.iter() .iter()
.filter(|arg| matches!(arg, GenericArg::Type(_))) .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
.skip(skip) .skip(skip)
.take(expected_num) .take(expected_num)
.zip(def_generics.iter_id().skip(skip))
{ {
match arg { if let Some(x) = generic_arg_to_chalk(
GenericArg::Type(type_ref) => { self.db,
had_explicit_type_args = true; id,
let ty = self.lower_ty(type_ref); arg,
substs.push(ty); &mut (),
} |_, type_ref| self.lower_ty(type_ref),
GenericArg::Lifetime(_) => {} |_, 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 { } else {
@ -692,7 +742,7 @@ impl<'a> TyLoweringContext<'a> {
// handle defaults. In expression or pattern path segments without // handle defaults. In expression or pattern path segments without
// explicitly specified type arguments, missing type arguments are inferred // explicitly specified type arguments, missing type arguments are inferred
// (i.e. defaults aren't used). // (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 { if let Some(def_generic) = def_generic {
let defaults = self.db.generic_defaults(def_generic); let defaults = self.db.generic_defaults(def_generic);
assert_eq!(total_len, defaults.len()); assert_eq!(total_len, defaults.len());
@ -707,8 +757,11 @@ impl<'a> TyLoweringContext<'a> {
// add placeholders for args that were not provided // add placeholders for args that were not provided
// FIXME: emit diagnostics in contexts where this is not allowed // FIXME: emit diagnostics in contexts where this is not allowed
for _ in substs.len()..total_len { for (_, data) in def_generics.iter().skip(substs.len()) {
substs.push(TyKind::Error.intern(Interner)); match data {
TypeOrConstParamData::TypeParamData(_) => substs.push(ty_error.clone()),
TypeOrConstParamData::ConstParamData(_) => substs.push(const_error.clone()),
}
} }
assert_eq!(substs.len(), total_len); assert_eq!(substs.len(), total_len);
@ -775,8 +828,8 @@ impl<'a> TyLoweringContext<'a> {
}; };
let placeholder = to_placeholder_idx(self.db, param_id); let placeholder = to_placeholder_idx(self.db, param_id);
match self.type_param_mode { match self.type_param_mode {
TypeParamLoweringMode::Placeholder => TyKind::Placeholder(placeholder), ParamLoweringMode::Placeholder => TyKind::Placeholder(placeholder),
TypeParamLoweringMode::Variable => { ParamLoweringMode::Variable => {
let idx = generics.param_idx(param_id).expect("matching generics"); let idx = generics.param_idx(param_id).expect("matching generics");
TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, idx)) TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, idx))
} }
@ -919,8 +972,7 @@ impl<'a> TyLoweringContext<'a> {
} }
predicates predicates
}); });
ReturnTypeImplTrait { bounds: crate::make_single_type_binders(predicates) }
ReturnTypeImplTrait { bounds: crate::make_only_type_binders(1, predicates) }
} }
} }
@ -999,7 +1051,7 @@ fn named_associated_type_shorthand_candidates<R>(
// Handle `Self::Type` referring to own associated type in trait definitions // Handle `Self::Type` referring to own associated type in trait definitions
if let GenericDefId::TraitId(trait_id) = param_id.parent() { if let GenericDefId::TraitId(trait_id) = param_id.parent() {
let generics = generics(db.upcast(), trait_id.into()); 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) let trait_ref = TyBuilder::trait_ref(db, trait_id)
.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0) .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
.build(); .build();
@ -1026,9 +1078,9 @@ pub(crate) fn field_types_query(
let generics = generics(db.upcast(), def); let generics = generics(db.upcast(), def);
let mut res = ArenaMap::default(); let mut res = ArenaMap::default();
let ctx = 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() { 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) Arc::new(res)
} }
@ -1049,7 +1101,7 @@ pub(crate) fn generic_predicates_for_param_query(
) -> Arc<[Binders<QuantifiedWhereClause>]> { ) -> Arc<[Binders<QuantifiedWhereClause>]> {
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx = 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 generics = generics(db.upcast(), def);
let mut predicates: Vec<_> = resolver let mut predicates: Vec<_> = resolver
.where_predicates_in_scope() .where_predicates_in_scope()
@ -1097,14 +1149,16 @@ pub(crate) fn generic_predicates_for_param_query(
} }
WherePredicate::Lifetime { .. } => false, 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(); .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 explicitly_unsized_tys = ctx.unsized_types.into_inner();
let implicitly_sized_predicates = let implicitly_sized_predicates =
implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &subst, &resolver) 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.extend(implicitly_sized_predicates);
predicates.into() predicates.into()
} }
@ -1124,8 +1178,8 @@ pub(crate) fn trait_environment_query(
def: GenericDefId, def: GenericDefId,
) -> Arc<TraitEnvironment> { ) -> Arc<TraitEnvironment> {
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver) let ctx =
.with_type_param_mode(TypeParamLoweringMode::Placeholder); TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Placeholder);
let mut traits_in_scope = Vec::new(); let mut traits_in_scope = Vec::new();
let mut clauses = Vec::new(); let mut clauses = Vec::new();
for pred in resolver.where_predicates_in_scope() { for pred in resolver.where_predicates_in_scope() {
@ -1153,14 +1207,14 @@ pub(crate) fn trait_environment_query(
// function default implementations (and speculative code // function default implementations (and speculative code
// inside consts or type aliases) // inside consts or type aliases)
cov_mark::hit!(trait_self_implements_self); 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 trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
let pred = WhereClause::Implemented(trait_ref); let pred = WhereClause::Implemented(trait_ref);
let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner); let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
clauses.push(program_clause.into_from_env_clause(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 explicitly_unsized_tys = ctx.unsized_types.into_inner();
let implicitly_sized_clauses = let implicitly_sized_clauses =
implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver).map(|pred| { 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>]> { ) -> Arc<[Binders<QuantifiedWhereClause>]> {
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx = 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 generics = generics(db.upcast(), def);
let mut predicates = resolver let mut predicates = resolver
.where_predicates_in_scope() .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<_>>(); .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 explicitly_unsized_tys = ctx.unsized_types.into_inner();
let implicitly_sized_predicates = let implicitly_sized_predicates =
implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) 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.extend(implicitly_sized_predicates);
predicates.into() predicates.into()
} }
@ -1234,40 +1290,36 @@ fn implicitly_sized_clauses<'a>(
pub(crate) fn generic_defaults_query( pub(crate) fn generic_defaults_query(
db: &dyn HirDatabase, db: &dyn HirDatabase,
def: GenericDefId, def: GenericDefId,
) -> Arc<[Binders<Ty>]> { ) -> Arc<[Binders<chalk_ir::GenericArg<Interner>>]> {
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx = 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 generic_params = generics(db.upcast(), def);
let defaults = generic_params let defaults = generic_params
.toc_iter() .iter()
.enumerate() .enumerate()
.map(|(idx, (_, p))| { .map(|(idx, (id, p))| {
let p = match p { let p = match p {
TypeOrConstParamData::TypeParamData(p) => p, TypeOrConstParamData::TypeParamData(p) => p,
TypeOrConstParamData::ConstParamData(_) => { TypeOrConstParamData::ConstParamData(_) => {
// FIXME: here we should add const generic parameters // FIXME: implement const generic defaults
let ty = TyKind::Error.intern(Interner); let val = unknown_const_as_generic(
return crate::make_only_type_binders(idx, ty); db.const_param_ty(ConstParamId::from_unchecked(id)),
);
return crate::make_binders_with_count(db, idx, &generic_params, val);
} }
}; };
let mut ty = let mut ty =
p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t)); p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
// Each default can only refer to previous parameters. // Each default can only refer to previous parameters.
ty = crate::fold_free_vars(ty, |bound, binders| { // type variable default referring to parameter coming
if bound.index >= idx && bound.debruijn == DebruijnIndex::INNERMOST { // after it. This is forbidden (FIXME: report
// type variable default referring to parameter coming // diagnostic)
// after it. This is forbidden (FIXME: report ty = fallback_bound_vars(ty, idx);
// diagnostic) let val = GenericArgData::Ty(ty).intern(Interner);
TyKind::Error.intern(Interner) crate::make_binders_with_count(db, idx, &generic_params, val)
} else {
bound.shifted_in_from(binders).to_ty(Interner)
}
});
crate::make_only_type_binders(idx, ty)
}) })
.collect(); .collect();
@ -1278,17 +1330,21 @@ pub(crate) fn generic_defaults_recover(
db: &dyn HirDatabase, db: &dyn HirDatabase,
_cycle: &[String], _cycle: &[String],
def: &GenericDefId, def: &GenericDefId,
) -> Arc<[Binders<Ty>]> { ) -> Arc<[Binders<crate::GenericArg>]> {
let generic_params = generics(db.upcast(), *def); let generic_params = generics(db.upcast(), *def);
// FIXME: this code is not covered in tests.
// we still need one default per parameter // we still need one default per parameter
let defaults = generic_params let defaults = generic_params
.toc_iter() .iter_id()
.enumerate() .enumerate()
.map(|(idx, _)| { .map(|(count, id)| {
let ty = TyKind::Error.intern(Interner); let val = match id {
itertools::Either::Left(_) => {
crate::make_only_type_binders(idx, ty) 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(); .collect();
@ -1300,26 +1356,27 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx_params = TyLoweringContext::new(db, &resolver) let ctx_params = TyLoweringContext::new(db, &resolver)
.with_impl_trait_mode(ImplTraitLoweringMode::Variable) .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 params = data.params.iter().map(|(_, tr)| ctx_params.lower_ty(tr)).collect::<Vec<_>>();
let ctx_ret = TyLoweringContext::new(db, &resolver) let ctx_ret = TyLoweringContext::new(db, &resolver)
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .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 ret = ctx_ret.lower_ty(&data.ret_type);
let generics = generics(db.upcast(), def.into()); let generics = generics(db.upcast(), def.into());
let mut sig = CallableSig::from_params_and_return(params, ret, data.is_varargs()); let mut sig = CallableSig::from_params_and_return(params, ret, data.is_varargs());
if !data.legacy_const_generics_indices.is_empty() { if !data.legacy_const_generics_indices.is_empty() {
sig.set_legacy_const_generics_indices(&data.legacy_const_generics_indices); 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 /// Build the declared type of a function. This should not need to look at the
/// function body. /// function body.
fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> { fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> {
let generics = generics(db.upcast(), 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( make_binders(
db,
&generics, &generics,
TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(Interner), 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 generics = generics(db.upcast(), def.into());
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx = 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. /// 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 fields = struct_data.variant_data.fields();
let resolver = def.resolver(db.upcast()); let resolver = def.resolver(db.upcast());
let ctx = 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 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(); 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)) 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()); return type_for_adt(db, def.into());
} }
let generics = generics(db.upcast(), 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( make_binders(
db,
&generics, &generics,
TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(Interner), 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 fields = var_data.variant_data.fields();
let resolver = def.parent.resolver(db.upcast()); let resolver = def.parent.resolver(db.upcast());
let ctx = 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 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(); 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)) 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()); return type_for_adt(db, def.parent.into());
} }
let generics = generics(db.upcast(), 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( make_binders(
db,
&generics, &generics,
TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs).intern(Interner), 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> { fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
let generics = generics(db.upcast(), adt.into()); let generics = generics(db.upcast(), adt.into());
let b = TyBuilder::adt(db, adt); let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
let ty = b.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build(); let ty = TyKind::Adt(crate::AdtId(adt), subst).intern(Interner);
make_binders(&generics, ty) make_binders(db, &generics, ty)
} }
fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
let generics = generics(db.upcast(), t.into()); let generics = generics(db.upcast(), t.into());
let resolver = t.resolver(db.upcast()); let resolver = t.resolver(db.upcast());
let ctx = 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 { if db.type_alias_data(t).is_extern {
Binders::empty(Interner, TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner)) Binders::empty(Interner, TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner))
} else { } else {
let type_ref = &db.type_alias_data(t).type_ref; let type_ref = &db.type_alias_data(t).type_ref;
let inner = ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error)); 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::AdtId(it) => generics(db.upcast(), it.into()),
TyDefId::TypeAliasId(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> { 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 generics = generics(db.upcast(), impl_id.into());
let ctx = 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(&impl_data.self_ty)) make_binders(db, &generics, ctx.lower_ty(&impl_data.self_ty))
} }
// returns None if def is a type arg // returns None if def is a type arg
pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
let parent_data = db.generic_params(def.parent()); 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 resolver = def.parent().resolver(db.upcast());
let ctx = TyLoweringContext::new(db, &resolver); let ctx = TyLoweringContext::new(db, &resolver);
match data { match data {
@ -1534,7 +1593,7 @@ pub(crate) fn impl_self_ty_recover(
impl_id: &ImplId, impl_id: &ImplId,
) -> Binders<Ty> { ) -> Binders<Ty> {
let generics = generics(db.upcast(), (*impl_id).into()); 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>> { 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 impl_id, impl_loc, impl_data
)); ));
let ctx = 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 (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
let target_trait = impl_data.target_trait.as_ref()?; let target_trait = impl_data.target_trait.as_ref()?;
Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, Some(self_ty))?)) 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 resolver = def.resolver(db.upcast());
let ctx_ret = TyLoweringContext::new(db, &resolver) let ctx_ret = TyLoweringContext::new(db, &resolver)
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .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 _ret = (&ctx_ret).lower_ty(&data.ret_type);
let generics = generics(db.upcast(), def.into()); let generics = generics(db.upcast(), def.into());
let return_type_impl_traits = 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() { if return_type_impl_traits.impl_traits.is_empty() {
None None
} else { } 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> { pub(crate) fn generic_arg_to_chalk<'a, T>(
crate::make_only_type_binders(generics.len(), value) 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())
}
}
} }

View File

@ -6,7 +6,7 @@ use std::{iter, ops::ControlFlow, sync::Arc};
use arrayvec::ArrayVec; use arrayvec::ArrayVec;
use base_db::{CrateId, Edition}; 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::{ use hir_def::{
item_scope::ItemScope, lang_item::LangItemTarget, nameres::DefMap, AssocItemId, BlockId, item_scope::ItemScope, lang_item::LangItemTarget, nameres::DefMap, AssocItemId, BlockId,
ConstId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId, ConstId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId,
@ -25,8 +25,9 @@ use crate::{
primitive::{self, FloatTy, IntTy, UintTy}, primitive::{self, FloatTy, IntTy, UintTy},
static_lifetime, static_lifetime,
utils::all_super_traits, utils::all_super_traits,
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner, AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, GenericArgData,
Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder,
TyExt, TyKind,
}; };
/// This is used as a key for indexing impls. /// This is used as a key for indexing impls.
@ -1087,13 +1088,14 @@ pub(crate) fn inherent_impl_substs(
.build(); .build();
let self_ty_with_vars = db.impl_self_ty(impl_id).substitute(Interner, &vars); let self_ty_with_vars = db.impl_self_ty(impl_id).substitute(Interner, &vars);
let mut kinds = self_ty.binders.interned().to_vec(); let mut kinds = self_ty.binders.interned().to_vec();
kinds.extend( kinds.extend(vars.iter(Interner).map(|x| {
iter::repeat(chalk_ir::WithKind::new( let kind = match x.data(Interner) {
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), GenericArgData::Ty(_) => chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
UniverseIndex::ROOT, GenericArgData::Const(c) => chalk_ir::VariableKind::Const(c.data(Interner).ty.clone()),
)) GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
.take(vars.len(Interner)), };
); chalk_ir::WithKind::new(kind, UniverseIndex::ROOT)
}));
let tys = Canonical { let tys = Canonical {
binders: CanonicalVarKinds::from_iter(Interner, kinds), binders: CanonicalVarKinds::from_iter(Interner, kinds),
value: (self_ty_with_vars, self_ty.value.clone()), 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 /// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
/// num_vars_to_keep) by `TyKind::Unknown`. /// num_vars_to_keep) by `TyKind::Unknown`.
fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution { pub(crate) fn fallback_bound_vars<T: Fold<Interner> + HasInterner<Interner = Interner>>(
crate::fold_free_vars(s, |bound, binders| { s: T,
if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST { num_vars_to_keep: usize,
TyKind::Error.intern(Interner) ) -> T::Result {
} else { crate::fold_free_vars(
bound.shifted_in_from(binders).to_ty(Interner) 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( fn transform_receiver_ty(
@ -1183,13 +1198,18 @@ fn generic_implements_goal(
.push(self_ty.value.clone()) .push(self_ty.value.clone())
.fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len()) .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
.build(); .build();
kinds.extend( kinds.extend(trait_ref.substitution.iter(Interner).skip(1).map(|x| {
iter::repeat(chalk_ir::WithKind::new( let vk = match x.data(Interner) {
chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), chalk_ir::GenericArgData::Ty(_) => {
UniverseIndex::ROOT, chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
)) }
.take(trait_ref.substitution.len(Interner) - 1), 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); let obligation = trait_ref.cast(Interner);
Canonical { Canonical {
binders: CanonicalVarKinds::from_iter(Interner, kinds), binders: CanonicalVarKinds::from_iter(Interner, kinds),

View File

@ -1359,7 +1359,69 @@ impl<T> [T] {
fn f() { fn f() {
let v = [1, 2].map::<_, usize>(|x| -> x * 2); let v = [1, 2].map::<_, usize>(|x| -> x * 2);
v; 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>
} }
"#, "#,
); );

View File

@ -1301,7 +1301,7 @@ impl<I: Iterator> IntoIterator for I {
#[test] #[test]
fn bug_11659() { fn bug_11659() {
check_infer( check_no_mismatches(
r#" r#"
struct LinkArray<const N: usize, LD>(LD); struct LinkArray<const N: usize, LD>(LD);
fn f<const N: usize, LD>(x: LD) -> LinkArray<N, 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); 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#" r#"
struct LinkArray<LD, const N: usize>(LD); struct LinkArray<LD, const N: usize>(LD);
fn f<const N: usize, LD>(x: LD) -> LinkArray<LD, N> { 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); 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),
}
}
"#,
)
}

View File

@ -1202,14 +1202,13 @@ fn infer_array() {
let b = [a, ["b"]]; let b = [a, ["b"]];
let x: [u8; 0] = []; let x: [u8; 0] = [];
// FIXME: requires const evaluation/taking type from rhs somehow
let y: [u8; 2+2] = [1,2,3,4]; let y: [u8; 2+2] = [1,2,3,4];
} }
"#, "#,
expect![[r#" expect![[r#"
8..9 'x': &str 8..9 'x': &str
17..18 'y': isize 17..18 'y': isize
27..395 '{ ...,4]; }': () 27..326 '{ ...,4]; }': ()
37..38 'a': [&str; 1] 37..38 'a': [&str; 1]
41..44 '[x]': [&str; 1] 41..44 '[x]': [&str; 1]
42..43 'x': &str 42..43 'x': &str
@ -1259,12 +1258,12 @@ fn infer_array() {
259..262 '"b"': &str 259..262 '"b"': &str
274..275 'x': [u8; 0] 274..275 'x': [u8; 0]
287..289 '[]': [u8; 0] 287..289 '[]': [u8; 0]
368..369 'y': [u8; _] 299..300 'y': [u8; 4]
383..392 '[1,2,3,4]': [u8; 4] 314..323 '[1,2,3,4]': [u8; 4]
384..385 '1': u8 315..316 '1': u8
386..387 '2': u8 317..318 '2': u8
388..389 '3': u8 319..320 '3': u8
390..391 '4': u8 321..322 '4': u8
"#]], "#]],
); );
} }

View File

@ -3394,7 +3394,6 @@ fn main() {
) )
} }
// FIXME: We should infer the length of the returned array :)
#[test] #[test]
fn const_generics() { fn const_generics() {
check_infer( check_infer(
@ -3418,18 +3417,18 @@ fn main() {
"#, "#,
expect![[r#" expect![[r#"
44..48 'self': &Self 44..48 'self': &Self
151..155 'self': &[u8; _] 151..155 'self': &[u8; L]
173..194 '{ ... }': [u8; _] 173..194 '{ ... }': [u8; L]
183..188 '*self': [u8; _] 183..188 '*self': [u8; L]
184..188 'self': &[u8; _] 184..188 'self': &[u8; L]
208..260 '{ ...g(); }': () 208..260 '{ ...g(); }': ()
218..219 'v': [u8; 2] 218..219 'v': [u8; 2]
222..230 '[0u8; 2]': [u8; 2] 222..230 '[0u8; 2]': [u8; 2]
223..226 '0u8': u8 223..226 '0u8': u8
228..229 '2': usize 228..229 '2': usize
240..242 'v2': [u8; _] 240..242 'v2': [u8; 2]
245..246 'v': [u8; 2] 245..246 'v': [u8; 2]
245..257 'v.do_thing()': [u8; _] 245..257 'v.do_thing()': [u8; 2]
"#]], "#]],
) )
} }

View File

@ -15,16 +15,18 @@ use hir_def::{
path::Path, path::Path,
resolver::{HasResolver, TypeNs}, resolver::{HasResolver, TypeNs},
type_ref::{TraitBoundModifier, TypeRef}, 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 hir_expand::name::{name, Name};
use itertools::Either;
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
use syntax::SmolStr; use syntax::SmolStr;
use crate::{ use crate::{
db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, TyKind, db::HirDatabase, ChalkTraitId, ConstData, ConstValue, GenericArgData, Interner, Substitution,
WhereClause, TraitRef, TraitRefExt, TyKind, WhereClause,
}; };
pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> { 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, &'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 self.parent_generics
.as_ref() .as_ref()
.into_iter() .into_iter()
.flat_map(|it| { .flat_map(|it| {
it.params it.params
.toc_iter() .iter()
.map(move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)) .map(move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p))
}) })
.chain( .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) (TypeOrConstParamId { parent: self.def, local_id }, p)
}), }),
) )
} }
/// Iterator over types and const params of parent.
pub(crate) fn iter_parent<'a>( pub(crate) fn iter_parent<'a>(
&'a self, &'a self,
) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a { ) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
self.parent_generics.as_ref().into_iter().flat_map(|it| { self.parent_generics.as_ref().into_iter().flat_map(|it| {
it.params it.params
.tocs .type_or_consts
.iter() .iter()
.map(move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)) .map(move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p))
}) })
@ -239,7 +254,7 @@ impl Generics {
/// (total, parents, child) /// (total, parents, child)
pub(crate) fn len_split(&self) -> (usize, usize, usize) { pub(crate) fn len_split(&self) -> (usize, usize, usize) {
let parent = self.parent_generics.as_ref().map_or(0, |p| p.len()); 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) (parent + child, parent, child)
} }
@ -248,22 +263,20 @@ impl Generics {
let parent = self.parent_generics.as_ref().map_or(0, |p| p.len()); let parent = self.parent_generics.as_ref().map_or(0, |p| p.len());
let self_params = self let self_params = self
.params .params
.tocs
.iter() .iter()
.filter_map(|x| x.1.type_param()) .filter_map(|x| x.1.type_param())
.filter(|p| p.provenance == TypeParamProvenance::TraitSelf) .filter(|p| p.provenance == TypeParamProvenance::TraitSelf)
.count(); .count();
let type_params = self let type_params = self
.params .params
.tocs .type_or_consts
.iter() .iter()
.filter_map(|x| x.1.type_param()) .filter_map(|x| x.1.type_param())
.filter(|p| p.provenance == TypeParamProvenance::TypeParamList) .filter(|p| p.provenance == TypeParamProvenance::TypeParamList)
.count(); .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 let impl_trait_params = self
.params .params
.tocs
.iter() .iter()
.filter_map(|x| x.1.type_param()) .filter_map(|x| x.1.type_param())
.filter(|p| p.provenance == TypeParamProvenance::ArgumentImplTrait) .filter(|p| p.provenance == TypeParamProvenance::ArgumentImplTrait)
@ -279,7 +292,7 @@ impl Generics {
if param.parent == self.def { if param.parent == self.def {
let (idx, (_local_id, data)) = self let (idx, (_local_id, data)) = self
.params .params
.tocs .type_or_consts
.iter() .iter()
.enumerate() .enumerate()
.find(|(_, (idx, _))| *idx == param.local_id) .find(|(_, (idx, _))| *idx == param.local_id)
@ -292,21 +305,47 @@ impl Generics {
} }
/// Returns a Substitution that replaces each parameter by a bound variable. /// 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( Substitution::from_iter(
Interner, Interner,
self.toc_iter() self.iter_id().enumerate().map(|(idx, id)| match id {
.enumerate() Either::Left(_) => GenericArgData::Ty(
.map(|(idx, _)| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner)), 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`). /// 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( Substitution::from_iter(
Interner, Interner,
self.toc_iter().map(|(id, _)| { self.iter_id().map(|id| match id {
TyKind::Placeholder(crate::to_placeholder_idx(db, id)).intern(Interner) 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),
}), }),
) )
} }

View File

@ -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] #[test]
fn hover_const_param() { fn hover_const_param() {
check( check(