Skip to content

Commit 739367a

Browse files
committed
pass sub_relations into canonical queries
1 parent 3246a20 commit 739367a

File tree

13 files changed

+325
-308
lines changed

13 files changed

+325
-308
lines changed

compiler/rustc_infer/src/infer/canonical/canonicalizer.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
77
88
use rustc_data_structures::fx::FxHashMap;
9+
use rustc_data_structures::sso::SsoHashMap;
910
use rustc_index::Idx;
1011
use rustc_middle::bug;
1112
use rustc_middle::ty::{
@@ -293,6 +294,7 @@ struct Canonicalizer<'cx, 'tcx> {
293294
// Note that indices is only used once `var_values` is big enough to be
294295
// heap-allocated.
295296
indices: FxHashMap<GenericArg<'tcx>, BoundVar>,
297+
sub_root_lookup_table: SsoHashMap<ty::TyVid, usize>,
296298
canonicalize_mode: &'cx dyn CanonicalizeMode,
297299
needs_canonical_flags: TypeFlags,
298300

@@ -361,7 +363,8 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
361363
// FIXME: perf problem described in #55921.
362364
ui = ty::UniverseIndex::ROOT;
363365
}
364-
self.canonicalize_ty_var(CanonicalVarKind::Ty(ui), t)
366+
let sub_root = self.get_or_insert_sub_root(vid);
367+
self.canonicalize_ty_var(CanonicalVarKind::Ty { ui, sub_root }, t)
365368
}
366369
}
367370
}
@@ -559,6 +562,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
559562
variables: SmallVec::from_slice(base.variables),
560563
query_state,
561564
indices: FxHashMap::default(),
565+
sub_root_lookup_table: Default::default(),
562566
binder_index: ty::INNERMOST,
563567
};
564568
if canonicalizer.query_state.var_values.spilled() {
@@ -657,6 +661,13 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
657661
}
658662
}
659663

664+
fn get_or_insert_sub_root(&mut self, vid: ty::TyVid) -> ty::BoundVar {
665+
let root_vid = self.infcx.unwrap().sub_root_var(vid);
666+
let idx =
667+
*self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.variables.len());
668+
ty::BoundVar::from(idx)
669+
}
670+
660671
/// Replaces the universe indexes used in `var_values` with their index in
661672
/// `query_state.universe_map`. This minimizes the maximum universe used in
662673
/// the canonicalized value.
@@ -679,7 +690,9 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
679690
CanonicalVarKind::Int | CanonicalVarKind::Float => {
680691
return kind;
681692
}
682-
CanonicalVarKind::Ty(u) => CanonicalVarKind::Ty(reverse_universe_map[&u]),
693+
CanonicalVarKind::Ty { ui, sub_root } => {
694+
CanonicalVarKind::Ty { ui: reverse_universe_map[&ui], sub_root }
695+
}
683696
CanonicalVarKind::Region(u) => CanonicalVarKind::Region(reverse_universe_map[&u]),
684697
CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]),
685698
CanonicalVarKind::PlaceholderTy(placeholder) => {

compiler/rustc_infer/src/infer/canonical/mod.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,12 @@ impl<'tcx> InferCtxt<'tcx> {
8484
variables: &List<CanonicalVarKind<'tcx>>,
8585
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
8686
) -> CanonicalVarValues<'tcx> {
87-
CanonicalVarValues {
88-
var_values: self.tcx.mk_args_from_iter(
89-
variables
90-
.iter()
91-
.map(|kind| self.instantiate_canonical_var(span, kind, &universe_map)),
92-
),
87+
let mut var_values = Vec::with_capacity(variables.len());
88+
for info in variables.iter() {
89+
let value = self.instantiate_canonical_var(span, info, &var_values, &universe_map);
90+
var_values.push(value);
9391
}
92+
CanonicalVarValues { var_values: self.tcx.mk_args(&var_values) }
9493
}
9594

9695
/// Given the "info" about a canonical variable, creates a fresh
@@ -105,10 +104,22 @@ impl<'tcx> InferCtxt<'tcx> {
105104
&self,
106105
span: Span,
107106
kind: CanonicalVarKind<'tcx>,
107+
previous_var_values: &[GenericArg<'tcx>],
108108
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
109109
) -> GenericArg<'tcx> {
110110
match kind {
111-
CanonicalVarKind::Ty(ui) => self.next_ty_var_in_universe(span, universe_map(ui)).into(),
111+
CanonicalVarKind::Ty { ui, sub_root } => {
112+
let vid = self.next_ty_vid_in_universe(span, universe_map(ui));
113+
// Fetch the `sub_root` in case it exists.
114+
if let Some(prev) = previous_var_values.get(sub_root.as_usize()) {
115+
if let &ty::Infer(ty::TyVar(sub_root)) = prev.expect_ty().kind() {
116+
self.inner.borrow_mut().type_variables().sub(vid, sub_root);
117+
} else {
118+
unreachable!()
119+
}
120+
}
121+
Ty::new_var(self.tcx, vid).into()
122+
}
112123

113124
CanonicalVarKind::Int => self.next_int_var().into(),
114125

compiler/rustc_infer/src/infer/canonical/query_response.rs

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use std::iter;
1313
use rustc_index::{Idx, IndexVec};
1414
use rustc_middle::arena::ArenaAllocatable;
1515
use rustc_middle::bug;
16+
use rustc_middle::infer::canonical::CanonicalVarKind;
1617
use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable};
1718
use tracing::{debug, instrument};
1819

@@ -420,7 +421,12 @@ impl<'tcx> InferCtxt<'tcx> {
420421
match result_value.kind() {
421422
GenericArgKind::Type(result_value) => {
422423
// e.g., here `result_value` might be `?0` in the example above...
423-
if let ty::Bound(debruijn, b) = *result_value.kind() {
424+
if let ty::Bound(debruijn, b) = *result_value.kind()
425+
&& !matches!(
426+
query_response.variables[b.var.as_usize()],
427+
CanonicalVarKind::Ty { .. }
428+
)
429+
{
424430
// ...in which case we would set `canonical_vars[0]` to `Some(?U)`.
425431

426432
// We only allow a `ty::INNERMOST` index in generic parameters.
@@ -453,32 +459,31 @@ impl<'tcx> InferCtxt<'tcx> {
453459
// Create result arguments: if we found a value for a
454460
// given variable in the loop above, use that. Otherwise, use
455461
// a fresh inference variable.
456-
let result_args = CanonicalVarValues {
457-
var_values: self.tcx.mk_args_from_iter(
458-
query_response.variables.iter().enumerate().map(|(index, var_kind)| {
459-
if var_kind.universe() != ty::UniverseIndex::ROOT {
460-
// A variable from inside a binder of the query. While ideally these shouldn't
461-
// exist at all, we have to deal with them for now.
462-
self.instantiate_canonical_var(cause.span, var_kind, |u| {
463-
universe_map[u.as_usize()]
464-
})
465-
} else if var_kind.is_existential() {
466-
match opt_values[BoundVar::new(index)] {
467-
Some(k) => k,
468-
None => self.instantiate_canonical_var(cause.span, var_kind, |u| {
469-
universe_map[u.as_usize()]
470-
}),
471-
}
472-
} else {
473-
// For placeholders which were already part of the input, we simply map this
474-
// universal bound variable back the placeholder of the input.
475-
opt_values[BoundVar::new(index)].expect(
476-
"expected placeholder to be unified with itself during response",
477-
)
478-
}
479-
}),
480-
),
481-
};
462+
let mut var_values = Vec::with_capacity(query_response.variables.len());
463+
for (index, kind) in query_response.variables.iter().enumerate() {
464+
let value = if kind.universe() != ty::UniverseIndex::ROOT {
465+
// A variable from inside a binder of the query. While ideally these shouldn't
466+
// exist at all, we have to deal with them for now.
467+
self.instantiate_canonical_var(cause.span, kind, &var_values, |u| {
468+
universe_map[u.as_usize()]
469+
})
470+
} else if kind.is_existential() {
471+
match opt_values[BoundVar::new(index)] {
472+
Some(k) => k,
473+
None => self.instantiate_canonical_var(cause.span, kind, &var_values, |u| {
474+
universe_map[u.as_usize()]
475+
}),
476+
}
477+
} else {
478+
// For placeholders which were already part of the input, we simply map this
479+
// universal bound variable back the placeholder of the input.
480+
opt_values[BoundVar::new(index)]
481+
.expect("expected placeholder to be unified with itself during response")
482+
};
483+
var_values.push(value);
484+
}
485+
486+
let result_args = CanonicalVarValues { var_values: self.tcx.mk_args(&var_values) };
482487

483488
let mut obligations = PredicateObligations::new();
484489

compiler/rustc_infer/src/infer/context.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
5959
self.root_var(var)
6060
}
6161

62+
fn sub_root_ty_var(&self, var: ty::TyVid) -> ty::TyVid {
63+
self.sub_root_var(var)
64+
}
65+
6266
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
6367
self.root_const_var(var)
6468
}

compiler/rustc_next_trait_solver/src/canonicalizer.rs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ pub struct Canonicalizer<'a, D: SolverDelegate<Interner = I>, I: Interner> {
6767
variables: &'a mut Vec<I::GenericArg>,
6868
var_kinds: Vec<CanonicalVarKind<I>>,
6969
variable_lookup_table: HashMap<I::GenericArg, usize>,
70+
sub_root_lookup_table: HashMap<ty::TyVid, usize>,
7071
binder_index: ty::DebruijnIndex,
7172

7273
/// We only use the debruijn index during lookup. We don't need to
@@ -88,6 +89,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
8889

8990
variables,
9091
variable_lookup_table: Default::default(),
92+
sub_root_lookup_table: Default::default(),
9193
var_kinds: Vec::new(),
9294
binder_index: ty::INNERMOST,
9395

@@ -132,13 +134,15 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
132134

133135
variables: &mut variables,
134136
variable_lookup_table: Default::default(),
137+
sub_root_lookup_table: Default::default(),
135138
var_kinds: Vec::new(),
136139
binder_index: ty::INNERMOST,
137140

138141
cache: Default::default(),
139142
};
140143
let param_env = param_env.fold_with(&mut env_canonicalizer);
141144
debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST);
145+
debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty());
142146
CanonicalParamEnvCacheEntry {
143147
param_env,
144148
variable_lookup_table: env_canonicalizer.variable_lookup_table,
@@ -164,13 +168,15 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
164168

165169
variables,
166170
variable_lookup_table: Default::default(),
171+
sub_root_lookup_table: Default::default(),
167172
var_kinds: Vec::new(),
168173
binder_index: ty::INNERMOST,
169174

170175
cache: Default::default(),
171176
};
172177
let param_env = param_env.fold_with(&mut env_canonicalizer);
173178
debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST);
179+
debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty());
174180
(param_env, env_canonicalizer.variable_lookup_table, env_canonicalizer.var_kinds)
175181
}
176182
}
@@ -199,6 +205,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
199205

200206
variables,
201207
variable_lookup_table,
208+
sub_root_lookup_table: Default::default(),
202209
var_kinds,
203210
binder_index: ty::INNERMOST,
204211

@@ -265,6 +272,13 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
265272
ty::BoundVar::from(idx)
266273
}
267274

275+
fn get_or_insert_sub_root(&mut self, vid: ty::TyVid) -> ty::BoundVar {
276+
let root_vid = self.delegate.sub_root_ty_var(vid);
277+
let idx =
278+
*self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.variables.len());
279+
ty::BoundVar::from(idx)
280+
}
281+
268282
fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVarKinds) {
269283
let mut var_kinds = self.var_kinds;
270284
// See the rustc-dev-guide section about how we deal with universes
@@ -312,16 +326,15 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
312326
"ty vid should have been resolved fully before canonicalization"
313327
);
314328

315-
match self.canonicalize_mode {
316-
CanonicalizeMode::Input { .. } => {
317-
CanonicalVarKind::Ty(ty::UniverseIndex::ROOT)
318-
}
319-
CanonicalizeMode::Response { .. } => {
320-
CanonicalVarKind::Ty(self.delegate.universe_of_ty(vid).unwrap_or_else(
321-
|| panic!("ty var should have been resolved: {t:?}"),
322-
))
323-
}
324-
}
329+
let sub_root = self.get_or_insert_sub_root(vid);
330+
let ui = match self.canonicalize_mode {
331+
CanonicalizeMode::Input { .. } => ty::UniverseIndex::ROOT,
332+
CanonicalizeMode::Response { .. } => self
333+
.delegate
334+
.universe_of_ty(vid)
335+
.unwrap_or_else(|| panic!("ty var should have been resolved: {t:?}")),
336+
};
337+
CanonicalVarKind::Ty { ui, sub_root }
325338
}
326339
ty::IntVar(vid) => {
327340
debug_assert_eq!(

compiler/rustc_next_trait_solver/src/delegate.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,14 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
5757
where
5858
V: TypeFoldable<Self::Interner>;
5959

60-
fn instantiate_canonical_var_with_infer(
60+
fn instantiate_canonical_var(
6161
&self,
6262
kind: ty::CanonicalVarKind<Self::Interner>,
6363
span: <Self::Interner as Interner>::Span,
64+
var_values: &[<Self::Interner as Interner>::GenericArg],
6465
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
6566
) -> <Self::Interner as Interner>::GenericArg;
67+
6668
fn add_item_bounds_for_hidden_type(
6769
&self,
6870
def_id: <Self::Interner as Interner>::DefId,

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ use rustc_type_ir::data_structures::HashSet;
1616
use rustc_type_ir::inherent::*;
1717
use rustc_type_ir::relate::solver_relating::RelateExt;
1818
use rustc_type_ir::{
19-
self as ty, Canonical, CanonicalVarValues, InferCtxtLike, Interner, TypeFoldable,
19+
self as ty, Canonical, CanonicalVarKind, CanonicalVarValues, InferCtxtLike, Interner,
20+
TypeFoldable,
2021
};
2122
use tracing::{debug, instrument, trace};
2223

@@ -340,7 +341,12 @@ where
340341
{
341342
match result_value.kind() {
342343
ty::GenericArgKind::Type(t) => {
343-
if let ty::Bound(debruijn, b) = t.kind() {
344+
if let ty::Bound(debruijn, b) = t.kind()
345+
&& !matches!(
346+
response.variables.get(b.var().as_usize()).unwrap(),
347+
CanonicalVarKind::Ty { .. }
348+
)
349+
{
344350
assert_eq!(debruijn, ty::INNERMOST);
345351
opt_values[b.var()] = Some(*original_value);
346352
}
@@ -360,38 +366,37 @@ where
360366
}
361367
}
362368

363-
let var_values = delegate.cx().mk_args_from_iter(
364-
response.variables.iter().enumerate().map(|(index, var_kind)| {
365-
if var_kind.universe() != ty::UniverseIndex::ROOT {
366-
// A variable from inside a binder of the query. While ideally these shouldn't
367-
// exist at all (see the FIXME at the start of this method), we have to deal with
368-
// them for now.
369-
delegate.instantiate_canonical_var_with_infer(var_kind, span, |idx| {
370-
prev_universe + idx.index()
371-
})
372-
} else if var_kind.is_existential() {
373-
// As an optimization we sometimes avoid creating a new inference variable here.
374-
//
375-
// All new inference variables we create start out in the current universe of the caller.
376-
// This is conceptually wrong as these inference variables would be able to name
377-
// more placeholders then they should be able to. However the inference variables have
378-
// to "come from somewhere", so by equating them with the original values of the caller
379-
// later on, we pull them down into their correct universe again.
380-
if let Some(v) = opt_values[ty::BoundVar::from_usize(index)] {
381-
v
382-
} else {
383-
delegate
384-
.instantiate_canonical_var_with_infer(var_kind, span, |_| prev_universe)
385-
}
369+
let mut var_values = Vec::with_capacity(response.variables.len());
370+
for (index, kind) in response.variables.iter().enumerate() {
371+
let value = if kind.universe() != ty::UniverseIndex::ROOT {
372+
// A variable from inside a binder of the query. While ideally these shouldn't
373+
// exist at all (see the FIXME at the start of this method), we have to deal with
374+
// them for now.
375+
delegate.instantiate_canonical_var(kind, span, &var_values, |idx| {
376+
prev_universe + idx.index()
377+
})
378+
} else if kind.is_existential() {
379+
// As an optimization we sometimes avoid creating a new inference variable here.
380+
//
381+
// All new inference variables we create start out in the current universe of the caller.
382+
// This is conceptually wrong as these inference variables would be able to name
383+
// more placeholders then they should be able to. However the inference variables have
384+
// to "come from somewhere", so by equating them with the original values of the caller
385+
// later on, we pull them down into their correct universe again.
386+
if let Some(v) = opt_values[ty::BoundVar::from_usize(index)] {
387+
v
386388
} else {
387-
// For placeholders which were already part of the input, we simply map this
388-
// universal bound variable back the placeholder of the input.
389-
original_values[var_kind.expect_placeholder_index()]
389+
delegate.instantiate_canonical_var(kind, span, &var_values, |_| prev_universe)
390390
}
391-
}),
392-
);
391+
} else {
392+
// For placeholders which were already part of the input, we simply map this
393+
// universal bound variable back the placeholder of the input.
394+
original_values[kind.expect_placeholder_index()]
395+
};
396+
var_values.push(value)
397+
}
393398

394-
CanonicalVarValues { var_values }
399+
CanonicalVarValues { var_values: delegate.cx().mk_args(&var_values) }
395400
}
396401

397402
/// Unify the `original_values` with the `var_values` returned by the canonical query..

0 commit comments

Comments
 (0)