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

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

View File

@ -55,7 +55,9 @@ use hir_def::{
use hir_expand::{name::name, MacroCallKind};
use hir_ty::{
autoderef,
consteval::{eval_const, ComputedExpr, ConstEvalCtx, ConstEvalError, ConstExt},
consteval::{
eval_const, unknown_const_as_generic, ComputedExpr, ConstEvalCtx, ConstEvalError, ConstExt,
},
could_unify,
diagnostics::BodyValidationDiagnostic,
method_resolution::{self, TyFingerprint},
@ -63,9 +65,9 @@ use hir_ty::{
subst_prefix,
traits::FnTrait,
AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, Substitution,
TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind,
WhereClause,
DebruijnIndex, GenericArgData, InEnvironment, Interner, ParamKind, QuantifiedWhereClause,
Scalar, Solution, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt,
TyKind, TyVariableKind, WhereClause,
};
use itertools::Itertools;
use nameres::diagnostics::DefDiagnosticKind;
@ -796,7 +798,7 @@ impl Field {
VariantDef::Union(it) => it.id.into(),
VariantDef::Variant(it) => it.parent.id.into(),
};
let substs = TyBuilder::type_params_subst(db, generic_def_id);
let substs = TyBuilder::placeholder_subst(db, generic_def_id);
let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
Type::new(db, self.parent.module(db).id.krate(), var_id, ty)
}
@ -983,7 +985,10 @@ impl_from!(Struct, Union, Enum for Adt);
impl Adt {
pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
let subst = db.generic_defaults(self.into());
subst.iter().any(|ty| ty.skip_binders().is_unknown())
subst.iter().any(|ty| match ty.skip_binders().data(Interner) {
GenericArgData::Ty(x) => x.is_unknown(),
_ => false,
})
}
/// Turns this ADT into a type. Any type parameters of the ADT will be
@ -1680,7 +1685,10 @@ pub struct TypeAlias {
impl TypeAlias {
pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
let subst = db.generic_defaults(self.id.into());
subst.iter().any(|ty| ty.skip_binders().is_unknown())
subst.iter().any(|ty| match ty.skip_binders().data(Interner) {
GenericArgData::Ty(x) => x.is_unknown(),
_ => false,
})
}
pub fn module(self, db: &dyn HirDatabase) -> Module {
@ -2047,7 +2055,7 @@ impl_from!(
impl GenericDef {
pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
let generics = db.generic_params(self.into());
let ty_params = generics.tocs.iter().map(|(local_id, _)| {
let ty_params = generics.type_or_consts.iter().map(|(local_id, _)| {
let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } };
match toc.split(db) {
Either::Left(x) => GenericParam::ConstParam(x),
@ -2067,7 +2075,7 @@ impl GenericDef {
pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
let generics = db.generic_params(self.into());
generics
.tocs
.type_or_consts
.iter()
.map(|(local_id, _)| TypeOrConstParam {
id: TypeOrConstParamId { parent: self.into(), local_id },
@ -2351,9 +2359,14 @@ impl TypeParam {
let resolver = self.id.parent().resolver(db.upcast());
let krate = self.id.parent().module(db.upcast()).krate();
let ty = params.get(local_idx)?.clone();
let subst = TyBuilder::type_params_subst(db, self.id.parent());
let subst = TyBuilder::placeholder_subst(db, self.id.parent());
let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx));
Some(Type::new_with_resolver_inner(db, krate, &resolver, ty))
match ty.data(Interner) {
GenericArgData::Ty(x) => {
Some(Type::new_with_resolver_inner(db, krate, &resolver, x.clone()))
}
_ => None,
}
}
}
@ -2389,7 +2402,7 @@ impl ConstParam {
pub fn name(self, db: &dyn HirDatabase) -> Name {
let params = db.generic_params(self.id.parent());
match params.tocs[self.id.local_id()].name() {
match params.type_or_consts[self.id.local_id()].name() {
Some(x) => x.clone(),
None => {
never!();
@ -2421,7 +2434,7 @@ pub struct TypeOrConstParam {
impl TypeOrConstParam {
pub fn name(self, db: &dyn HirDatabase) -> Name {
let params = db.generic_params(self.id.parent);
match params.tocs[self.id.local_id].name() {
match params.type_or_consts[self.id.local_id].name() {
Some(n) => n.clone(),
_ => Name::missing(),
}
@ -2437,12 +2450,12 @@ impl TypeOrConstParam {
pub fn split(self, db: &dyn HirDatabase) -> Either<ConstParam, TypeParam> {
let params = db.generic_params(self.id.parent);
match &params.tocs[self.id.local_id] {
match &params.type_or_consts[self.id.local_id] {
hir_def::generics::TypeOrConstParamData::TypeParamData(_) => {
Either::Right(TypeParam { id: self.id.into() })
Either::Right(TypeParam { id: TypeParamId::from_unchecked(self.id) })
}
hir_def::generics::TypeOrConstParamData::ConstParamData(_) => {
Either::Left(ConstParam { id: self.id.into() })
Either::Left(ConstParam { id: ConstParamId::from_unchecked(self.id) })
}
}
}
@ -2688,9 +2701,19 @@ impl Type {
}
pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
let mut it = args.iter().map(|t| t.ty.clone());
let trait_ref = TyBuilder::trait_ref(db, trait_.id)
.push(self.ty.clone())
.fill(args.iter().map(|t| t.ty.clone()))
.fill(|x| {
let r = it.next().unwrap();
match x {
ParamKind::Type => GenericArgData::Ty(r).intern(Interner),
ParamKind::Const(ty) => {
// FIXME: this code is not covered in tests.
unknown_const_as_generic(ty.clone())
}
}
})
.build();
let goal = Canonical {
@ -2707,9 +2730,18 @@ impl Type {
args: &[Type],
alias: TypeAlias,
) -> Option<Type> {
let mut args = args.iter();
let projection = TyBuilder::assoc_type_projection(db, alias.id)
.push(self.ty.clone())
.fill(args.iter().map(|t| t.ty.clone()))
.fill(|x| {
// FIXME: this code is not covered in tests.
match x {
ParamKind::Type => {
GenericArgData::Ty(args.next().unwrap().ty.clone()).intern(Interner)
}
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
}
})
.build();
let goal = hir_ty::make_canonical(
InEnvironment::new(

View File

@ -279,7 +279,7 @@ impl SourceToDefCtx<'_, '_> {
pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> {
let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into();
let dyn_map = self.cache_for(container, src.file_id);
dyn_map[keys::TYPE_PARAM].get(&src.value).copied().map(|x| x.into())
dyn_map[keys::TYPE_PARAM].get(&src.value).copied().map(|x| TypeParamId::from_unchecked(x))
}
pub(super) fn lifetime_param_to_def(
@ -297,7 +297,7 @@ impl SourceToDefCtx<'_, '_> {
) -> Option<ConstParamId> {
let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into();
let dyn_map = self.cache_for(container, src.file_id);
dyn_map[keys::CONST_PARAM].get(&src.value).copied().map(|x| x.into())
dyn_map[keys::CONST_PARAM].get(&src.value).copied().map(|x| ConstParamId::from_unchecked(x))
}
pub(super) fn generic_param_to_def(

View File

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

View File

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

View File

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

View File

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

View File

@ -6,7 +6,11 @@ use std::{
iter,
};
use crate::{body::LowerCtx, intern::Interned, type_ref::LifetimeRef};
use crate::{
body::LowerCtx,
intern::Interned,
type_ref::{ConstScalarOrPath, LifetimeRef},
};
use hir_expand::name::{name, Name};
use syntax::ast;
@ -78,6 +82,7 @@ pub struct AssociatedTypeBinding {
pub enum GenericArg {
Type(TypeRef),
Lifetime(LifetimeRef),
Const(ConstScalarOrPath),
}
impl Path {

View File

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

View File

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

View File

@ -89,7 +89,7 @@ pub enum TypeRef {
Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
// FIXME: for full const generics, the latter element (length) here is going to have to be an
// expression that is further lowered later in hir_ty.
Array(Box<TypeRef>, ConstScalar),
Array(Box<TypeRef>, ConstScalarOrPath),
Slice(Box<TypeRef>),
/// A fn pointer. Last element of the vector is the return type.
Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/),
@ -162,10 +162,7 @@ impl TypeRef {
// `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the
// `hir_ty` level, which would allow knowing the type of:
// let v: [u8; 2 + 2] = [0u8; 4];
let len = inner
.expr()
.map(ConstScalar::usize_from_literal_expr)
.unwrap_or(ConstScalar::Unknown);
let len = ConstScalarOrPath::from_expr_opt(inner.expr());
TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len)
}
@ -278,7 +275,8 @@ impl TypeRef {
crate::path::GenericArg::Type(type_ref) => {
go(type_ref, f);
}
crate::path::GenericArg::Lifetime(_) => {}
crate::path::GenericArg::Const(_)
| crate::path::GenericArg::Lifetime(_) => {}
}
}
for binding in &args_and_bindings.bindings {
@ -357,6 +355,60 @@ impl TypeBound {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ConstScalarOrPath {
Scalar(ConstScalar),
Path(Name),
}
impl std::fmt::Display for ConstScalarOrPath {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ConstScalarOrPath::Scalar(s) => write!(f, "{}", s),
ConstScalarOrPath::Path(n) => write!(f, "{}", n),
}
}
}
impl ConstScalarOrPath {
pub(crate) fn from_expr_opt(expr: Option<ast::Expr>) -> Self {
match expr {
Some(x) => Self::from_expr(x),
None => Self::Scalar(ConstScalar::Unknown),
}
}
// FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this
// parse stage.
fn from_expr(expr: ast::Expr) -> Self {
match expr {
ast::Expr::PathExpr(p) => {
match p.path().and_then(|x| x.segment()).and_then(|x| x.name_ref()) {
Some(x) => Self::Path(x.as_name()),
None => Self::Scalar(ConstScalar::Unknown),
}
}
ast::Expr::Literal(lit) => {
let lkind = lit.kind();
match lkind {
ast::LiteralKind::IntNumber(num)
if num.suffix() == None || num.suffix() == Some("usize") =>
{
Self::Scalar(
num.value()
.and_then(|v| v.try_into().ok())
.map(ConstScalar::Usize)
.unwrap_or(ConstScalar::Unknown),
)
}
_ => Self::Scalar(ConstScalar::Unknown),
}
}
_ => Self::Scalar(ConstScalar::Unknown),
}
}
}
/// A concrete constant value
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ConstScalar {
@ -389,25 +441,4 @@ impl ConstScalar {
_ => None,
}
}
// FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this
// parse stage.
fn usize_from_literal_expr(expr: ast::Expr) -> ConstScalar {
match expr {
ast::Expr::Literal(lit) => {
let lkind = lit.kind();
match lkind {
ast::LiteralKind::IntNumber(num)
if num.suffix() == None || num.suffix() == Some("usize") =>
{
num.value().and_then(|v| v.try_into().ok())
}
_ => None,
}
}
_ => None,
}
.map(ConstScalar::Usize)
.unwrap_or(ConstScalar::Unknown)
}
}

View File

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

View File

@ -8,67 +8,136 @@ use chalk_ir::{
interner::HasInterner,
AdtId, BoundVar, DebruijnIndex, Scalar,
};
use hir_def::{builtin_type::BuiltinType, GenericDefId, TraitId, TypeAliasId};
use hir_def::{
builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, GenericDefId, TraitId,
TypeAliasId,
};
use smallvec::SmallVec;
use crate::{
db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders,
CallableSig, GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt,
TyKind, ValueTyDefId,
consteval::unknown_const_as_generic, db::HirDatabase, primitive, to_assoc_type_id,
to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData, ConstValue, GenericArg,
GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
ValueTyDefId,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParamKind {
Type,
Const(Ty),
}
/// This is a builder for `Ty` or anything that needs a `Substitution`.
pub struct TyBuilder<D> {
/// The `data` field is used to keep track of what we're building (e.g. an
/// ADT, a `TraitRef`, ...).
data: D,
vec: SmallVec<[GenericArg; 2]>,
param_count: usize,
param_kinds: SmallVec<[ParamKind; 2]>,
}
impl<A> TyBuilder<A> {
fn with_data<B>(self, data: B) -> TyBuilder<B> {
TyBuilder { data, param_kinds: self.param_kinds, vec: self.vec }
}
}
impl<D> TyBuilder<D> {
fn new(data: D, param_count: usize) -> TyBuilder<D> {
TyBuilder { data, param_count, vec: SmallVec::with_capacity(param_count) }
fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder<D> {
TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds }
}
fn build_internal(self) -> (D, Substitution) {
assert_eq!(self.vec.len(), self.param_count);
assert_eq!(self.vec.len(), self.param_kinds.len());
for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
self.assert_match_kind(a, e);
}
let subst = Substitution::from_iter(Interner, self.vec);
(self.data, subst)
}
pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
self.vec.push(arg.cast(Interner));
let arg = arg.cast(Interner);
let expected_kind = &self.param_kinds[self.vec.len()];
let arg_kind = match arg.data(Interner) {
chalk_ir::GenericArgData::Ty(_) => ParamKind::Type,
chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
chalk_ir::GenericArgData::Const(c) => {
let c = c.data(Interner);
ParamKind::Const(c.ty.clone())
}
};
assert_eq!(*expected_kind, arg_kind);
self.vec.push(arg);
self
}
pub fn remaining(&self) -> usize {
self.param_count - self.vec.len()
self.param_kinds.len() - self.vec.len()
}
pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
self.fill(
(starting_from..)
.map(|idx| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner)),
)
// self.fill is inlined to make borrow checker happy
let mut this = self;
let other = this.param_kinds.iter().skip(this.vec.len());
let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
ParamKind::Type => {
GenericArgData::Ty(TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner))
.intern(Interner)
}
ParamKind::Const(ty) => GenericArgData::Const(
ConstData {
value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
ty: ty.clone(),
}
.intern(Interner),
)
.intern(Interner),
});
this.vec.extend(filler.take(this.remaining()).casted(Interner));
assert_eq!(this.remaining(), 0);
this
}
pub fn fill_with_unknown(self) -> Self {
self.fill(iter::repeat(TyKind::Error.intern(Interner)))
// self.fill is inlined to make borrow checker happy
let mut this = self;
let filler = this.param_kinds.iter().skip(this.vec.len()).map(|x| match x {
ParamKind::Type => GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner),
ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
});
this.vec.extend(filler.casted(Interner));
assert_eq!(this.remaining(), 0);
this
}
pub fn fill(mut self, filler: impl Iterator<Item = impl CastTo<GenericArg>>) -> Self {
self.vec.extend(filler.take(self.remaining()).casted(Interner));
pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler));
assert_eq!(self.remaining(), 0);
self
}
pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
assert!(self.vec.is_empty());
assert!(parent_substs.len(Interner) <= self.param_count);
self.vec.extend(parent_substs.iter(Interner).cloned());
assert!(parent_substs.len(Interner) <= self.param_kinds.len());
self.extend(parent_substs.iter(Interner).cloned());
self
}
fn extend(&mut self, it: impl Iterator<Item = GenericArg> + Clone) {
for x in it.clone().zip(self.param_kinds.iter().skip(self.vec.len())) {
self.assert_match_kind(&x.0, &x.1);
}
self.vec.extend(it);
}
fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
match (a.data(Interner), e) {
(chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
| (chalk_ir::GenericArgData::Const(_), ParamKind::Const(_)) => (),
_ => panic!("Mismatched kinds: {:?}, {:?}, {:?}", a, self.vec, self.param_kinds),
}
}
}
impl TyBuilder<()> {
@ -101,16 +170,26 @@ impl TyBuilder<()> {
TyKind::Slice(argument).intern(Interner)
}
pub fn type_params_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
pub fn placeholder_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
let params = generics(db.upcast(), def.into());
params.type_params_subst(db)
params.placeholder_subst(db)
}
pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> {
let def = def.into();
let params = generics(db.upcast(), def);
let param_count = params.len();
TyBuilder::new((), param_count)
TyBuilder::new(
(),
params
.iter()
.map(|(id, data)| match data {
TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
TypeOrConstParamData::ConstParamData(_) => {
ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
}
})
.collect(),
)
}
pub fn build(self) -> Substitution {
@ -120,10 +199,8 @@ impl TyBuilder<()> {
}
impl TyBuilder<hir_def::AdtId> {
pub fn adt(db: &dyn HirDatabase, adt: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
let generics = generics(db.upcast(), adt.into());
let param_count = generics.len();
TyBuilder::new(adt, param_count)
pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
TyBuilder::subst_for_def(db, def).with_data(def)
}
pub fn fill_with_defaults(
@ -133,14 +210,15 @@ impl TyBuilder<hir_def::AdtId> {
) -> Self {
let defaults = db.generic_defaults(self.data.into());
for default_ty in defaults.iter().skip(self.vec.len()) {
if default_ty.skip_binders().is_unknown() {
self.vec.push(fallback().cast(Interner));
} else {
// 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));
}
if let GenericArgData::Ty(x) = default_ty.skip_binders().data(Interner) {
if x.is_unknown() {
self.vec.push(fallback().cast(Interner));
continue;
}
};
// each default can depend on the previous parameters
let subst_so_far = Substitution::from_iter(Interner, self.vec.clone());
self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
}
self
}
@ -154,7 +232,7 @@ impl TyBuilder<hir_def::AdtId> {
pub struct Tuple(usize);
impl TyBuilder<Tuple> {
pub fn tuple(size: usize) -> TyBuilder<Tuple> {
TyBuilder::new(Tuple(size), size)
TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect())
}
pub fn build(self) -> Ty {
@ -164,10 +242,8 @@ impl TyBuilder<Tuple> {
}
impl TyBuilder<TraitId> {
pub fn trait_ref(db: &dyn HirDatabase, trait_id: TraitId) -> TyBuilder<TraitId> {
let generics = generics(db.upcast(), trait_id.into());
let param_count = generics.len();
TyBuilder::new(trait_id, param_count)
pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
TyBuilder::subst_for_def(db, def).with_data(def)
}
pub fn build(self) -> TraitRef {
@ -177,13 +253,8 @@ impl TyBuilder<TraitId> {
}
impl TyBuilder<TypeAliasId> {
pub fn assoc_type_projection(
db: &dyn HirDatabase,
type_alias: TypeAliasId,
) -> TyBuilder<TypeAliasId> {
let generics = generics(db.upcast(), type_alias.into());
let param_count = generics.len();
TyBuilder::new(type_alias, param_count)
pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder<TypeAliasId> {
TyBuilder::subst_for_def(db, def).with_data(def)
}
pub fn build(self) -> ProjectionTy {
@ -194,8 +265,16 @@ impl TyBuilder<TypeAliasId> {
impl<T: HasInterner<Interner = Interner> + Fold<Interner>> TyBuilder<Binders<T>> {
fn subst_binders(b: Binders<T>) -> Self {
let param_count = b.binders.len(Interner);
TyBuilder::new(b, param_count)
let param_kinds = b
.binders
.iter(Interner)
.map(|x| match x {
chalk_ir::VariableKind::Ty(_) => ParamKind::Type,
chalk_ir::VariableKind::Lifetime => panic!("Got lifetime parameter"),
chalk_ir::VariableKind::Const(ty) => ParamKind::Const(ty.clone()),
})
.collect();
TyBuilder::new(b, param_kinds)
}
pub fn build(self) -> <T as Fold<Interner>>::Result {

View File

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

View File

@ -237,11 +237,11 @@ impl TyExt for Ty {
TyKind::Placeholder(idx) => {
let id = from_placeholder_idx(db, *idx);
let generic_params = db.generic_params(id.parent);
let param_data = &generic_params.tocs[id.local_id];
let param_data = &generic_params.type_or_consts[id.local_id];
match param_data {
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
let substs = TyBuilder::type_params_subst(db, id.parent);
let substs = TyBuilder::placeholder_subst(db, id.parent);
let predicates = db
.generic_predicates(id.parent)
.iter()

View File

@ -2,15 +2,25 @@
use std::{collections::HashMap, convert::TryInto, fmt::Display};
use chalk_ir::{IntTy, Scalar};
use chalk_ir::{BoundVar, DebruijnIndex, GenericArgData, IntTy, Scalar};
use hir_def::{
expr::{ArithOp, BinaryOp, Expr, Literal, Pat},
path::ModPath,
resolver::{Resolver, ValueNs},
type_ref::ConstScalar,
};
use hir_expand::name::Name;
use la_arena::{Arena, Idx};
use stdx::never;
use crate::{Const, ConstData, ConstValue, Interner, Ty, TyKind};
use crate::{
db::HirDatabase,
infer::{Expectation, InferenceContext},
lower::ParamLoweringMode,
to_placeholder_idx,
utils::Generics,
Const, ConstData, ConstValue, GenericArg, Interner, Ty, TyKind,
};
/// Extension trait for [`Const`]
pub trait ConstExt {
@ -303,6 +313,57 @@ pub fn eval_usize(expr: Idx<Expr>, mut ctx: ConstEvalCtx<'_>) -> Option<u64> {
None
}
pub(crate) fn path_to_const(
db: &dyn HirDatabase,
resolver: &Resolver,
path: &ModPath,
mode: ParamLoweringMode,
args_lazy: impl FnOnce() -> Generics,
debruijn: DebruijnIndex,
) -> Option<Const> {
match resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
Some(ValueNs::GenericParam(p)) => {
let ty = db.const_param_ty(p);
let args = args_lazy();
let value = match mode {
ParamLoweringMode::Placeholder => {
ConstValue::Placeholder(to_placeholder_idx(db, p.into()))
}
ParamLoweringMode::Variable => match args.param_idx(p.into()) {
Some(x) => ConstValue::BoundVar(BoundVar::new(debruijn, x)),
None => {
never!(
"Generic list doesn't contain this param: {:?}, {}, {:?}",
args,
path,
p
);
return None;
}
},
};
Some(ConstData { ty, value }.intern(Interner))
}
_ => None,
}
}
pub fn unknown_const(ty: Ty) -> Const {
ConstData {
ty,
value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: ConstScalar::Unknown }),
}
.intern(Interner)
}
pub fn unknown_const_usize() -> Const {
unknown_const(TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner))
}
pub fn unknown_const_as_generic(ty: Ty) -> GenericArg {
GenericArgData::Const(unknown_const(ty)).intern(Interner)
}
/// Interns a possibly-unknown target usize
pub fn usize_const(value: Option<u64>) -> Const {
ConstData {
@ -313,3 +374,27 @@ pub fn usize_const(value: Option<u64>) -> Const {
}
.intern(Interner)
}
pub(crate) fn eval_to_const(
expr: Idx<Expr>,
mode: ParamLoweringMode,
ctx: &mut InferenceContext,
args: impl FnOnce() -> Generics,
debruijn: DebruijnIndex,
) -> Const {
if let Expr::Path(p) = &ctx.body.exprs[expr] {
let db = ctx.db;
let resolver = &ctx.resolver;
if let Some(c) = path_to_const(db, resolver, p.mod_path(), mode, args, debruijn) {
return c;
}
}
let body = ctx.body.clone();
let ctx = ConstEvalCtx {
exprs: &body.exprs,
pats: &body.pats,
local_data: HashMap::default(),
infer: &mut |x| ctx.infer_expr(x, &Expectation::None),
};
usize_const(eval_usize(expr, ctx))
}

View File

@ -13,7 +13,7 @@ use la_arena::ArenaMap;
use crate::{
chalk_db,
method_resolution::{InherentImpls, TraitImpls},
Binders, CallableDefId, FnDefId, ImplTraitId, InferenceResult, Interner, PolyFnSig,
Binders, CallableDefId, FnDefId, GenericArg, ImplTraitId, InferenceResult, Interner, PolyFnSig,
QuantifiedWhereClause, ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId,
};
use hir_expand::name::Name;
@ -73,7 +73,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
#[salsa::invoke(crate::lower::generic_defaults_query)]
#[salsa::cycle(crate::lower::generic_defaults_recover)]
fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>;
fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<GenericArg>]>;
#[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;

View File

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

View File

@ -16,7 +16,7 @@
use std::ops::Index;
use std::sync::Arc;
use chalk_ir::{cast::Cast, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
use hir_def::{
body::Body,
data::{ConstData, FunctionData, StaticData},
@ -29,14 +29,16 @@ use hir_def::{
TraitId, TypeAliasId, VariantId,
};
use hir_expand::name::{name, Name};
use itertools::Either;
use la_arena::ArenaMap;
use rustc_hash::FxHashMap;
use stdx::impl_from;
use crate::{
db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode,
to_assoc_type_id, AliasEq, AliasTy, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy,
Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
builder::ParamKind, db::HirDatabase, fold_tys_and_consts, infer::coerce::CoerceMany,
lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal,
GenericArg, GenericArgData, Goal, InEnvironment, Interner, ProjectionTy, Substitution,
TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
};
// This lint has a false positive here. See the link below for details.
@ -354,11 +356,11 @@ impl Index<PatId> for InferenceResult {
/// The inference context contains all information needed during type inference.
#[derive(Clone, Debug)]
struct InferenceContext<'a> {
db: &'a dyn HirDatabase,
pub(crate) struct InferenceContext<'a> {
pub(crate) db: &'a dyn HirDatabase,
owner: DefWithBodyId,
body: Arc<Body>,
resolver: Resolver,
pub(crate) body: Arc<Body>,
pub(crate) resolver: Resolver,
table: unify::InferenceTable<'a>,
trait_env: Arc<TraitEnvironment>,
result: InferenceResult,
@ -488,6 +490,20 @@ impl<'a> InferenceContext<'a> {
self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed)
}
/// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it.
fn insert_const_vars_shallow(&mut self, c: Const) -> Const {
let data = c.data(Interner);
match data.value {
ConstValue::Concrete(cc) => match cc.interned {
hir_def::type_ref::ConstScalar::Usize(_) => c,
hir_def::type_ref::ConstScalar::Unknown => {
self.table.new_const_var(data.ty.clone())
}
},
_ => c,
}
}
/// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
match ty.kind(Interner) {
@ -505,7 +521,14 @@ impl<'a> InferenceContext<'a> {
}
fn insert_type_vars(&mut self, ty: Ty) -> Ty {
fold_tys(ty, |ty, _| self.insert_type_vars_shallow(ty), DebruijnIndex::INNERMOST)
fold_tys_and_consts(
ty,
|x, _| match x {
Either::Left(ty) => Either::Left(self.insert_type_vars_shallow(ty)),
Either::Right(c) => Either::Right(self.insert_const_vars_shallow(c)),
},
DebruijnIndex::INNERMOST,
)
}
fn resolve_obligations_as_possible(&mut self) {
@ -533,7 +556,7 @@ impl<'a> InferenceContext<'a> {
&mut self,
inner_ty: Ty,
assoc_ty: Option<TypeAliasId>,
params: &[Ty],
params: &[GenericArg],
) -> Ty {
match assoc_ty {
Some(res_assoc_ty) => {
@ -542,9 +565,10 @@ impl<'a> InferenceContext<'a> {
_ => panic!("resolve_associated_type called with non-associated type"),
};
let ty = self.table.new_type_var();
let mut param_iter = params.iter().cloned();
let trait_ref = TyBuilder::trait_ref(self.db, trait_)
.push(inner_ty)
.fill(params.iter().cloned())
.fill(|_| param_iter.next().unwrap())
.build();
let alias_eq = AliasEq {
alias: AliasTy::Projection(ProjectionTy {
@ -627,13 +651,21 @@ impl<'a> InferenceContext<'a> {
}
TypeNs::SelfType(impl_id) => {
let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
let substs = generics.type_params_subst(self.db);
let substs = generics.placeholder_subst(self.db);
let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
self.resolve_variant_on_alias(ty, unresolved, path)
}
TypeNs::TypeAliasId(it) => {
let ty = TyBuilder::def_ty(self.db, it.into())
.fill(std::iter::repeat_with(|| self.table.new_type_var()))
.fill(|x| match x {
ParamKind::Type => {
GenericArgData::Ty(self.table.new_type_var()).intern(Interner)
}
ParamKind::Const(ty) => {
GenericArgData::Const(self.table.new_const_var(ty.clone()))
.intern(Interner)
}
})
.build();
self.resolve_variant_on_alias(ty, unresolved, path)
}
@ -827,7 +859,7 @@ impl<'a> InferenceContext<'a> {
/// When inferring an expression, we propagate downward whatever type hint we
/// are able in the form of an `Expectation`.
#[derive(Clone, PartialEq, Eq, Debug)]
enum Expectation {
pub(crate) enum Expectation {
None,
HasType(Ty),
// Castable(Ty), // rustc has this, we currently just don't propagate an expectation for casts

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1359,7 +1359,69 @@ impl<T> [T] {
fn f() {
let v = [1, 2].map::<_, usize>(|x| -> x * 2);
v;
//^ [usize; _]
//^ [usize; 2]
}
"#,
);
}
#[test]
fn resolve_const_generic_method() {
check_types(
r#"
struct Const<const N: usize>;
#[lang = "array"]
impl<T, const N: usize> [T; N] {
pub fn my_map<F, U, const X: usize>(self, f: F, c: Const<X>) -> [U; X]
where
F: FnMut(T) -> U,
{ loop {} }
}
#[lang = "slice"]
impl<T> [T] {
pub fn my_map<F, const X: usize, U>(self, f: F, c: Const<X>) -> &[U]
where
F: FnMut(T) -> U,
{ loop {} }
}
fn f<const C: usize, P>() {
let v = [1, 2].my_map::<_, (), 12>(|x| -> x * 2, Const::<12>);
v;
//^ [(); 12]
let v = [1, 2].my_map::<_, P, C>(|x| -> x * 2, Const::<C>);
v;
//^ [P; C]
}
"#,
);
}
#[test]
fn const_generic_type_alias() {
check_types(
r#"
struct Const<const N: usize>;
type U2 = Const<2>;
type U5 = Const<5>;
impl U2 {
fn f(self) -> Const<12> {
loop {}
}
}
impl U5 {
fn f(self) -> Const<15> {
loop {}
}
}
fn f(x: U2) {
let y = x.f();
//^ Const<12>
}
"#,
);

View File

@ -1301,7 +1301,7 @@ impl<I: Iterator> IntoIterator for I {
#[test]
fn bug_11659() {
check_infer(
check_no_mismatches(
r#"
struct LinkArray<const N: usize, LD>(LD);
fn f<const N: usize, LD>(x: LD) -> LinkArray<N, LD> {
@ -1314,26 +1314,8 @@ fn test() {
let y = LinkArray::<52, LinkArray<2, i32>>(x);
}
"#,
expect![[r#"
67..68 'x': LD
94..138 '{ ... r }': LinkArray<{unknown}, LD>
104..105 'r': LinkArray<{unknown}, LD>
108..126 'LinkAr...N, LD>': LinkArray<{unknown}, LD>(LD) -> LinkArray<{unknown}, LD>
108..129 'LinkAr...LD>(x)': LinkArray<{unknown}, LD>
127..128 'x': LD
135..136 'r': LinkArray<{unknown}, LD>
150..232 '{ ...(x); }': ()
160..161 'x': LinkArray<{unknown}, {unknown}>
164..175 'f::<2, i32>': fn f<i32, i32>(i32) -> LinkArray<{unknown}, {unknown}>
164..178 'f::<2, i32>(5)': LinkArray<{unknown}, {unknown}>
176..177 '5': i32
188..189 'y': LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>
192..226 'LinkAr... i32>>': LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>(LinkArray<{unknown}, {unknown}>) -> LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>
192..229 'LinkAr...2>>(x)': LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>
227..228 'x': LinkArray<{unknown}, {unknown}>
"#]],
);
check_infer(
check_no_mismatches(
r#"
struct LinkArray<LD, const N: usize>(LD);
fn f<const N: usize, LD>(x: LD) -> LinkArray<LD, N> {
@ -1346,23 +1328,106 @@ fn test() {
let y = LinkArray::<LinkArray<i32, 2>, 52>(x);
}
"#,
expect![[r#"
67..68 'x': LD
94..138 '{ ... r }': LinkArray<LD, {unknown}>
104..105 'r': LinkArray<LD, {unknown}>
108..126 'LinkAr...LD, N>': LinkArray<LD, {unknown}>(LD) -> LinkArray<LD, {unknown}>
108..129 'LinkAr... N>(x)': LinkArray<LD, {unknown}>
127..128 'x': LD
135..136 'r': LinkArray<LD, {unknown}>
150..232 '{ ...(x); }': ()
160..161 'x': LinkArray<i32, {unknown}>
164..175 'f::<i32, 2>': fn f<i32, i32>(i32) -> LinkArray<i32, {unknown}>
164..178 'f::<i32, 2>(5)': LinkArray<i32, {unknown}>
176..177 '5': i32
188..189 'y': LinkArray<LinkArray<i32, {unknown}>, {unknown}>
192..226 'LinkAr...>, 52>': LinkArray<LinkArray<i32, {unknown}>, {unknown}>(LinkArray<i32, {unknown}>) -> LinkArray<LinkArray<i32, {unknown}>, {unknown}>
192..229 'LinkAr...52>(x)': LinkArray<LinkArray<i32, {unknown}>, {unknown}>
227..228 'x': LinkArray<i32, {unknown}>
"#]],
);
}
#[test]
fn const_generic_error_tolerance() {
check_no_mismatches(
r#"
#[lang = "sized"]
pub trait Sized {}
struct CT<const N: usize, T>(T);
struct TC<T, const N: usize>(T);
fn f<const N: usize, T>(x: T) -> (CT<N, T>, TC<T, N>) {
let l = CT::<N, T>(x);
let r = TC::<N, T>(x);
(l, r)
}
trait TR1<const N: usize>;
trait TR2<const N: usize>;
impl<const N: usize, T> TR1<N> for CT<N, T>;
impl<const N: usize, T> TR1<5> for TC<T, N>;
impl<const N: usize, T> TR2<N> for CT<T, N>;
trait TR3<const N: usize> {
fn tr3(&self) -> &Self;
}
impl<const N: usize, T> TR3<5> for TC<T, N> {
fn tr3(&self) -> &Self {
self
}
}
impl<const N: usize, T> TR3<Item = 5> for TC<T, N> {}
impl<const N: usize, T> TR3<T> for TC<T, N> {}
fn impl_trait<const N: usize>(inp: impl TR1<N>) {}
fn dyn_trait<const N: usize>(inp: &dyn TR2<N>) {}
fn impl_trait_bad<'a, const N: usize>(inp: impl TR1<i32>) -> impl TR1<'a, i32> {}
fn impl_trait_very_bad<const N: usize>(inp: impl TR1<Item = i32>) -> impl TR1<'a, Item = i32, 5, Foo = N> {}
fn test() {
f::<2, i32>(5);
f::<2, 2>(5);
f(5);
f::<i32>(5);
CT::<52, CT<2, i32>>(x);
CT::<CT<2, i32>>(x);
impl_trait_bad(5);
impl_trait_bad(12);
TR3<5>::tr3();
TR3<{ 2+3 }>::tr3();
TC::<i32, 10>(5).tr3();
TC::<i32, 20>(5).tr3();
TC::<i32, i32>(5).tr3();
TC::<i32, { 7 + 3 }>(5).tr3();
}
"#,
);
}
#[test]
fn const_generic_impl_trait() {
check_no_mismatches(
r#"
//- minicore: from
struct Foo<T, const M: usize>;
trait Tr<T> {
fn f(T) -> Self;
}
impl<T, const M: usize> Tr<[T; M]> for Foo<T, M> {
fn f(_: [T; M]) -> Self {
Self
}
}
fn test() {
Foo::f([1, 2, 7, 10]);
}
"#,
);
}
#[test]
fn nalgebra_factorial() {
check_no_mismatches(
r#"
const FACTORIAL: [u128; 4] = [1, 1, 2, 6];
fn factorial(n: usize) -> u128 {
match FACTORIAL.get(n) {
Some(f) => *f,
None => panic!("{}! is greater than u128::MAX", n),
}
}
"#,
)
}

View File

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

View File

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

View File

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

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]
fn hover_const_param() {
check(