mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 05:15:04 +00:00
Fix fallback to bound vars in unify
This commit is contained in:
parent
aebcf7b5d4
commit
278f5b043d
1 changed files with 78 additions and 45 deletions
|
@ -4,7 +4,6 @@ use std::{borrow::Cow, fmt, sync::Arc};
|
||||||
|
|
||||||
use chalk_ir::{
|
use chalk_ir::{
|
||||||
cast::Cast, fold::Fold, interner::HasInterner, FloatTy, IntTy, TyVariableKind, UniverseIndex,
|
cast::Cast, fold::Fold, interner::HasInterner, FloatTy, IntTy, TyVariableKind, UniverseIndex,
|
||||||
VariableKind,
|
|
||||||
};
|
};
|
||||||
use chalk_solve::infer::ParameterEnaVariableExt;
|
use chalk_solve::infer::ParameterEnaVariableExt;
|
||||||
use ena::unify::UnifyKey;
|
use ena::unify::UnifyKey;
|
||||||
|
@ -12,7 +11,7 @@ use ena::unify::UnifyKey;
|
||||||
use super::{InferOk, InferResult, InferenceContext, TypeError};
|
use super::{InferOk, InferResult, InferenceContext, TypeError};
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase, fold_tys, static_lifetime, BoundVar, Canonical, DebruijnIndex, GenericArg,
|
db::HirDatabase, fold_tys, static_lifetime, BoundVar, Canonical, DebruijnIndex, GenericArg,
|
||||||
InferenceVar, Interner, Scalar, Substitution, TraitEnvironment, Ty, TyKind,
|
InferenceVar, Interner, Scalar, Substitution, TraitEnvironment, Ty, TyKind, VariableKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'a> InferenceContext<'a> {
|
impl<'a> InferenceContext<'a> {
|
||||||
|
@ -112,19 +111,28 @@ pub(crate) fn unify(
|
||||||
}
|
}
|
||||||
// default any type vars that weren't unified back to their original bound vars
|
// default any type vars that weren't unified back to their original bound vars
|
||||||
// (kind of hacky)
|
// (kind of hacky)
|
||||||
for (i, var) in vars.iter(&Interner).enumerate() {
|
let find_var = |iv| {
|
||||||
let var = var.assert_ty_ref(&Interner);
|
vars.iter(&Interner).position(|v| match v.interned() {
|
||||||
if &*table.resolve_ty_shallow(var) == var {
|
chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(&Interner),
|
||||||
table.unify(
|
chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(&Interner),
|
||||||
var,
|
chalk_ir::GenericArgData::Const(c) => c.inference_var(&Interner),
|
||||||
&TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i)).intern(&Interner),
|
} == Some(iv))
|
||||||
);
|
};
|
||||||
}
|
let fallback = |iv, kind, default| match kind {
|
||||||
}
|
chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv).map_or(default, |i| {
|
||||||
|
BoundVar::new(DebruijnIndex::INNERMOST, i).to_ty(&Interner).cast(&Interner)
|
||||||
|
}),
|
||||||
|
chalk_ir::VariableKind::Lifetime => find_var(iv).map_or(default, |i| {
|
||||||
|
BoundVar::new(DebruijnIndex::INNERMOST, i).to_lifetime(&Interner).cast(&Interner)
|
||||||
|
}),
|
||||||
|
chalk_ir::VariableKind::Const(ty) => find_var(iv).map_or(default, |i| {
|
||||||
|
BoundVar::new(DebruijnIndex::INNERMOST, i).to_const(&Interner, ty).cast(&Interner)
|
||||||
|
}),
|
||||||
|
};
|
||||||
Some(Substitution::from_iter(
|
Some(Substitution::from_iter(
|
||||||
&Interner,
|
&Interner,
|
||||||
vars.iter(&Interner)
|
vars.iter(&Interner)
|
||||||
.map(|v| table.resolve_ty_completely(v.assert_ty_ref(&Interner).clone())),
|
.map(|v| table.resolve_with_fallback(v.assert_ty_ref(&Interner).clone(), fallback)),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,8 +209,65 @@ impl<'a> InferenceTable<'a> {
|
||||||
self.new_var(TyVariableKind::General, true)
|
self.new_var(TyVariableKind::General, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn resolve_with_fallback<T>(
|
||||||
|
&mut self,
|
||||||
|
t: T,
|
||||||
|
fallback: impl Fn(InferenceVar, VariableKind, GenericArg) -> GenericArg,
|
||||||
|
) -> T::Result
|
||||||
|
where
|
||||||
|
T: HasInterner<Interner = Interner> + Fold<Interner>,
|
||||||
|
{
|
||||||
|
self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_with_fallback_inner<T>(
|
||||||
|
&mut self,
|
||||||
|
var_stack: &mut Vec<InferenceVar>,
|
||||||
|
t: T,
|
||||||
|
fallback: &impl Fn(InferenceVar, VariableKind, GenericArg) -> GenericArg,
|
||||||
|
) -> T::Result
|
||||||
|
where
|
||||||
|
T: HasInterner<Interner = Interner> + Fold<Interner>,
|
||||||
|
{
|
||||||
|
fold_tys(
|
||||||
|
t,
|
||||||
|
|ty, _| match ty.kind(&Interner) {
|
||||||
|
&TyKind::InferenceVar(tv, kind) => {
|
||||||
|
if var_stack.contains(&tv) {
|
||||||
|
cov_mark::hit!(type_var_cycles_resolve_as_possible);
|
||||||
|
// recursive type
|
||||||
|
let default =
|
||||||
|
self.type_variable_table.fallback_value(tv, kind).cast(&Interner);
|
||||||
|
return fallback(tv, VariableKind::Ty(kind), default)
|
||||||
|
.assert_ty_ref(&Interner)
|
||||||
|
.clone();
|
||||||
|
}
|
||||||
|
if let Some(known_ty) = self.var_unification_table.probe_var(tv) {
|
||||||
|
// known_ty may contain other variables that are known by now
|
||||||
|
var_stack.push(tv);
|
||||||
|
let result = self.resolve_with_fallback_inner(
|
||||||
|
var_stack,
|
||||||
|
known_ty.assert_ty_ref(&Interner).clone(),
|
||||||
|
fallback,
|
||||||
|
);
|
||||||
|
var_stack.pop();
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
let default =
|
||||||
|
self.type_variable_table.fallback_value(tv, kind).cast(&Interner);
|
||||||
|
fallback(tv, VariableKind::Ty(kind), default)
|
||||||
|
.assert_ty_ref(&Interner)
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => ty,
|
||||||
|
},
|
||||||
|
DebruijnIndex::INNERMOST,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve_ty_completely(&mut self, ty: Ty) -> Ty {
|
pub(crate) fn resolve_ty_completely(&mut self, ty: Ty) -> Ty {
|
||||||
self.resolve_ty_completely_inner(&mut Vec::new(), ty)
|
self.resolve_with_fallback(ty, |_, _, d| d)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME get rid of this, instead resolve shallowly where necessary
|
// FIXME get rid of this, instead resolve shallowly where necessary
|
||||||
|
@ -282,38 +347,6 @@ impl<'a> InferenceTable<'a> {
|
||||||
DebruijnIndex::INNERMOST,
|
DebruijnIndex::INNERMOST,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves the type completely; type variables without known type are
|
|
||||||
/// replaced by TyKind::Unknown.
|
|
||||||
fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<InferenceVar>, ty: Ty) -> Ty {
|
|
||||||
// FIXME implement as a proper Folder, handle lifetimes and consts as well
|
|
||||||
fold_tys(
|
|
||||||
ty,
|
|
||||||
|ty, _| match ty.kind(&Interner) {
|
|
||||||
&TyKind::InferenceVar(tv, kind) => {
|
|
||||||
if tv_stack.contains(&tv) {
|
|
||||||
cov_mark::hit!(type_var_cycles_resolve_completely);
|
|
||||||
// recursive type
|
|
||||||
return self.type_variable_table.fallback_value(tv, kind);
|
|
||||||
}
|
|
||||||
if let Some(known_ty) = self.var_unification_table.probe_var(tv) {
|
|
||||||
// known_ty may contain other variables that are known by now
|
|
||||||
tv_stack.push(tv);
|
|
||||||
let result = self.resolve_ty_completely_inner(
|
|
||||||
tv_stack,
|
|
||||||
known_ty.assert_ty_ref(&Interner).clone(),
|
|
||||||
);
|
|
||||||
tv_stack.pop();
|
|
||||||
result
|
|
||||||
} else {
|
|
||||||
self.type_variable_table.fallback_value(tv, kind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => ty,
|
|
||||||
},
|
|
||||||
DebruijnIndex::INNERMOST,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> fmt::Debug for InferenceTable<'a> {
|
impl<'a> fmt::Debug for InferenceTable<'a> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue