Skip to content

Commit 8b3ed20

Browse files
committed
Auto merge of rust-lang#140375 - lcnr:subrelations-infcx, r=<try>
eagerly compute `sub_relations` again We still only using them for diagnostics with the old solver. 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_relations` in any way. We would also need to consider them when canonicalizing as otherwise instantiating the canonical response may fail. Necessary for type inference guidance due to not-yet defined opaque types, cc rust-lang/trait-system-refactor-initiative#182. r? `@compiler-errors`
2 parents 1a95cc6 + 8eb514a commit 8b3ed20

File tree

23 files changed

+299
-237
lines changed

23 files changed

+299
-237
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

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

485509
let mut obligations = PredicateObligations::new();
486510

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
@@ -733,6 +733,7 @@ impl<'tcx> InferCtxt<'tcx> {
733733
let r_b = self.shallow_resolve(predicate.skip_binder().b);
734734
match (r_a.kind(), r_b.kind()) {
735735
(&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
736+
self.inner.borrow_mut().type_variables().sub(a_vid, b_vid);
736737
return Err((a_vid, b_vid));
737738
}
738739
_ => {}
@@ -1065,6 +1066,10 @@ impl<'tcx> InferCtxt<'tcx> {
10651066
self.inner.borrow_mut().type_variables().root_var(var)
10661067
}
10671068

1069+
pub fn sub_root_var(&self, var: ty::TyVid) -> ty::TyVid {
1070+
self.inner.borrow_mut().type_variables().sub_root_var(var)
1071+
}
1072+
10681073
pub fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
10691074
self.inner.borrow_mut().const_unification_table().find(var).vid
10701075
}

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
@@ -18,7 +18,7 @@ pub struct Snapshot<'tcx> {
1818
#[derive(Clone)]
1919
pub(crate) enum UndoLog<'tcx> {
2020
OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>),
21-
TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
21+
TypeVariables(type_variable::UndoLog<'tcx>),
2222
ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
2323
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
2424
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
@@ -44,7 +44,9 @@ macro_rules! impl_from {
4444
impl_from! {
4545
RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
4646

47+
TypeVariables(type_variable::UndoLog<'tcx>),
4748
TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
49+
TypeVariables(sv::UndoLog<ut::Delegate<ty::TyVid>>),
4850
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
4951
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
5052

0 commit comments

Comments
 (0)