Skip to content

Commit bbf9bd9

Browse files
committed
Auto merge of rust-lang#140752 - lcnr:subrelations-infcx-perf-2, r=<try>
[PERF] eagerly compute `sub_relations` again perf run for rust-lang#140375 r? ghost
2 parents 3ef8e64 + df02bca commit bbf9bd9

File tree

24 files changed

+308
-246
lines changed

24 files changed

+308
-246
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

-7
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
1919
use rustc_session::Session;
2020
use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym};
2121
use rustc_trait_selection::error_reporting::TypeErrCtxt;
22-
use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations;
2322
use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
2423

2524
use crate::coercion::DynamicCoerceMany;
@@ -177,14 +176,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
177176
///
178177
/// [`InferCtxtErrorExt::err_ctxt`]: rustc_trait_selection::error_reporting::InferCtxtErrorExt::err_ctxt
179178
pub(crate) fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
180-
let mut sub_relations = SubRelations::default();
181-
sub_relations.add_constraints(
182-
self,
183-
self.fulfillment_cx.borrow_mut().pending_obligations().iter().map(|o| o.predicate),
184-
);
185179
TypeErrCtxt {
186180
infcx: &self.infcx,
187-
sub_relations: RefCell::new(sub_relations),
188181
typeck_results: Some(self.typeck_results.borrow()),
189182
fallback_has_occurred: self.fallback_has_occurred.get(),
190183
normalize_fn_sig: Box::new(|fn_sig| {

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

+18-14
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,8 +18,7 @@ use tracing::debug;
1718

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

2424
impl<'tcx> InferCtxt<'tcx> {
@@ -299,6 +299,7 @@ struct Canonicalizer<'cx, 'tcx> {
299299
// Note that indices is only used once `var_values` is big enough to be
300300
// heap-allocated.
301301
indices: FxHashMap<GenericArg<'tcx>, BoundVar>,
302+
sub_root_lookup_table: SsoHashMap<ty::TyVid, usize>,
302303
canonicalize_mode: &'cx dyn CanonicalizeMode,
303304
needs_canonical_flags: TypeFlags,
304305

@@ -367,9 +368,10 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
367368
// FIXME: perf problem described in #55921.
368369
ui = ty::UniverseIndex::ROOT;
369370
}
371+
let sub_root = self.get_or_insert_sub_root(vid);
370372
self.canonicalize_ty_var(
371373
CanonicalVarInfo {
372-
kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
374+
kind: CanonicalVarKind::Ty { universe: ui, sub_root },
373375
},
374376
t,
375377
)
@@ -382,21 +384,15 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
382384
if nt != t {
383385
return self.fold_ty(nt);
384386
} else {
385-
self.canonicalize_ty_var(
386-
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
387-
t,
388-
)
387+
self.canonicalize_ty_var(CanonicalVarInfo { kind: CanonicalVarKind::Int }, t)
389388
}
390389
}
391390
ty::Infer(ty::FloatVar(vid)) => {
392391
let nt = self.infcx.unwrap().opportunistic_resolve_float_var(vid);
393392
if nt != t {
394393
return self.fold_ty(nt);
395394
} else {
396-
self.canonicalize_ty_var(
397-
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
398-
t,
399-
)
395+
self.canonicalize_ty_var(CanonicalVarInfo { kind: CanonicalVarKind::Float }, t)
400396
}
401397
}
402398

@@ -576,6 +572,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
576572
variables: SmallVec::from_slice(base.variables),
577573
query_state,
578574
indices: FxHashMap::default(),
575+
sub_root_lookup_table: Default::default(),
579576
binder_index: ty::INNERMOST,
580577
};
581578
if canonicalizer.query_state.var_values.spilled() {
@@ -670,6 +667,13 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
670667
}
671668
}
672669

670+
fn get_or_insert_sub_root(&mut self, vid: ty::TyVid) -> ty::BoundVar {
671+
let root_vid = self.infcx.unwrap().sub_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+
673677
/// Replaces the universe indexes used in `var_values` with their index in
674678
/// `query_state.universe_map`. This minimizes the maximum universe used in
675679
/// the canonicalized value.
@@ -690,11 +694,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
690694
.iter()
691695
.map(|v| CanonicalVarInfo {
692696
kind: match v.kind {
693-
CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
697+
CanonicalVarKind::Int | CanonicalVarKind::Float => {
694698
return *v;
695699
}
696-
CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
697-
CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
700+
CanonicalVarKind::Ty { universe, sub_root } => {
701+
CanonicalVarKind::Ty { universe: reverse_universe_map[&universe], sub_root }
698702
}
699703
CanonicalVarKind::Region(u) => {
700704
CanonicalVarKind::Region(reverse_universe_map[&u])

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

+18-16
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,12 @@ impl<'tcx> InferCtxt<'tcx> {
8484
variables: &List<CanonicalVarInfo<'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(|info| self.instantiate_canonical_var(span, info, &universe_map)),
92-
),
87+
let mut var_values = Vec::new();
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,21 +104,24 @@ impl<'tcx> InferCtxt<'tcx> {
105104
&self,
106105
span: Span,
107106
cv_info: CanonicalVarInfo<'tcx>,
107+
previous_var_values: &[GenericArg<'tcx>],
108108
universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex,
109109
) -> GenericArg<'tcx> {
110110
match cv_info.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))
111+
CanonicalVarKind::Ty { universe, sub_root } => {
112+
let vid = self.next_ty_var_id_in_universe(span, universe_map(universe));
113+
if let Some(prev) = previous_var_values.get(sub_root.as_usize()) {
114+
// We cannot simply assume that previous `var_values` get instantiated
115+
// with inference variables as we may reuse the generic arguments from the
116+
// input which may have gotten constrained after we've canonicalized it.
117+
if let &ty::Infer(ty::TyVar(sub_root)) = prev.expect_ty().kind() {
118+
self.inner.borrow_mut().type_variables().sub(vid, sub_root);
115119
}
116-
117-
CanonicalTyVarKind::Int => self.next_int_var(),
118-
119-
CanonicalTyVarKind::Float => self.next_float_var(),
120-
};
121-
ty.into()
120+
}
121+
Ty::new_var(self.tcx, vid).into()
122122
}
123+
CanonicalVarKind::Int => self.next_int_var().into(),
124+
CanonicalVarKind::Float => self.next_float_var().into(),
123125

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

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

+49-25
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use std::iter;
1313
use rustc_index::{Idx, IndexVec};
1414
use rustc_middle::arena::ArenaAllocatable;
1515
use rustc_middle::mir::ConstraintCategory;
16-
use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable};
16+
use rustc_middle::ty::{
17+
self, BoundVar, CanonicalVarKind, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable,
18+
};
1719
use rustc_middle::{bug, span_bug};
1820
use tracing::{debug, instrument};
1921

@@ -443,32 +445,54 @@ impl<'tcx> InferCtxt<'tcx> {
443445
// Create result arguments: if we found a value for a
444446
// given variable in the loop above, use that. Otherwise, use
445447
// a fresh inference variable.
446-
let result_args = CanonicalVarValues {
447-
var_values: self.tcx.mk_args_from_iter(
448-
query_response.variables.iter().enumerate().map(|(index, info)| {
449-
if info.universe() != ty::UniverseIndex::ROOT {
450-
// A variable from inside a binder of the query. While ideally these shouldn't
451-
// exist at all, we have to deal with them for now.
452-
self.instantiate_canonical_var(cause.span, info, |u| {
453-
universe_map[u.as_usize()]
454-
})
455-
} else if info.is_existential() {
456-
match opt_values[BoundVar::new(index)] {
457-
Some(k) => k,
458-
None => self.instantiate_canonical_var(cause.span, info, |u| {
459-
universe_map[u.as_usize()]
460-
}),
448+
let mut var_values = Vec::with_capacity(query_response.variables.len());
449+
for (index, info) in query_response.variables.iter().enumerate() {
450+
let value = if info.universe() != ty::UniverseIndex::ROOT {
451+
// A variable from inside a binder of the query. While ideally these shouldn't
452+
// exist at all, we have to deal with them for now.
453+
self.instantiate_canonical_var(cause.span, info, &var_values, |u| {
454+
universe_map[u.as_usize()]
455+
})
456+
} else if info.is_existential() {
457+
// As an optimization we sometimes avoid creating a new inference variable here.
458+
// We need to still make sure to register any subtype relations returned by the
459+
// query.
460+
match opt_values[BoundVar::new(index)] {
461+
Some(v) => {
462+
if let CanonicalVarKind::Ty { universe: _, sub_root } = info.kind {
463+
if let Some(prev) = var_values.get(sub_root.as_usize()) {
464+
// We cannot simply assume that previous `var_values`
465+
// are inference variables, see the comment in
466+
// `instantiate_canonical_var`.
467+
let v = self.shallow_resolve(v.expect_ty());
468+
let prev = self.shallow_resolve(prev.expect_ty());
469+
match (v.kind(), prev.kind()) {
470+
(
471+
&ty::Infer(ty::TyVar(vid)),
472+
&ty::Infer(ty::TyVar(sub_root)),
473+
) => {
474+
self.inner.borrow_mut().type_variables().sub(vid, sub_root)
475+
}
476+
_ => {}
477+
}
478+
}
461479
}
462-
} else {
463-
// For placeholders which were already part of the input, we simply map this
464-
// universal bound variable back the placeholder of the input.
465-
opt_values[BoundVar::new(index)].expect(
466-
"expected placeholder to be unified with itself during response",
467-
)
480+
v
468481
}
469-
}),
470-
),
471-
};
482+
None => self.instantiate_canonical_var(cause.span, info, &var_values, |u| {
483+
universe_map[u.as_usize()]
484+
}),
485+
}
486+
} else {
487+
// For placeholders which were already part of the input, we simply map this
488+
// universal bound variable back the placeholder of the input.
489+
opt_values[BoundVar::new(index)]
490+
.expect("expected placeholder to be unified with itself during response")
491+
};
492+
var_values.push(value)
493+
}
494+
495+
let result_args = CanonicalVarValues { var_values: self.tcx.mk_args(&var_values) };
472496

473497
let mut obligations = PredicateObligations::new();
474498

compiler/rustc_infer/src/infer/context.rs

+7
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
5555
fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid {
5656
self.root_var(var)
5757
}
58+
fn sub_root_ty_var(&self, var: ty::TyVid) -> ty::TyVid {
59+
self.sub_root_var(var)
60+
}
5861

5962
fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
6063
self.root_const_var(var)
@@ -125,6 +128,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
125128
self.inner.borrow_mut().type_variables().equate(a, b);
126129
}
127130

131+
fn sub_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) {
132+
self.inner.borrow_mut().type_variables().sub(a, b);
133+
}
134+
128135
fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid) {
129136
self.inner.borrow_mut().int_unification_table().union(a, b);
130137
}

compiler/rustc_infer/src/infer/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,7 @@ impl<'tcx> InferCtxt<'tcx> {
724724
let r_b = self.shallow_resolve(predicate.skip_binder().b);
725725
match (r_a.kind(), r_b.kind()) {
726726
(&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
727+
self.inner.borrow_mut().type_variables().sub(a_vid, b_vid);
727728
return Err((a_vid, b_vid));
728729
}
729730
_ => {}
@@ -1056,6 +1057,10 @@ impl<'tcx> InferCtxt<'tcx> {
10561057
self.inner.borrow_mut().type_variables().root_var(var)
10571058
}
10581059

1060+
pub fn sub_root_var(&self, var: ty::TyVid) -> ty::TyVid {
1061+
self.inner.borrow_mut().type_variables().sub_root_var(var)
1062+
}
1063+
10591064
pub fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
10601065
self.inner.borrow_mut().const_unification_table().find(var).vid
10611066
}

compiler/rustc_infer/src/infer/relate/generalize.rs

+4
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
503503
let origin = inner.type_variables().var_origin(vid);
504504
let new_var_id =
505505
inner.type_variables().new_var(self.for_universe, origin);
506+
// Record that `vid` and `new_var_id` have to be subtypes
507+
// of each other. This is currently only used for diagnostics.
508+
// To see why, see the docs in the `type_variables` module.
509+
inner.type_variables().sub(vid, new_var_id);
506510
// If we're in the new solver and create a new inference
507511
// variable inside of an alias we eagerly constrain that
508512
// inference variable to prevent unexpected ambiguity errors.

compiler/rustc_infer/src/infer/snapshot/undo_log.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub struct Snapshot<'tcx> {
1919
pub(crate) enum UndoLog<'tcx> {
2020
DuplicateOpaqueType,
2121
OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>),
22-
TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
22+
TypeVariables(type_variable::UndoLog<'tcx>),
2323
ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
2424
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
2525
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
@@ -45,7 +45,9 @@ macro_rules! impl_from {
4545
impl_from! {
4646
RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
4747

48+
TypeVariables(type_variable::UndoLog<'tcx>),
4849
TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
50+
TypeVariables(sv::UndoLog<ut::Delegate<ty::TyVid>>),
4951
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
5052
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
5153

0 commit comments

Comments
 (0)