Skip to content

Commit 9c27f27

Browse files
committed
Auto merge of #140375 - lcnr:subrelations-infcx, r=BoxyUwU
eagerly compute `sub_unification_table` again Previously called `sub_relations`. We still only using them for diagnostics right now. This mostly reverts #119989. Necessary for type inference guidance due to not-yet defined opaque types, cc rust-lang/trait-system-refactor-initiative#182. We could use them for cycle detection in generalization and it seems desirable to do so in the future. However, this is unsound with the old trait solver as its cache does not track these `sub_unification_table` in any way. We now properly track the `sub_unification_table` when canonicalizing so using them in the new solver is totally sound and the performance impact is far more manageable than I thought back in #119989. r? `@compiler-errors`
2 parents a78f9aa + b51a3a5 commit 9c27f27

File tree

33 files changed

+585
-570
lines changed

33 files changed

+585
-570
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4681,6 +4681,7 @@ dependencies = [
46814681
name = "rustc_type_ir"
46824682
version = "0.0.0"
46834683
dependencies = [
4684+
"arrayvec",
46844685
"bitflags",
46854686
"derive-where",
46864687
"ena",

compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
2121
use rustc_session::Session;
2222
use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym};
2323
use rustc_trait_selection::error_reporting::TypeErrCtxt;
24-
use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations;
2524
use rustc_trait_selection::traits::{
2625
self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt,
2726
};
@@ -188,14 +187,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
188187
///
189188
/// [`InferCtxtErrorExt::err_ctxt`]: rustc_trait_selection::error_reporting::InferCtxtErrorExt::err_ctxt
190189
pub(crate) fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
191-
let mut sub_relations = SubRelations::default();
192-
sub_relations.add_constraints(
193-
self,
194-
self.fulfillment_cx.borrow_mut().pending_obligations().iter().map(|o| o.predicate),
195-
);
196190
TypeErrCtxt {
197191
infcx: &self.infcx,
198-
sub_relations: RefCell::new(sub_relations),
199192
typeck_results: Some(self.typeck_results.borrow()),
200193
fallback_has_occurred: self.fallback_has_occurred.get(),
201194
normalize_fn_sig: Box::new(|fn_sig| {

compiler/rustc_hir_typeck/src/method/probe.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -403,15 +403,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
403403
// special handling for this "trivial case" is a good idea.
404404

405405
let infcx = &self.infcx;
406-
let (ParamEnvAnd { param_env: _, value: self_ty }, canonical_inference_vars) =
406+
let (ParamEnvAnd { param_env: _, value: self_ty }, var_values) =
407407
infcx.instantiate_canonical(span, &query_input.canonical);
408408
debug!(?self_ty, ?query_input, "probe_op: Mode::Path");
409409
MethodAutoderefStepsResult {
410410
steps: infcx.tcx.arena.alloc_from_iter([CandidateStep {
411-
self_ty: self.make_query_response_ignoring_pending_obligations(
412-
canonical_inference_vars,
413-
self_ty,
414-
),
411+
self_ty: self
412+
.make_query_response_ignoring_pending_obligations(var_values, self_ty),
415413
autoderefs: 0,
416414
from_unsafe_deref: false,
417415
unsize: false,

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

Lines changed: 24 additions & 10 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::{
@@ -17,7 +18,7 @@ use tracing::debug;
1718

1819
use crate::infer::InferCtxt;
1920
use crate::infer::canonical::{
20-
Canonical, CanonicalQueryInput, CanonicalTyVarKind, CanonicalVarKind, OriginalQueryValues,
21+
Canonical, CanonicalQueryInput, CanonicalVarKind, OriginalQueryValues,
2122
};
2223

2324
impl<'tcx> InferCtxt<'tcx> {
@@ -293,6 +294,13 @@ 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+
/// Maps each `sub_unification_table_root_var` to the index of the first
298+
/// variable which used it.
299+
///
300+
/// This means in case two type variables have the same sub relations root,
301+
/// we set the `sub_root` of the second variable to the position of the first.
302+
/// Otherwise the `sub_root` of each type variable is just its own position.
303+
sub_root_lookup_table: SsoHashMap<ty::TyVid, usize>,
296304
canonicalize_mode: &'cx dyn CanonicalizeMode,
297305
needs_canonical_flags: TypeFlags,
298306

@@ -361,10 +369,8 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
361369
// FIXME: perf problem described in #55921.
362370
ui = ty::UniverseIndex::ROOT;
363371
}
364-
self.canonicalize_ty_var(
365-
CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
366-
t,
367-
)
372+
let sub_root = self.get_or_insert_sub_root(vid);
373+
self.canonicalize_ty_var(CanonicalVarKind::Ty { ui, sub_root }, t)
368374
}
369375
}
370376
}
@@ -374,15 +380,15 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
374380
if nt != t {
375381
return self.fold_ty(nt);
376382
} else {
377-
self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Int), t)
383+
self.canonicalize_ty_var(CanonicalVarKind::Int, t)
378384
}
379385
}
380386
ty::Infer(ty::FloatVar(vid)) => {
381387
let nt = self.infcx.unwrap().opportunistic_resolve_float_var(vid);
382388
if nt != t {
383389
return self.fold_ty(nt);
384390
} else {
385-
self.canonicalize_ty_var(CanonicalVarKind::Ty(CanonicalTyVarKind::Float), t)
391+
self.canonicalize_ty_var(CanonicalVarKind::Float, t)
386392
}
387393
}
388394

@@ -562,6 +568,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
562568
variables: SmallVec::from_slice(base.variables),
563569
query_state,
564570
indices: FxHashMap::default(),
571+
sub_root_lookup_table: Default::default(),
565572
binder_index: ty::INNERMOST,
566573
};
567574
if canonicalizer.query_state.var_values.spilled() {
@@ -660,6 +667,13 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
660667
}
661668
}
662669

670+
fn get_or_insert_sub_root(&mut self, vid: ty::TyVid) -> ty::BoundVar {
671+
let root_vid = self.infcx.unwrap().sub_unification_table_root_var(vid);
672+
let idx =
673+
*self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.variables.len());
674+
ty::BoundVar::from(idx)
675+
}
676+
663677
/// Replaces the universe indexes used in `var_values` with their index in
664678
/// `query_state.universe_map`. This minimizes the maximum universe used in
665679
/// the canonicalized value.
@@ -679,11 +693,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
679693
self.variables
680694
.iter()
681695
.map(|&kind| match kind {
682-
CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
696+
CanonicalVarKind::Int | CanonicalVarKind::Float => {
683697
return kind;
684698
}
685-
CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
686-
CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
699+
CanonicalVarKind::Ty { ui, sub_root } => {
700+
CanonicalVarKind::Ty { ui: reverse_universe_map[&ui], sub_root }
687701
}
688702
CanonicalVarKind::Region(u) => CanonicalVarKind::Region(reverse_universe_map[&u]),
689703
CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]),

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

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
pub use instantiate::CanonicalExt;
2525
use rustc_index::IndexVec;
2626
pub use rustc_middle::infer::canonical::*;
27-
use rustc_middle::ty::{self, GenericArg, List, Ty, TyCtxt, TypeFoldable};
27+
use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt, TypeFoldable};
2828
use rustc_span::Span;
2929

3030
use crate::infer::{InferCtxt, RegionVariableOrigin};
@@ -67,30 +67,12 @@ impl<'tcx> InferCtxt<'tcx> {
6767
.chain((1..=canonical.max_universe.as_u32()).map(|_| self.create_next_universe()))
6868
.collect();
6969

70-
let canonical_inference_vars =
71-
self.instantiate_canonical_vars(span, canonical.variables, |ui| universes[ui]);
72-
let result = canonical.instantiate(self.tcx, &canonical_inference_vars);
73-
(result, canonical_inference_vars)
74-
}
75-
76-
/// Given the "infos" about the canonical variables from some
77-
/// canonical, creates fresh variables with the same
78-
/// characteristics (see `instantiate_canonical_var` for
79-
/// details). You can then use `instantiate` to instantiate the
80-
/// canonical variable with these inference variables.
81-
fn instantiate_canonical_vars(
82-
&self,
83-
span: Span,
84-
variables: &List<CanonicalVarKind<'tcx>>,
85-
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
86-
) -> 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-
),
93-
}
70+
let var_values =
71+
CanonicalVarValues::instantiate(self.tcx, &canonical.variables, |var_values, info| {
72+
self.instantiate_canonical_var(span, info, &var_values, |ui| universes[ui])
73+
});
74+
let result = canonical.instantiate(self.tcx, &var_values);
75+
(result, var_values)
9476
}
9577

9678
/// Given the "info" about a canonical variable, creates a fresh
@@ -105,21 +87,27 @@ impl<'tcx> InferCtxt<'tcx> {
10587
&self,
10688
span: Span,
10789
kind: CanonicalVarKind<'tcx>,
90+
previous_var_values: &[GenericArg<'tcx>],
10891
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
10992
) -> GenericArg<'tcx> {
11093
match kind {
111-
CanonicalVarKind::Ty(ty_kind) => {
112-
let ty = match ty_kind {
113-
CanonicalTyVarKind::General(ui) => {
114-
self.next_ty_var_in_universe(span, universe_map(ui))
94+
CanonicalVarKind::Ty { ui, sub_root } => {
95+
let vid = self.next_ty_vid_in_universe(span, universe_map(ui));
96+
// If this inference variable is related to an earlier variable
97+
// via subtyping, we need to add that info to the inference context.
98+
if let Some(prev) = previous_var_values.get(sub_root.as_usize()) {
99+
if let &ty::Infer(ty::TyVar(sub_root)) = prev.expect_ty().kind() {
100+
self.sub_unify_ty_vids_raw(vid, sub_root);
101+
} else {
102+
unreachable!()
115103
}
104+
}
105+
Ty::new_var(self.tcx, vid).into()
106+
}
116107

117-
CanonicalTyVarKind::Int => self.next_int_var(),
108+
CanonicalVarKind::Int => self.next_int_var().into(),
118109

119-
CanonicalTyVarKind::Float => self.next_float_var(),
120-
};
121-
ty.into()
122-
}
110+
CanonicalVarKind::Float => self.next_float_var().into(),
123111

124112
CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, bound }) => {
125113
let universe_mapped = universe_map(universe);

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

Lines changed: 37 additions & 40 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

@@ -413,35 +414,34 @@ impl<'tcx> InferCtxt<'tcx> {
413414
let mut opt_values: IndexVec<BoundVar, Option<GenericArg<'tcx>>> =
414415
IndexVec::from_elem_n(None, query_response.variables.len());
415416

416-
// In terms of our example above, we are iterating over pairs like:
417-
// [(?A, Vec<?0>), ('static, '?1), (?B, ?0)]
418417
for (original_value, result_value) in iter::zip(&original_values.var_values, result_values)
419418
{
420419
match result_value.kind() {
421420
GenericArgKind::Type(result_value) => {
422-
// e.g., here `result_value` might be `?0` in the example above...
423-
if let ty::Bound(debruijn, b) = *result_value.kind() {
424-
// ...in which case we would set `canonical_vars[0]` to `Some(?U)`.
425-
421+
// We disable the instantiation guess for inference variables
422+
// and only use it for placeholders. We need to handle the
423+
// `sub_root` of type inference variables which would make this
424+
// more involved. They are also a lot rarer than region variables.
425+
if let ty::Bound(debruijn, b) = *result_value.kind()
426+
&& !matches!(
427+
query_response.variables[b.var.as_usize()],
428+
CanonicalVarKind::Ty { .. }
429+
)
430+
{
426431
// We only allow a `ty::INNERMOST` index in generic parameters.
427432
assert_eq!(debruijn, ty::INNERMOST);
428433
opt_values[b.var] = Some(*original_value);
429434
}
430435
}
431436
GenericArgKind::Lifetime(result_value) => {
432-
// e.g., here `result_value` might be `'?1` in the example above...
433437
if let ty::ReBound(debruijn, b) = result_value.kind() {
434-
// ... in which case we would set `canonical_vars[0]` to `Some('static)`.
435-
436438
// We only allow a `ty::INNERMOST` index in generic parameters.
437439
assert_eq!(debruijn, ty::INNERMOST);
438440
opt_values[b.var] = Some(*original_value);
439441
}
440442
}
441443
GenericArgKind::Const(result_value) => {
442444
if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() {
443-
// ...in which case we would set `canonical_vars[0]` to `Some(const X)`.
444-
445445
// We only allow a `ty::INNERMOST` index in generic parameters.
446446
assert_eq!(debruijn, ty::INNERMOST);
447447
opt_values[b.var] = Some(*original_value);
@@ -453,39 +453,36 @@ impl<'tcx> InferCtxt<'tcx> {
453453
// Create result arguments: if we found a value for a
454454
// given variable in the loop above, use that. Otherwise, use
455455
// 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-
};
456+
let tcx = self.tcx;
457+
let variables = query_response.variables;
458+
let var_values = CanonicalVarValues::instantiate(tcx, variables, |var_values, kind| {
459+
if 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, kind, &var_values, |u| {
463+
universe_map[u.as_usize()]
464+
})
465+
} else if kind.is_existential() {
466+
match opt_values[BoundVar::new(var_values.len())] {
467+
Some(k) => k,
468+
None => self.instantiate_canonical_var(cause.span, kind, &var_values, |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(var_values.len())]
476+
.expect("expected placeholder to be unified with itself during response")
477+
}
478+
});
482479

483480
let mut obligations = PredicateObligations::new();
484481

485482
// Carry all newly resolved opaque types to the caller's scope
486483
for &(a, b) in &query_response.value.opaque_types {
487-
let a = instantiate_value(self.tcx, &result_args, a);
488-
let b = instantiate_value(self.tcx, &result_args, b);
484+
let a = instantiate_value(self.tcx, &var_values, a);
485+
let b = instantiate_value(self.tcx, &var_values, b);
489486
debug!(?a, ?b, "constrain opaque type");
490487
// We use equate here instead of, for example, just registering the
491488
// opaque type's hidden value directly, because the hidden type may have been an inference
@@ -502,7 +499,7 @@ impl<'tcx> InferCtxt<'tcx> {
502499
);
503500
}
504501

505-
Ok(InferOk { value: result_args, obligations })
502+
Ok(InferOk { value: var_values, obligations })
506503
}
507504

508505
/// Given a "guess" at the values for the canonical variables in

compiler/rustc_infer/src/infer/context.rs

Lines changed: 8 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_unification_table_root_var(&self, var: ty::TyVid) -> ty::TyVid {
63+
self.sub_unification_table_root_var(var)
64+
}
65+
6266
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
6367
self.root_const_var(var)
6468
}
@@ -179,6 +183,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
179183
self.inner.borrow_mut().type_variables().equate(a, b);
180184
}
181185

186+
fn sub_unify_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) {
187+
self.sub_unify_ty_vids_raw(a, b);
188+
}
189+
182190
fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid) {
183191
self.inner.borrow_mut().int_unification_table().union(a, b);
184192
}

0 commit comments

Comments
 (0)