mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Implement Chalk variable kinds
This means we need to keep track of the kinds (general/int/float) of variables in `Canonical`, which requires some more ceremony. (It also exposes some places where we're not really dealing with canonicalization correctly -- another thing to be cleaned up when we switch to using Chalk's types directly.) Should fix the last remaining issue of #2534.
This commit is contained in:
parent
4a19d5954a
commit
d5d485ef92
8 changed files with 140 additions and 71 deletions
|
@ -1187,7 +1187,7 @@ impl Type {
|
||||||
None => return false,
|
None => return false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let canonical_ty = Canonical { value: self.ty.value.clone(), num_vars: 0 };
|
let canonical_ty = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
|
||||||
method_resolution::implements_trait(
|
method_resolution::implements_trait(
|
||||||
&canonical_ty,
|
&canonical_ty,
|
||||||
db,
|
db,
|
||||||
|
@ -1211,7 +1211,7 @@ impl Type {
|
||||||
self.ty.environment.clone(),
|
self.ty.environment.clone(),
|
||||||
hir_ty::Obligation::Trait(trait_ref),
|
hir_ty::Obligation::Trait(trait_ref),
|
||||||
),
|
),
|
||||||
num_vars: 0,
|
kinds: Arc::new([]),
|
||||||
};
|
};
|
||||||
|
|
||||||
db.trait_solve(self.krate, goal).is_some()
|
db.trait_solve(self.krate, goal).is_some()
|
||||||
|
@ -1286,7 +1286,7 @@ impl Type {
|
||||||
pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
|
pub fn autoderef<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Type> + 'a {
|
||||||
// There should be no inference vars in types passed here
|
// There should be no inference vars in types passed here
|
||||||
// FIXME check that?
|
// FIXME check that?
|
||||||
let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 };
|
let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
|
||||||
let environment = self.ty.environment.clone();
|
let environment = self.ty.environment.clone();
|
||||||
let ty = InEnvironment { value: canonical, environment };
|
let ty = InEnvironment { value: canonical, environment };
|
||||||
autoderef(db, Some(self.krate), ty)
|
autoderef(db, Some(self.krate), ty)
|
||||||
|
@ -1327,7 +1327,7 @@ impl Type {
|
||||||
// There should be no inference vars in types passed here
|
// There should be no inference vars in types passed here
|
||||||
// FIXME check that?
|
// FIXME check that?
|
||||||
// FIXME replace Unknown by bound vars here
|
// FIXME replace Unknown by bound vars here
|
||||||
let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 };
|
let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
|
||||||
|
|
||||||
let env = self.ty.environment.clone();
|
let env = self.ty.environment.clone();
|
||||||
let krate = krate.id;
|
let krate = krate.id;
|
||||||
|
@ -1358,7 +1358,7 @@ impl Type {
|
||||||
// There should be no inference vars in types passed here
|
// There should be no inference vars in types passed here
|
||||||
// FIXME check that?
|
// FIXME check that?
|
||||||
// FIXME replace Unknown by bound vars here
|
// FIXME replace Unknown by bound vars here
|
||||||
let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 };
|
let canonical = Canonical { value: self.ty.value.clone(), kinds: Arc::new([]) };
|
||||||
|
|
||||||
let env = self.ty.environment.clone();
|
let env = self.ty.environment.clone();
|
||||||
let krate = krate.id;
|
let krate = krate.id;
|
||||||
|
|
|
@ -37,7 +37,7 @@ pub(crate) fn deref(
|
||||||
ty: InEnvironment<&Canonical<Ty>>,
|
ty: InEnvironment<&Canonical<Ty>>,
|
||||||
) -> Option<Canonical<Ty>> {
|
) -> Option<Canonical<Ty>> {
|
||||||
if let Some(derefed) = ty.value.value.builtin_deref() {
|
if let Some(derefed) = ty.value.value.builtin_deref() {
|
||||||
Some(Canonical { value: derefed, num_vars: ty.value.num_vars })
|
Some(Canonical { value: derefed, kinds: ty.value.kinds.clone() })
|
||||||
} else {
|
} else {
|
||||||
deref_by_trait(db, krate, ty)
|
deref_by_trait(db, krate, ty)
|
||||||
}
|
}
|
||||||
|
@ -68,8 +68,8 @@ fn deref_by_trait(
|
||||||
|
|
||||||
// Check that the type implements Deref at all
|
// Check that the type implements Deref at all
|
||||||
let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() };
|
let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() };
|
||||||
let implements_goal = super::Canonical {
|
let implements_goal = Canonical {
|
||||||
num_vars: ty.value.num_vars,
|
kinds: ty.value.kinds.clone(),
|
||||||
value: InEnvironment {
|
value: InEnvironment {
|
||||||
value: Obligation::Trait(trait_ref),
|
value: Obligation::Trait(trait_ref),
|
||||||
environment: ty.environment.clone(),
|
environment: ty.environment.clone(),
|
||||||
|
@ -81,7 +81,7 @@ fn deref_by_trait(
|
||||||
|
|
||||||
// Now do the assoc type projection
|
// Now do the assoc type projection
|
||||||
let projection = super::traits::ProjectionPredicate {
|
let projection = super::traits::ProjectionPredicate {
|
||||||
ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.num_vars)),
|
ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.kinds.len())),
|
||||||
projection_ty: super::ProjectionTy { associated_ty: target, parameters },
|
projection_ty: super::ProjectionTy { associated_ty: target, parameters },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -89,7 +89,8 @@ fn deref_by_trait(
|
||||||
|
|
||||||
let in_env = InEnvironment { value: obligation, environment: ty.environment };
|
let in_env = InEnvironment { value: obligation, environment: ty.environment };
|
||||||
|
|
||||||
let canonical = super::Canonical { num_vars: 1 + ty.value.num_vars, value: in_env };
|
let canonical =
|
||||||
|
Canonical::new(in_env, ty.value.kinds.iter().copied().chain(Some(super::TyKind::General)));
|
||||||
|
|
||||||
let solution = db.trait_solve(krate, canonical)?;
|
let solution = db.trait_solve(krate, canonical)?;
|
||||||
|
|
||||||
|
@ -110,7 +111,7 @@ fn deref_by_trait(
|
||||||
// assumptions will be broken. We would need to properly introduce
|
// assumptions will be broken. We would need to properly introduce
|
||||||
// new variables in that case
|
// new variables in that case
|
||||||
|
|
||||||
for i in 1..vars.0.num_vars {
|
for i in 1..vars.0.kinds.len() {
|
||||||
if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
|
if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
|
||||||
{
|
{
|
||||||
warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution);
|
warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.value, solution);
|
||||||
|
@ -119,7 +120,7 @@ fn deref_by_trait(
|
||||||
}
|
}
|
||||||
Some(Canonical {
|
Some(Canonical {
|
||||||
value: vars.0.value[vars.0.value.len() - 1].clone(),
|
value: vars.0.value[vars.0.value.len() - 1].clone(),
|
||||||
num_vars: vars.0.num_vars,
|
kinds: vars.0.kinds.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Solution::Ambig(_) => {
|
Solution::Ambig(_) => {
|
||||||
|
|
|
@ -9,7 +9,7 @@ use test_utils::mark;
|
||||||
use super::{InferenceContext, Obligation};
|
use super::{InferenceContext, Obligation};
|
||||||
use crate::{
|
use crate::{
|
||||||
BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty,
|
BoundVar, Canonical, DebruijnIndex, GenericPredicate, InEnvironment, InferTy, Substs, Ty,
|
||||||
TypeCtor, TypeWalk,
|
TyKind, TypeCtor, TypeWalk,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'a> InferenceContext<'a> {
|
impl<'a> InferenceContext<'a> {
|
||||||
|
@ -86,10 +86,20 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
|
fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
|
||||||
Canonicalized {
|
let kinds = self
|
||||||
value: Canonical { value: result, num_vars: self.free_vars.len() },
|
.free_vars
|
||||||
free_vars: self.free_vars,
|
.iter()
|
||||||
}
|
.map(|v| match v {
|
||||||
|
// mapping MaybeNeverTypeVar to the same kind as general ones
|
||||||
|
// should be fine, because as opposed to int or float type vars,
|
||||||
|
// they don't restrict what kind of type can go into them, they
|
||||||
|
// just affect fallback.
|
||||||
|
InferTy::TypeVar(_) | InferTy::MaybeNeverTypeVar(_) => TyKind::General,
|
||||||
|
InferTy::IntVar(_) => TyKind::Integer,
|
||||||
|
InferTy::FloatVar(_) => TyKind::Float,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Canonicalized { value: Canonical { value: result, kinds }, free_vars: self.free_vars }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
|
pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
|
||||||
|
@ -131,26 +141,41 @@ impl<T> Canonicalized<T> {
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Vec<Ty>>) {
|
pub fn apply_solution(&self, ctx: &mut InferenceContext<'_>, solution: Canonical<Substs>) {
|
||||||
// the solution may contain new variables, which we need to convert to new inference vars
|
// the solution may contain new variables, which we need to convert to new inference vars
|
||||||
let new_vars = Substs((0..solution.num_vars).map(|_| ctx.table.new_type_var()).collect());
|
let new_vars = Substs(
|
||||||
|
solution
|
||||||
|
.kinds
|
||||||
|
.iter()
|
||||||
|
.map(|k| match k {
|
||||||
|
TyKind::General => ctx.table.new_type_var(),
|
||||||
|
TyKind::Integer => ctx.table.new_integer_var(),
|
||||||
|
TyKind::Float => ctx.table.new_float_var(),
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
for (i, ty) in solution.value.into_iter().enumerate() {
|
for (i, ty) in solution.value.into_iter().enumerate() {
|
||||||
let var = self.free_vars[i];
|
let var = self.free_vars[i];
|
||||||
// eagerly replace projections in the type; we may be getting types
|
// eagerly replace projections in the type; we may be getting types
|
||||||
// e.g. from where clauses where this hasn't happened yet
|
// e.g. from where clauses where this hasn't happened yet
|
||||||
let ty = ctx.normalize_associated_types_in(ty.subst_bound_vars(&new_vars));
|
let ty = ctx.normalize_associated_types_in(ty.clone().subst_bound_vars(&new_vars));
|
||||||
ctx.table.unify(&Ty::Infer(var), &ty);
|
ctx.table.unify(&Ty::Infer(var), &ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> {
|
pub fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substs> {
|
||||||
let mut table = InferenceTable::new();
|
let mut table = InferenceTable::new();
|
||||||
let num_vars = ty1.num_vars.max(ty2.num_vars);
|
let vars = Substs(
|
||||||
let vars =
|
tys.kinds
|
||||||
Substs::builder(num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build();
|
.iter()
|
||||||
let ty1_with_vars = ty1.value.clone().subst_bound_vars(&vars);
|
// we always use type vars here because we want everything to
|
||||||
let ty2_with_vars = ty2.value.clone().subst_bound_vars(&vars);
|
// fallback to Unknown in the end (kind of hacky, as below)
|
||||||
|
.map(|_| table.new_type_var())
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
let ty1_with_vars = tys.value.0.clone().subst_bound_vars(&vars);
|
||||||
|
let ty2_with_vars = tys.value.1.clone().subst_bound_vars(&vars);
|
||||||
if !table.unify(&ty1_with_vars, &ty2_with_vars) {
|
if !table.unify(&ty1_with_vars, &ty2_with_vars) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -162,7 +187,7 @@ pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(
|
Some(
|
||||||
Substs::builder(ty1.num_vars)
|
Substs::builder(tys.kinds.len())
|
||||||
.fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone())))
|
.fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone())))
|
||||||
.build(),
|
.build(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -662,13 +662,27 @@ impl TypeWalk for GenericPredicate {
|
||||||
|
|
||||||
/// Basically a claim (currently not validated / checked) that the contained
|
/// Basically a claim (currently not validated / checked) that the contained
|
||||||
/// type / trait ref contains no inference variables; any inference variables it
|
/// type / trait ref contains no inference variables; any inference variables it
|
||||||
/// contained have been replaced by bound variables, and `num_vars` tells us how
|
/// contained have been replaced by bound variables, and `kinds` tells us how
|
||||||
/// many there are. This is used to erase irrelevant differences between types
|
/// many there are and whether they were normal or float/int variables. This is
|
||||||
/// before using them in queries.
|
/// used to erase irrelevant differences between types before using them in
|
||||||
|
/// queries.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Canonical<T> {
|
pub struct Canonical<T> {
|
||||||
pub value: T,
|
pub value: T,
|
||||||
pub num_vars: usize,
|
pub kinds: Arc<[TyKind]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Canonical<T> {
|
||||||
|
pub fn new(value: T, kinds: impl IntoIterator<Item = TyKind>) -> Self {
|
||||||
|
Self { value, kinds: kinds.into_iter().collect() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum TyKind {
|
||||||
|
General,
|
||||||
|
Integer,
|
||||||
|
Float,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A function signature as seen by type inference: Several parameter types and
|
/// A function signature as seen by type inference: Several parameter types and
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//! For details about how this works in rustc, see the method lookup page in the
|
//! For details about how this works in rustc, see the method lookup page in the
|
||||||
//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
|
//! [rustc guide](https://rust-lang.github.io/rustc-guide/method-lookup.html)
|
||||||
//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
|
//! and the corresponding code mostly in librustc_typeck/check/method/probe.rs.
|
||||||
use std::sync::Arc;
|
use std::{iter, sync::Arc};
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
|
@ -17,7 +17,8 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use super::Substs;
|
use super::Substs;
|
||||||
use crate::{
|
use crate::{
|
||||||
autoderef, db::HirDatabase, primitive::FloatBitness, utils::all_super_traits, ApplicationTy,
|
autoderef, db::HirDatabase, primitive::FloatBitness, utils::all_super_traits, ApplicationTy,
|
||||||
Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
|
Canonical, DebruijnIndex, InEnvironment, TraitEnvironment, TraitRef, Ty, TyKind, TypeCtor,
|
||||||
|
TypeWalk,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This is used as a key for indexing impls.
|
/// This is used as a key for indexing impls.
|
||||||
|
@ -377,7 +378,7 @@ fn iterate_method_candidates_with_autoref(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
let refed = Canonical {
|
let refed = Canonical {
|
||||||
num_vars: deref_chain[0].num_vars,
|
kinds: deref_chain[0].kinds.clone(),
|
||||||
value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()),
|
value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()),
|
||||||
};
|
};
|
||||||
if iterate_method_candidates_by_receiver(
|
if iterate_method_candidates_by_receiver(
|
||||||
|
@ -393,7 +394,7 @@ fn iterate_method_candidates_with_autoref(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
let ref_muted = Canonical {
|
let ref_muted = Canonical {
|
||||||
num_vars: deref_chain[0].num_vars,
|
kinds: deref_chain[0].kinds.clone(),
|
||||||
value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()),
|
value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()),
|
||||||
};
|
};
|
||||||
if iterate_method_candidates_by_receiver(
|
if iterate_method_candidates_by_receiver(
|
||||||
|
@ -612,18 +613,19 @@ pub(crate) fn inherent_impl_substs(
|
||||||
// we create a var for each type parameter of the impl; we need to keep in
|
// we create a var for each type parameter of the impl; we need to keep in
|
||||||
// mind here that `self_ty` might have vars of its own
|
// mind here that `self_ty` might have vars of its own
|
||||||
let vars = Substs::build_for_def(db, impl_id)
|
let vars = Substs::build_for_def(db, impl_id)
|
||||||
.fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.num_vars)
|
.fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.kinds.len())
|
||||||
.build();
|
.build();
|
||||||
let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
|
let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
|
||||||
let self_ty_with_vars =
|
let mut kinds = self_ty.kinds.to_vec();
|
||||||
Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars };
|
kinds.extend(iter::repeat(TyKind::General).take(vars.len()));
|
||||||
let substs = super::infer::unify(&self_ty_with_vars, self_ty);
|
let tys = Canonical { kinds: kinds.into(), value: (self_ty_with_vars, self_ty.value.clone()) };
|
||||||
|
let substs = super::infer::unify(&tys);
|
||||||
// We only want the substs for the vars we added, not the ones from self_ty.
|
// We only want the substs for the vars we added, not the ones from self_ty.
|
||||||
// Also, if any of the vars we added are still in there, we replace them by
|
// Also, if any of the vars we added are still in there, we replace them by
|
||||||
// Unknown. I think this can only really happen if self_ty contained
|
// Unknown. I think this can only really happen if self_ty contained
|
||||||
// Unknown, and in that case we want the result to contain Unknown in those
|
// Unknown, and in that case we want the result to contain Unknown in those
|
||||||
// places again.
|
// places again.
|
||||||
substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.num_vars))
|
substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.kinds.len()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
|
/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
|
||||||
|
@ -683,15 +685,15 @@ fn generic_implements_goal(
|
||||||
trait_: TraitId,
|
trait_: TraitId,
|
||||||
self_ty: Canonical<Ty>,
|
self_ty: Canonical<Ty>,
|
||||||
) -> Canonical<InEnvironment<super::Obligation>> {
|
) -> Canonical<InEnvironment<super::Obligation>> {
|
||||||
let num_vars = self_ty.num_vars;
|
let mut kinds = self_ty.kinds.to_vec();
|
||||||
let substs = super::Substs::build_for_def(db, trait_)
|
let substs = super::Substs::build_for_def(db, trait_)
|
||||||
.push(self_ty.value)
|
.push(self_ty.value)
|
||||||
.fill_with_bound_vars(DebruijnIndex::INNERMOST, num_vars)
|
.fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
|
||||||
.build();
|
.build();
|
||||||
let num_vars = substs.len() - 1 + self_ty.num_vars;
|
kinds.extend(iter::repeat(TyKind::General).take(substs.len() - 1));
|
||||||
let trait_ref = TraitRef { trait_, substs };
|
let trait_ref = TraitRef { trait_, substs };
|
||||||
let obligation = super::Obligation::Trait(trait_ref);
|
let obligation = super::Obligation::Trait(trait_ref);
|
||||||
Canonical { num_vars, value: InEnvironment::new(env, obligation) }
|
Canonical { kinds: kinds.into(), value: InEnvironment::new(env, obligation) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn autoderef_method_receiver(
|
fn autoderef_method_receiver(
|
||||||
|
@ -704,9 +706,9 @@ fn autoderef_method_receiver(
|
||||||
if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) =
|
if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) =
|
||||||
deref_chain.last().map(|ty| &ty.value)
|
deref_chain.last().map(|ty| &ty.value)
|
||||||
{
|
{
|
||||||
let num_vars = deref_chain.last().unwrap().num_vars;
|
let kinds = deref_chain.last().unwrap().kinds.clone();
|
||||||
let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone());
|
let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone());
|
||||||
deref_chain.push(Canonical { value: unsized_ty, num_vars })
|
deref_chain.push(Canonical { value: unsized_ty, kinds })
|
||||||
}
|
}
|
||||||
deref_chain
|
deref_chain
|
||||||
}
|
}
|
||||||
|
|
|
@ -3029,3 +3029,21 @@ fn infer_dyn_fn_output() {
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn variable_kinds() {
|
||||||
|
check_types(
|
||||||
|
r#"
|
||||||
|
trait Trait<T> { fn get(self, t: T) -> T; }
|
||||||
|
struct S;
|
||||||
|
impl Trait<u128> for S {}
|
||||||
|
impl Trait<f32> for S {}
|
||||||
|
fn test() {
|
||||||
|
S.get(1);
|
||||||
|
//^^^^^^^^ u128
|
||||||
|
S.get(1.);
|
||||||
|
//^^^^^^^^ f32
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//! Trait solving using Chalk.
|
//! Trait solving using Chalk.
|
||||||
use std::{panic, sync::Arc};
|
use std::sync::Arc;
|
||||||
|
|
||||||
use chalk_ir::cast::Cast;
|
use chalk_ir::cast::Cast;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
|
@ -8,7 +8,7 @@ use hir_def::{
|
||||||
use ra_db::{impl_intern_key, salsa, CrateId};
|
use ra_db::{impl_intern_key, salsa, CrateId};
|
||||||
use ra_prof::profile;
|
use ra_prof::profile;
|
||||||
|
|
||||||
use crate::{db::HirDatabase, DebruijnIndex};
|
use crate::{db::HirDatabase, DebruijnIndex, Substs};
|
||||||
|
|
||||||
use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
|
use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
|
||||||
|
|
||||||
|
@ -190,15 +190,7 @@ fn solution_from_chalk(
|
||||||
solution: chalk_solve::Solution<Interner>,
|
solution: chalk_solve::Solution<Interner>,
|
||||||
) -> Solution {
|
) -> Solution {
|
||||||
let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<Interner>>| {
|
let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<Interner>>| {
|
||||||
let value = subst
|
let result = from_chalk(db, subst);
|
||||||
.value
|
|
||||||
.iter(&Interner)
|
|
||||||
.map(|p| match p.ty(&Interner) {
|
|
||||||
Some(ty) => from_chalk(db, ty.clone()),
|
|
||||||
None => unimplemented!(),
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let result = Canonical { value, num_vars: subst.binders.len(&Interner) };
|
|
||||||
SolutionVariables(result)
|
SolutionVariables(result)
|
||||||
};
|
};
|
||||||
match solution {
|
match solution {
|
||||||
|
@ -222,7 +214,7 @@ fn solution_from_chalk(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct SolutionVariables(pub Canonical<Vec<Ty>>);
|
pub struct SolutionVariables(pub Canonical<Substs>);
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
/// A (possible) solution for a proposed goal.
|
/// A (possible) solution for a proposed goal.
|
||||||
|
|
|
@ -17,7 +17,7 @@ use crate::{
|
||||||
primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness},
|
primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness},
|
||||||
traits::{builtin, AssocTyValue, Canonical, Impl, Obligation},
|
traits::{builtin, AssocTyValue, Canonical, Impl, Obligation},
|
||||||
ApplicationTy, CallableDef, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId,
|
ApplicationTy, CallableDef, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId,
|
||||||
ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor,
|
ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TyKind, TypeCtor,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::interner::*;
|
use super::interner::*;
|
||||||
|
@ -555,22 +555,39 @@ where
|
||||||
type Chalk = chalk_ir::Canonical<T::Chalk>;
|
type Chalk = chalk_ir::Canonical<T::Chalk>;
|
||||||
|
|
||||||
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
|
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
|
||||||
let parameter = chalk_ir::CanonicalVarKind::new(
|
let kinds = self
|
||||||
chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General),
|
.kinds
|
||||||
chalk_ir::UniverseIndex::ROOT,
|
.iter()
|
||||||
);
|
.map(|k| match k {
|
||||||
|
TyKind::General => chalk_ir::TyKind::General,
|
||||||
|
TyKind::Integer => chalk_ir::TyKind::Integer,
|
||||||
|
TyKind::Float => chalk_ir::TyKind::Float,
|
||||||
|
})
|
||||||
|
.map(|tk| {
|
||||||
|
chalk_ir::CanonicalVarKind::new(
|
||||||
|
chalk_ir::VariableKind::Ty(tk),
|
||||||
|
chalk_ir::UniverseIndex::ROOT,
|
||||||
|
)
|
||||||
|
});
|
||||||
let value = self.value.to_chalk(db);
|
let value = self.value.to_chalk(db);
|
||||||
chalk_ir::Canonical {
|
chalk_ir::Canonical { value, binders: chalk_ir::CanonicalVarKinds::from(&Interner, kinds) }
|
||||||
value,
|
|
||||||
binders: chalk_ir::CanonicalVarKinds::from(&Interner, vec![parameter; self.num_vars]),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
|
fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
|
||||||
Canonical {
|
let kinds = canonical
|
||||||
num_vars: canonical.binders.len(&Interner),
|
.binders
|
||||||
value: from_chalk(db, canonical.value),
|
.iter(&Interner)
|
||||||
}
|
.map(|k| match k.kind {
|
||||||
|
chalk_ir::VariableKind::Ty(tk) => match tk {
|
||||||
|
chalk_ir::TyKind::General => TyKind::General,
|
||||||
|
chalk_ir::TyKind::Integer => TyKind::Integer,
|
||||||
|
chalk_ir::TyKind::Float => TyKind::Float,
|
||||||
|
},
|
||||||
|
chalk_ir::VariableKind::Lifetime => panic!("unexpected lifetime from Chalk"),
|
||||||
|
chalk_ir::VariableKind::Const(_) => panic!("unexpected const from Chalk"),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Canonical { kinds, value: from_chalk(db, canonical.value) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue