Skip to content

Commit d2329c5

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 3ef8e64 + 53c24cb commit d2329c5

File tree

24 files changed

+288
-257
lines changed

24 files changed

+288
-257
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

+29-36
Original file line numberDiff line numberDiff line change
@@ -408,16 +408,7 @@ impl<'tcx> InferCtxt<'tcx> {
408408
for (original_value, result_value) in iter::zip(&original_values.var_values, result_values)
409409
{
410410
match result_value.unpack() {
411-
GenericArgKind::Type(result_value) => {
412-
// e.g., here `result_value` might be `?0` in the example above...
413-
if let ty::Bound(debruijn, b) = *result_value.kind() {
414-
// ...in which case we would set `canonical_vars[0]` to `Some(?U)`.
415-
416-
// We only allow a `ty::INNERMOST` index in generic parameters.
417-
assert_eq!(debruijn, ty::INNERMOST);
418-
opt_values[b.var] = Some(*original_value);
419-
}
420-
}
411+
GenericArgKind::Type(_) => {}
421412
GenericArgKind::Lifetime(result_value) => {
422413
// e.g., here `result_value` might be `'?1` in the example above...
423414
if let ty::ReBound(debruijn, br) = result_value.kind() {
@@ -443,32 +434,34 @@ impl<'tcx> InferCtxt<'tcx> {
443434
// Create result arguments: if we found a value for a
444435
// given variable in the loop above, use that. Otherwise, use
445436
// 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-
}),
461-
}
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-
)
468-
}
469-
}),
470-
),
471-
};
437+
let mut var_values = Vec::with_capacity(query_response.variables.len());
438+
for (index, info) in query_response.variables.iter().enumerate() {
439+
let value = if info.universe() != ty::UniverseIndex::ROOT {
440+
// A variable from inside a binder of the query. While ideally these shouldn't
441+
// exist at all, we have to deal with them for now.
442+
self.instantiate_canonical_var(cause.span, info, &var_values, |u| {
443+
universe_map[u.as_usize()]
444+
})
445+
} else if info.is_existential() {
446+
// As an optimization we sometimes avoid creating a new inference variable here.
447+
// We need to still make sure to register any subtype relations returned by the
448+
// query.
449+
match opt_values[BoundVar::new(index)] {
450+
Some(v) => v,
451+
None => self.instantiate_canonical_var(cause.span, info, &var_values, |u| {
452+
universe_map[u.as_usize()]
453+
}),
454+
}
455+
} else {
456+
// For placeholders which were already part of the input, we simply map this
457+
// universal bound variable back the placeholder of the input.
458+
opt_values[BoundVar::new(index)]
459+
.expect("expected placeholder to be unified with itself during response")
460+
};
461+
var_values.push(value)
462+
}
463+
464+
let result_args = CanonicalVarValues { var_values: self.tcx.mk_args(&var_values) };
472465

473466
let mut obligations = PredicateObligations::new();
474467

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)