Store diverging flag for type variables as bitflags

This commit is contained in:
Ryo Yoshida 2023-01-05 20:06:49 +09:00
parent a97c71f92d
commit 1bfc732b78
No known key found for this signature in database
GPG Key ID: E25698A930586171
3 changed files with 19 additions and 15 deletions

1
Cargo.lock generated
View File

@ -557,6 +557,7 @@ version = "0.0.0"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"base-db", "base-db",
"bitflags",
"chalk-derive", "chalk-derive",
"chalk-ir", "chalk-ir",
"chalk-recursive", "chalk-recursive",

View File

@ -13,6 +13,7 @@ doctest = false
cov-mark = "2.0.0-pre.1" cov-mark = "2.0.0-pre.1"
itertools = "0.10.5" itertools = "0.10.5"
arrayvec = "0.7.2" arrayvec = "0.7.2"
bitflags = "1.3.2"
smallvec = "1.10.0" smallvec = "1.10.0"
ena = "0.14.0" ena = "0.14.0"
tracing = "0.1.35" tracing = "0.1.35"

View File

@ -1,6 +1,6 @@
//! Unification and canonicalization logic. //! Unification and canonicalization logic.
use std::{fmt, mem, sync::Arc}; use std::{fmt, iter, mem, sync::Arc};
use chalk_ir::{ use chalk_ir::{
cast::Cast, fold::TypeFoldable, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy, cast::Cast, fold::TypeFoldable, interner::HasInterner, zip::Zip, CanonicalVarKind, FloatTy,
@ -128,9 +128,11 @@ pub(crate) fn unify(
)) ))
} }
#[derive(Copy, Clone, Debug)] bitflags::bitflags! {
pub(crate) struct TypeVariableData { #[derive(Default)]
diverging: bool, pub(crate) struct TypeVariableFlags: u8 {
const DIVERGING = 1 << 0;
}
} }
type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>; type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>;
@ -140,14 +142,14 @@ pub(crate) struct InferenceTable<'a> {
pub(crate) db: &'a dyn HirDatabase, pub(crate) db: &'a dyn HirDatabase,
pub(crate) trait_env: Arc<TraitEnvironment>, pub(crate) trait_env: Arc<TraitEnvironment>,
var_unification_table: ChalkInferenceTable, var_unification_table: ChalkInferenceTable,
type_variable_table: Vec<TypeVariableData>, type_variable_table: Vec<TypeVariableFlags>,
pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>, pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
} }
pub(crate) struct InferenceTableSnapshot { pub(crate) struct InferenceTableSnapshot {
var_table_snapshot: chalk_solve::infer::InferenceSnapshot<Interner>, var_table_snapshot: chalk_solve::infer::InferenceSnapshot<Interner>,
pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>, pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
type_variable_table_snapshot: Vec<TypeVariableData>, type_variable_table_snapshot: Vec<TypeVariableFlags>,
} }
impl<'a> InferenceTable<'a> { impl<'a> InferenceTable<'a> {
@ -169,19 +171,19 @@ impl<'a> InferenceTable<'a> {
/// result. /// result.
pub(super) fn propagate_diverging_flag(&mut self) { pub(super) fn propagate_diverging_flag(&mut self) {
for i in 0..self.type_variable_table.len() { for i in 0..self.type_variable_table.len() {
if !self.type_variable_table[i].diverging { if !self.type_variable_table[i].contains(TypeVariableFlags::DIVERGING) {
continue; continue;
} }
let v = InferenceVar::from(i as u32); let v = InferenceVar::from(i as u32);
let root = self.var_unification_table.inference_var_root(v); let root = self.var_unification_table.inference_var_root(v);
if let Some(data) = self.type_variable_table.get_mut(root.index() as usize) { if let Some(data) = self.type_variable_table.get_mut(root.index() as usize) {
data.diverging = true; *data |= TypeVariableFlags::DIVERGING;
} }
} }
} }
pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) { pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) {
self.type_variable_table[iv.index() as usize].diverging = diverging; self.type_variable_table[iv.index() as usize].set(TypeVariableFlags::DIVERGING, diverging);
} }
fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty {
@ -189,7 +191,7 @@ impl<'a> InferenceTable<'a> {
_ if self _ if self
.type_variable_table .type_variable_table
.get(iv.index() as usize) .get(iv.index() as usize)
.map_or(false, |data| data.diverging) => .map_or(false, |data| data.contains(TypeVariableFlags::DIVERGING)) =>
{ {
TyKind::Never TyKind::Never
} }
@ -247,10 +249,8 @@ impl<'a> InferenceTable<'a> {
} }
fn extend_type_variable_table(&mut self, to_index: usize) { fn extend_type_variable_table(&mut self, to_index: usize) {
self.type_variable_table.extend( let count = to_index - self.type_variable_table.len() + 1;
(0..1 + to_index - self.type_variable_table.len()) self.type_variable_table.extend(iter::repeat(TypeVariableFlags::default()).take(count));
.map(|_| TypeVariableData { diverging: false }),
);
} }
fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty { fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty {
@ -258,7 +258,9 @@ impl<'a> InferenceTable<'a> {
// Chalk might have created some type variables for its own purposes that we don't know about... // Chalk might have created some type variables for its own purposes that we don't know about...
self.extend_type_variable_table(var.index() as usize); self.extend_type_variable_table(var.index() as usize);
assert_eq!(var.index() as usize, self.type_variable_table.len() - 1); assert_eq!(var.index() as usize, self.type_variable_table.len() - 1);
self.type_variable_table[var.index() as usize].diverging = diverging; if diverging {
self.type_variable_table[var.index() as usize] |= TypeVariableFlags::DIVERGING;
}
var.to_ty_with_kind(Interner, kind) var.to_ty_with_kind(Interner, kind)
} }