|
|
|
|
@@ -4,8 +4,8 @@ use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack};
|
|
|
|
|
use rustc_type_ir::inherent::*;
|
|
|
|
|
use rustc_type_ir::solve::{Goal, QueryInput};
|
|
|
|
|
use rustc_type_ir::{
|
|
|
|
|
self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, InferCtxtLike,
|
|
|
|
|
Interner, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
|
|
|
|
self as ty, Canonical, CanonicalTyVarKind, CanonicalVarKind, InferCtxtLike, Interner,
|
|
|
|
|
TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
use crate::delegate::SolverDelegate;
|
|
|
|
|
@@ -50,7 +50,7 @@ pub struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner> {
|
|
|
|
|
|
|
|
|
|
// Mutable fields.
|
|
|
|
|
variables: &'a mut Vec<I::GenericArg>,
|
|
|
|
|
primitive_var_infos: Vec<CanonicalVarInfo<I>>,
|
|
|
|
|
var_kinds: Vec<CanonicalVarKind<I>>,
|
|
|
|
|
variable_lookup_table: HashMap<I::GenericArg, usize>,
|
|
|
|
|
binder_index: ty::DebruijnIndex,
|
|
|
|
|
|
|
|
|
|
@@ -73,7 +73,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|
|
|
|
|
|
|
|
|
variables,
|
|
|
|
|
variable_lookup_table: Default::default(),
|
|
|
|
|
primitive_var_infos: Vec::new(),
|
|
|
|
|
var_kinds: Vec::new(),
|
|
|
|
|
binder_index: ty::INNERMOST,
|
|
|
|
|
|
|
|
|
|
cache: Default::default(),
|
|
|
|
|
@@ -106,7 +106,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|
|
|
|
|
|
|
|
|
variables,
|
|
|
|
|
variable_lookup_table: Default::default(),
|
|
|
|
|
primitive_var_infos: Vec::new(),
|
|
|
|
|
var_kinds: Vec::new(),
|
|
|
|
|
binder_index: ty::INNERMOST,
|
|
|
|
|
|
|
|
|
|
cache: Default::default(),
|
|
|
|
|
@@ -123,7 +123,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|
|
|
|
// We're able to reuse the `variable_lookup_table` as whether or not
|
|
|
|
|
// it already contains an entry for `'static` does not matter.
|
|
|
|
|
variable_lookup_table: env_canonicalizer.variable_lookup_table,
|
|
|
|
|
primitive_var_infos: env_canonicalizer.primitive_var_infos,
|
|
|
|
|
var_kinds: env_canonicalizer.var_kinds,
|
|
|
|
|
binder_index: ty::INNERMOST,
|
|
|
|
|
|
|
|
|
|
// We do not reuse the cache as it may contain entries whose canonicalized
|
|
|
|
|
@@ -149,7 +149,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|
|
|
|
fn get_or_insert_bound_var(
|
|
|
|
|
&mut self,
|
|
|
|
|
arg: impl Into<I::GenericArg>,
|
|
|
|
|
canonical_var_info: CanonicalVarInfo<I>,
|
|
|
|
|
kind: CanonicalVarKind<I>,
|
|
|
|
|
) -> ty::BoundVar {
|
|
|
|
|
// FIXME: 16 is made up and arbitrary. We should look at some
|
|
|
|
|
// perf data here.
|
|
|
|
|
@@ -162,14 +162,14 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|
|
|
|
*self.variable_lookup_table.entry(arg).or_insert_with(|| {
|
|
|
|
|
let var = self.variables.len();
|
|
|
|
|
self.variables.push(arg);
|
|
|
|
|
self.primitive_var_infos.push(canonical_var_info);
|
|
|
|
|
self.var_kinds.push(kind);
|
|
|
|
|
var
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
self.variables.iter().position(|&v| v == arg).unwrap_or_else(|| {
|
|
|
|
|
let var = self.variables.len();
|
|
|
|
|
self.variables.push(arg);
|
|
|
|
|
self.primitive_var_infos.push(canonical_var_info);
|
|
|
|
|
self.var_kinds.push(kind);
|
|
|
|
|
var
|
|
|
|
|
})
|
|
|
|
|
};
|
|
|
|
|
@@ -177,8 +177,8 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|
|
|
|
ty::BoundVar::from(idx)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVars) {
|
|
|
|
|
let mut var_infos = self.primitive_var_infos;
|
|
|
|
|
fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVarKinds) {
|
|
|
|
|
let mut var_kinds = self.var_kinds;
|
|
|
|
|
// See the rustc-dev-guide section about how we deal with universes
|
|
|
|
|
// during canonicalization in the new solver.
|
|
|
|
|
match self.canonicalize_mode {
|
|
|
|
|
@@ -192,25 +192,25 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|
|
|
|
// information for placeholders and inference variables created inside
|
|
|
|
|
// of the query.
|
|
|
|
|
CanonicalizeMode::Response { max_input_universe } => {
|
|
|
|
|
for var in var_infos.iter_mut() {
|
|
|
|
|
for var in var_kinds.iter_mut() {
|
|
|
|
|
let uv = var.universe();
|
|
|
|
|
let new_uv = ty::UniverseIndex::from(
|
|
|
|
|
uv.index().saturating_sub(max_input_universe.index()),
|
|
|
|
|
);
|
|
|
|
|
*var = var.with_updated_universe(new_uv);
|
|
|
|
|
}
|
|
|
|
|
let max_universe = var_infos
|
|
|
|
|
let max_universe = var_kinds
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|info| info.universe())
|
|
|
|
|
.map(|kind| kind.universe())
|
|
|
|
|
.max()
|
|
|
|
|
.unwrap_or(ty::UniverseIndex::ROOT);
|
|
|
|
|
|
|
|
|
|
let var_infos = self.delegate.cx().mk_canonical_var_infos(&var_infos);
|
|
|
|
|
return (max_universe, var_infos);
|
|
|
|
|
let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds);
|
|
|
|
|
return (max_universe, var_kinds);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Given a `var_infos` with existentials `En` and universals `Un` in
|
|
|
|
|
// Given a `var_kinds` with existentials `En` and universals `Un` in
|
|
|
|
|
// universes `n`, this algorithm compresses them in place so that:
|
|
|
|
|
//
|
|
|
|
|
// - the new universe indices are as small as possible
|
|
|
|
|
@@ -219,12 +219,12 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|
|
|
|
// 2. put a placeholder in the same universe as an existential which cannot name it
|
|
|
|
|
//
|
|
|
|
|
// Let's walk through an example:
|
|
|
|
|
// - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 0
|
|
|
|
|
// - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 1
|
|
|
|
|
// - var_infos: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 1, next_orig_uv: 2
|
|
|
|
|
// - var_infos: [E0, U1, E5, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 5
|
|
|
|
|
// - var_infos: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6
|
|
|
|
|
// - var_infos: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: -
|
|
|
|
|
// - var_kinds: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 0
|
|
|
|
|
// - var_kinds: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 0, next_orig_uv: 1
|
|
|
|
|
// - var_kinds: [E0, U1, E5, U2, E2, E6, U6], curr_compressed_uv: 1, next_orig_uv: 2
|
|
|
|
|
// - var_kinds: [E0, U1, E5, U1, E1, E6, U6], curr_compressed_uv: 1, next_orig_uv: 5
|
|
|
|
|
// - var_kinds: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6
|
|
|
|
|
// - var_kinds: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: -
|
|
|
|
|
//
|
|
|
|
|
// This algorithm runs in `O(mn)` where `n` is the number of different universes and
|
|
|
|
|
// `m` the number of variables. This should be fine as both are expected to be small.
|
|
|
|
|
@@ -232,7 +232,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|
|
|
|
let mut existential_in_new_uv = None;
|
|
|
|
|
let mut next_orig_uv = Some(ty::UniverseIndex::ROOT);
|
|
|
|
|
while let Some(orig_uv) = next_orig_uv.take() {
|
|
|
|
|
let mut update_uv = |var: &mut CanonicalVarInfo<I>, orig_uv, is_existential| {
|
|
|
|
|
let mut update_uv = |var: &mut CanonicalVarKind<I>, orig_uv, is_existential| {
|
|
|
|
|
let uv = var.universe();
|
|
|
|
|
match uv.cmp(&orig_uv) {
|
|
|
|
|
Ordering::Less => (), // Already updated
|
|
|
|
|
@@ -284,7 +284,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|
|
|
|
// Whenever we compress the universe of a placeholder, no existential with
|
|
|
|
|
// an already compressed universe can name that placeholder.
|
|
|
|
|
for is_existential in [false, true] {
|
|
|
|
|
for var in var_infos.iter_mut() {
|
|
|
|
|
for var in var_kinds.iter_mut() {
|
|
|
|
|
// We simply put all regions from the input into the highest
|
|
|
|
|
// compressed universe, so we only deal with them at the end.
|
|
|
|
|
if !var.is_region() {
|
|
|
|
|
@@ -298,7 +298,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|
|
|
|
|
|
|
|
|
// We put all regions into a separate universe.
|
|
|
|
|
let mut first_region = true;
|
|
|
|
|
for var in var_infos.iter_mut() {
|
|
|
|
|
for var in var_kinds.iter_mut() {
|
|
|
|
|
if var.is_region() {
|
|
|
|
|
if first_region {
|
|
|
|
|
first_region = false;
|
|
|
|
|
@@ -309,8 +309,8 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let var_infos = self.delegate.cx().mk_canonical_var_infos(&var_infos);
|
|
|
|
|
(curr_compressed_uv, var_infos)
|
|
|
|
|
let var_kinds = self.delegate.cx().mk_canonical_var_kinds(&var_kinds);
|
|
|
|
|
(curr_compressed_uv, var_kinds)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn cached_fold_ty(&mut self, t: I::Ty) -> I::Ty {
|
|
|
|
|
@@ -391,7 +391,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let var = self.get_or_insert_bound_var(t, CanonicalVarInfo { kind });
|
|
|
|
|
let var = self.get_or_insert_bound_var(t, kind);
|
|
|
|
|
|
|
|
|
|
Ty::new_anon_bound(self.cx(), self.binder_index, var)
|
|
|
|
|
}
|
|
|
|
|
@@ -475,7 +475,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let var = self.get_or_insert_bound_var(r, CanonicalVarInfo { kind });
|
|
|
|
|
let var = self.get_or_insert_bound_var(r, kind);
|
|
|
|
|
|
|
|
|
|
Region::new_anon_bound(self.cx(), self.binder_index, var)
|
|
|
|
|
}
|
|
|
|
|
@@ -525,7 +525,7 @@ impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I> for Canonicaliz
|
|
|
|
|
| ty::ConstKind::Expr(_) => return c.super_fold_with(self),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let var = self.get_or_insert_bound_var(c, CanonicalVarInfo { kind });
|
|
|
|
|
let var = self.get_or_insert_bound_var(c, kind);
|
|
|
|
|
|
|
|
|
|
Const::new_anon_bound(self.cx(), self.binder_index, var)
|
|
|
|
|
}
|
|
|
|
|
|