8385: Align `InferenceVar` to Chalk r=flodiebold a=flodiebold



Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
bors[bot] 2021-04-06 19:11:41 +00:00 committed by GitHub
commit 1643d1534b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 85 additions and 103 deletions

View file

@ -683,25 +683,6 @@ impl<'a> InferenceContext<'a> {
} }
} }
/// The kinds of placeholders we need during type inference. There's separate
/// values for general types, and for integer and float variables. The latter
/// two are used for inference of literal values (e.g. `100` could be one of
/// several integer types).
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct InferenceVar {
index: u32,
}
impl InferenceVar {
fn to_inner(self) -> unify::TypeVarId {
unify::TypeVarId(self.index)
}
fn from_inner(unify::TypeVarId(index): unify::TypeVarId) -> Self {
InferenceVar { index }
}
}
/// When inferring an expression, we propagate downward whatever type hint we /// When inferring an expression, we propagate downward whatever type hint we
/// are able in the form of an `Expectation`. /// are able in the form of an `Expectation`.
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]

View file

@ -51,7 +51,7 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
t.fold_binders( t.fold_binders(
&mut |ty, binders| match ty.kind(&Interner) { &mut |ty, binders| match ty.kind(&Interner) {
&TyKind::InferenceVar(var, kind) => { &TyKind::InferenceVar(var, kind) => {
let inner = var.to_inner(); let inner = from_inference_var(var);
if self.var_stack.contains(&inner) { if self.var_stack.contains(&inner) {
// recursive type // recursive type
return self.ctx.table.type_variable_table.fallback_value(var, kind); return self.ctx.table.type_variable_table.fallback_value(var, kind);
@ -65,7 +65,7 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
result result
} else { } else {
let root = self.ctx.table.var_unification_table.find(inner); let root = self.ctx.table.var_unification_table.find(inner);
let position = self.add(InferenceVar::from_inner(root), kind); let position = self.add(to_inference_var(root), kind);
TyKind::BoundVar(BoundVar::new(binders, position)).intern(&Interner) TyKind::BoundVar(BoundVar::new(binders, position)).intern(&Interner)
} }
} }
@ -207,16 +207,16 @@ impl TypeVariableTable {
} }
pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) { pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) {
self.inner[iv.to_inner().0 as usize].diverging = diverging; self.inner[from_inference_var(iv).0 as usize].diverging = diverging;
} }
fn is_diverging(&mut self, iv: InferenceVar) -> bool { fn is_diverging(&mut self, iv: InferenceVar) -> bool {
self.inner[iv.to_inner().0 as usize].diverging self.inner[from_inference_var(iv).0 as usize].diverging
} }
fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty {
match kind { match kind {
_ if self.inner[iv.to_inner().0 as usize].diverging => TyKind::Never, _ if self.inner[from_inference_var(iv).0 as usize].diverging => TyKind::Never,
TyVariableKind::General => TyKind::Error, TyVariableKind::General => TyKind::Error,
TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)), TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)),
TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)), TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)),
@ -250,7 +250,7 @@ impl InferenceTable {
self.type_variable_table.push(TypeVariableData { diverging }); self.type_variable_table.push(TypeVariableData { diverging });
let key = self.var_unification_table.new_key(TypeVarValue::Unknown); let key = self.var_unification_table.new_key(TypeVarValue::Unknown);
assert_eq!(key.0 as usize, self.type_variable_table.inner.len() - 1); assert_eq!(key.0 as usize, self.type_variable_table.inner.len() - 1);
TyKind::InferenceVar(InferenceVar::from_inner(key), kind).intern(&Interner) TyKind::InferenceVar(to_inference_var(key), kind).intern(&Interner)
} }
pub(crate) fn new_type_var(&mut self) -> Ty { pub(crate) fn new_type_var(&mut self) -> Ty {
@ -369,8 +369,12 @@ impl InferenceTable {
== self.type_variable_table.is_diverging(*tv2) => == self.type_variable_table.is_diverging(*tv2) =>
{ {
// both type vars are unknown since we tried to resolve them // both type vars are unknown since we tried to resolve them
if !self.var_unification_table.unioned(tv1.to_inner(), tv2.to_inner()) { if !self
self.var_unification_table.union(tv1.to_inner(), tv2.to_inner()); .var_unification_table
.unioned(from_inference_var(*tv1), from_inference_var(*tv2))
{
self.var_unification_table
.union(from_inference_var(*tv1), from_inference_var(*tv2));
self.revision += 1; self.revision += 1;
} }
true true
@ -407,7 +411,7 @@ impl InferenceTable {
) => { ) => {
// the type var is unknown since we tried to resolve it // the type var is unknown since we tried to resolve it
self.var_unification_table.union_value( self.var_unification_table.union_value(
tv.to_inner(), from_inference_var(*tv),
TypeVarValue::Known(other.clone().intern(&Interner)), TypeVarValue::Known(other.clone().intern(&Interner)),
); );
self.revision += 1; self.revision += 1;
@ -462,7 +466,7 @@ impl InferenceTable {
} }
match ty.kind(&Interner) { match ty.kind(&Interner) {
TyKind::InferenceVar(tv, _) => { TyKind::InferenceVar(tv, _) => {
let inner = tv.to_inner(); let inner = from_inference_var(*tv);
match self.var_unification_table.inlined_probe_value(inner).known() { match self.var_unification_table.inlined_probe_value(inner).known() {
Some(known_ty) => { Some(known_ty) => {
// The known_ty can't be a type var itself // The known_ty can't be a type var itself
@ -485,7 +489,7 @@ impl InferenceTable {
fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
ty.fold(&mut |ty| match ty.kind(&Interner) { ty.fold(&mut |ty| match ty.kind(&Interner) {
&TyKind::InferenceVar(tv, kind) => { &TyKind::InferenceVar(tv, kind) => {
let inner = tv.to_inner(); let inner = from_inference_var(tv);
if tv_stack.contains(&inner) { if tv_stack.contains(&inner) {
cov_mark::hit!(type_var_cycles_resolve_as_possible); cov_mark::hit!(type_var_cycles_resolve_as_possible);
// recursive type // recursive type
@ -512,7 +516,7 @@ impl InferenceTable {
fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
ty.fold(&mut |ty| match ty.kind(&Interner) { ty.fold(&mut |ty| match ty.kind(&Interner) {
&TyKind::InferenceVar(tv, kind) => { &TyKind::InferenceVar(tv, kind) => {
let inner = tv.to_inner(); let inner = from_inference_var(tv);
if tv_stack.contains(&inner) { if tv_stack.contains(&inner) {
cov_mark::hit!(type_var_cycles_resolve_completely); cov_mark::hit!(type_var_cycles_resolve_completely);
// recursive type // recursive type
@ -555,6 +559,14 @@ impl UnifyKey for TypeVarId {
} }
} }
fn from_inference_var(var: InferenceVar) -> TypeVarId {
TypeVarId(var.index())
}
fn to_inference_var(TypeVarId(index): TypeVarId) -> InferenceVar {
index.into()
}
/// The value of a type variable: either we already know the type, or we don't /// The value of a type variable: either we already know the type, or we don't
/// know it yet. /// know it yet.
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]

View file

@ -42,7 +42,7 @@ use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
pub use autoderef::autoderef; pub use autoderef::autoderef;
pub use builder::TyBuilder; pub use builder::TyBuilder;
pub use chalk_ext::{ProjectionTyExt, TyExt}; pub use chalk_ext::{ProjectionTyExt, TyExt};
pub use infer::{could_unify, InferenceResult, InferenceVar}; pub use infer::{could_unify, InferenceResult};
pub use lower::{ pub use lower::{
associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
TyDefId, TyLoweringContext, ValueTyDefId, TyDefId, TyLoweringContext, ValueTyDefId,

View file

@ -10,10 +10,9 @@ use base_db::salsa::InternKey;
use hir_def::{GenericDefId, TypeAliasId}; use hir_def::{GenericDefId, TypeAliasId};
use crate::{ use crate::{
chalk_ext::ProjectionTyExt, db::HirDatabase, dummy_usize_const, static_lifetime, AliasTy, chalk_ext::ProjectionTyExt, db::HirDatabase, static_lifetime, AliasTy, CallableDefId,
CallableDefId, Canonical, Const, DomainGoal, FnPointer, GenericArg, InEnvironment, Lifetime, Canonical, DomainGoal, FnPointer, GenericArg, InEnvironment, OpaqueTy, ProjectionTy,
OpaqueTy, ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TypeWalk, QuantifiedWhereClause, Substitution, TraitRef, Ty, TypeWalk, WhereClause,
WhereClause,
}; };
use super::interner::*; use super::interner::*;
@ -23,16 +22,16 @@ impl ToChalk for Ty {
type Chalk = chalk_ir::Ty<Interner>; type Chalk = chalk_ir::Ty<Interner>;
fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> { fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
match self.into_inner() { match self.into_inner() {
TyKind::Ref(m, lt, ty) => ref_to_chalk(db, m, lt, ty), TyKind::Ref(m, lt, ty) => {
TyKind::Array(ty, size) => array_to_chalk(db, ty, size), chalk_ir::TyKind::Ref(m, lt, ty.to_chalk(db)).intern(&Interner)
TyKind::Function(FnPointer { sig, substitution: substs, .. }) => { }
TyKind::Array(ty, size) => {
chalk_ir::TyKind::Array(ty.to_chalk(db), size).intern(&Interner)
}
TyKind::Function(FnPointer { sig, substitution: substs, num_binders }) => {
let substitution = chalk_ir::FnSubst(substs.0.to_chalk(db)); let substitution = chalk_ir::FnSubst(substs.0.to_chalk(db));
chalk_ir::TyKind::Function(chalk_ir::FnPointer { chalk_ir::TyKind::Function(chalk_ir::FnPointer { num_binders, sig, substitution })
num_binders: 0, .intern(&Interner)
sig,
substitution,
})
.intern(&Interner)
} }
TyKind::AssociatedType(assoc_type_id, substs) => { TyKind::AssociatedType(assoc_type_id, substs) => {
let substitution = substs.to_chalk(db); let substitution = substs.to_chalk(db);
@ -74,22 +73,13 @@ impl ToChalk for Ty {
chalk_ir::TyKind::Adt(adt_id, substitution).intern(&Interner) chalk_ir::TyKind::Adt(adt_id, substitution).intern(&Interner)
} }
TyKind::Alias(AliasTy::Projection(proj_ty)) => { TyKind::Alias(AliasTy::Projection(proj_ty)) => {
let associated_ty_id = proj_ty.associated_ty_id; chalk_ir::AliasTy::Projection(proj_ty.to_chalk(db))
let substitution = proj_ty.substitution.to_chalk(db);
chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
associated_ty_id,
substitution,
})
.cast(&Interner)
.intern(&Interner)
}
TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
let opaque_ty_id = opaque_ty.opaque_ty_id;
let substitution = opaque_ty.substitution.to_chalk(db);
chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { opaque_ty_id, substitution })
.cast(&Interner) .cast(&Interner)
.intern(&Interner) .intern(&Interner)
} }
TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
chalk_ir::AliasTy::Opaque(opaque_ty.to_chalk(db)).cast(&Interner).intern(&Interner)
}
TyKind::Placeholder(idx) => idx.to_ty::<Interner>(&Interner), TyKind::Placeholder(idx) => idx.to_ty::<Interner>(&Interner),
TyKind::BoundVar(idx) => chalk_ir::TyKind::BoundVar(idx).intern(&Interner), TyKind::BoundVar(idx) => chalk_ir::TyKind::BoundVar(idx).intern(&Interner),
TyKind::InferenceVar(..) => panic!("uncanonicalized infer ty"), TyKind::InferenceVar(..) => panic!("uncanonicalized infer ty"),
@ -101,7 +91,7 @@ impl ToChalk for Ty {
); );
let bounded_ty = chalk_ir::DynTy { let bounded_ty = chalk_ir::DynTy {
bounds: chalk_ir::Binders::new(binders, where_clauses), bounds: chalk_ir::Binders::new(binders, where_clauses),
lifetime: static_lifetime(), lifetime: dyn_ty.lifetime,
}; };
chalk_ir::TyKind::Dyn(bounded_ty).intern(&Interner) chalk_ir::TyKind::Dyn(bounded_ty).intern(&Interner)
} }
@ -114,17 +104,10 @@ impl ToChalk for Ty {
chalk_ir::TyKind::Array(ty, size) => TyKind::Array(from_chalk(db, ty), size), chalk_ir::TyKind::Array(ty, size) => TyKind::Array(from_chalk(db, ty), size),
chalk_ir::TyKind::Placeholder(idx) => TyKind::Placeholder(idx), chalk_ir::TyKind::Placeholder(idx) => TyKind::Placeholder(idx),
chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(proj)) => { chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(proj)) => {
let associated_ty = proj.associated_ty_id; TyKind::Alias(AliasTy::Projection(from_chalk(db, proj)))
let parameters = from_chalk(db, proj.substitution);
TyKind::Alias(AliasTy::Projection(ProjectionTy {
associated_ty_id: associated_ty,
substitution: parameters,
}))
} }
chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(opaque_ty)) => { chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(opaque_ty)) => {
let opaque_ty_id = opaque_ty.opaque_ty_id; TyKind::Alias(AliasTy::Opaque(from_chalk(db, opaque_ty)))
let parameters = from_chalk(db, opaque_ty.substitution);
TyKind::Alias(AliasTy::Opaque(OpaqueTy { opaque_ty_id, substitution: parameters }))
} }
chalk_ir::TyKind::Function(chalk_ir::FnPointer { chalk_ir::TyKind::Function(chalk_ir::FnPointer {
num_binders, num_binders,
@ -138,18 +121,19 @@ impl ToChalk for Ty {
} }
chalk_ir::TyKind::BoundVar(idx) => TyKind::BoundVar(idx), chalk_ir::TyKind::BoundVar(idx) => TyKind::BoundVar(idx),
chalk_ir::TyKind::InferenceVar(_iv, _kind) => TyKind::Error, chalk_ir::TyKind::InferenceVar(_iv, _kind) => TyKind::Error,
chalk_ir::TyKind::Dyn(where_clauses) => { chalk_ir::TyKind::Dyn(dyn_ty) => {
assert_eq!(where_clauses.bounds.binders.len(&Interner), 1); assert_eq!(dyn_ty.bounds.binders.len(&Interner), 1);
let bounds = where_clauses let (bounds, binders) = dyn_ty.bounds.into_value_and_skipped_binders();
.bounds let where_clauses = crate::QuantifiedWhereClauses::from_iter(
.skip_binders() &Interner,
.iter(&Interner) bounds.interned().iter().cloned().map(|p| from_chalk(db, p)),
.map(|c| from_chalk(db, c.clone())); );
TyKind::Dyn(crate::DynTy { TyKind::Dyn(crate::DynTy {
bounds: crate::Binders::new( bounds: crate::Binders::new(binders, where_clauses),
where_clauses.bounds.binders.clone(), // HACK: we sometimes get lifetime variables back in solutions
crate::QuantifiedWhereClauses::from_iter(&Interner, bounds), // from Chalk, and don't have the infrastructure to substitute
), // them yet. So for now we just turn them into 'static right
// when we get them
lifetime: static_lifetime(), lifetime: static_lifetime(),
}) })
} }
@ -169,8 +153,12 @@ impl ToChalk for Ty {
} }
chalk_ir::TyKind::Raw(mutability, ty) => TyKind::Raw(mutability, from_chalk(db, ty)), chalk_ir::TyKind::Raw(mutability, ty) => TyKind::Raw(mutability, from_chalk(db, ty)),
chalk_ir::TyKind::Slice(ty) => TyKind::Slice(from_chalk(db, ty)), chalk_ir::TyKind::Slice(ty) => TyKind::Slice(from_chalk(db, ty)),
chalk_ir::TyKind::Ref(mutability, lifetime, ty) => { chalk_ir::TyKind::Ref(mutability, _lifetime, ty) => {
TyKind::Ref(mutability, lifetime, from_chalk(db, ty)) // HACK: we sometimes get lifetime variables back in solutions
// from Chalk, and don't have the infrastructure to substitute
// them yet. So for now we just turn them into 'static right
// when we get them
TyKind::Ref(mutability, static_lifetime(), from_chalk(db, ty))
} }
chalk_ir::TyKind::Str => TyKind::Str, chalk_ir::TyKind::Str => TyKind::Str,
chalk_ir::TyKind::Never => TyKind::Never, chalk_ir::TyKind::Never => TyKind::Never,
@ -189,26 +177,6 @@ impl ToChalk for Ty {
} }
} }
/// We currently don't model lifetimes, but Chalk does. So, we have to insert a
/// fake lifetime here, because Chalks built-in logic may expect it to be there.
fn ref_to_chalk(
db: &dyn HirDatabase,
mutability: chalk_ir::Mutability,
_lifetime: Lifetime,
ty: Ty,
) -> chalk_ir::Ty<Interner> {
let arg = ty.to_chalk(db);
let lifetime = static_lifetime();
chalk_ir::TyKind::Ref(mutability, lifetime, arg).intern(&Interner)
}
/// We currently don't model constants, but Chalk does. So, we have to insert a
/// fake constant here, because Chalks built-in logic may expect it to be there.
fn array_to_chalk(db: &dyn HirDatabase, ty: Ty, _: Const) -> chalk_ir::Ty<Interner> {
let arg = ty.to_chalk(db);
chalk_ir::TyKind::Array(arg, dummy_usize_const()).intern(&Interner)
}
impl ToChalk for GenericArg { impl ToChalk for GenericArg {
type Chalk = chalk_ir::GenericArg<Interner>; type Chalk = chalk_ir::GenericArg<Interner>;

View file

@ -11,8 +11,7 @@ use smallvec::SmallVec;
use crate::{ use crate::{
AssocTypeId, CanonicalVarKinds, ChalkTraitId, ClosureId, Const, FnDefId, FnSig, ForeignDefId, AssocTypeId, CanonicalVarKinds, ChalkTraitId, ClosureId, Const, FnDefId, FnSig, ForeignDefId,
InferenceVar, Interner, Lifetime, OpaqueTyId, PlaceholderIndex, TypeWalk, VariableKind, Interner, Lifetime, OpaqueTyId, PlaceholderIndex, TypeWalk, VariableKind, VariableKinds,
VariableKinds,
}; };
#[derive(Clone, PartialEq, Eq, Debug, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
@ -524,3 +523,25 @@ pub enum Guidance {
/// There's no useful information to feed back to type inference /// There's no useful information to feed back to type inference
Unknown, Unknown,
} }
/// The kinds of placeholders we need during type inference. There's separate
/// values for general types, and for integer and float variables. The latter
/// two are used for inference of literal values (e.g. `100` could be one of
/// several integer types).
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct InferenceVar {
index: u32,
}
impl From<u32> for InferenceVar {
fn from(index: u32) -> InferenceVar {
InferenceVar { index }
}
}
impl InferenceVar {
/// Gets the underlying index value.
pub fn index(self) -> u32 {
self.index
}
}