Skip to content

Commit e184142

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 25cdf1f + 26f4ee0 commit e184142

File tree

27 files changed

+292
-264
lines changed

27 files changed

+292
-264
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_hir_typeck/src/method/probe.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1213,7 +1213,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12131213
debug!("pick_all_method: step={:?}", step);
12141214
// skip types that are from a type error or that would require dereferencing
12151215
// a raw pointer
1216-
!step.self_ty.references_error() && !step.from_unsafe_deref
1216+
!step.self_ty.value.references_error() && !step.from_unsafe_deref
12171217
})
12181218
.find_map(|step| {
12191219
let InferOk { value: self_ty, obligations: _ } = self

compiler/rustc_hir_typeck/src/writeback.rs

+1-21
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use rustc_errors::ErrorGuaranteed;
99
use rustc_hir::intravisit::{self, InferKind, Visitor};
1010
use rustc_hir::{self as hir, AmbigArg, HirId};
1111
use rustc_infer::traits::solve::Goal;
12-
use rustc_middle::span_bug;
1312
use rustc_middle::traits::ObligationCause;
1413
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
1514
use rustc_middle::ty::{
@@ -513,15 +512,6 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
513512
self.typeck_results.user_provided_types_mut().extend(
514513
fcx_typeck_results.user_provided_types().items().map(|(local_id, c_ty)| {
515514
let hir_id = HirId { owner: common_hir_owner, local_id };
516-
517-
if cfg!(debug_assertions) && c_ty.has_infer() {
518-
span_bug!(
519-
hir_id.to_span(self.fcx.tcx),
520-
"writeback: `{:?}` has inference variables",
521-
c_ty
522-
);
523-
};
524-
525515
(hir_id, *c_ty)
526516
}),
527517
);
@@ -532,17 +522,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
532522
assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
533523

534524
self.typeck_results.user_provided_sigs.extend_unord(
535-
fcx_typeck_results.user_provided_sigs.items().map(|(&def_id, c_sig)| {
536-
if cfg!(debug_assertions) && c_sig.has_infer() {
537-
span_bug!(
538-
self.fcx.tcx.def_span(def_id),
539-
"writeback: `{:?}` has inference variables",
540-
c_sig
541-
);
542-
};
543-
544-
(def_id, *c_sig)
545-
}),
525+
fcx_typeck_results.user_provided_sigs.items().map(|(def_id, c_sig)| (*def_id, *c_sig)),
546526
);
547527
}
548528

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

+17-14
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ use tracing::debug;
1717

1818
use crate::infer::InferCtxt;
1919
use crate::infer::canonical::{
20-
Canonical, CanonicalQueryInput, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind,
21-
OriginalQueryValues,
20+
Canonical, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues,
2221
};
2322

2423
impl<'tcx> InferCtxt<'tcx> {
@@ -299,6 +298,7 @@ struct Canonicalizer<'cx, 'tcx> {
299298
// Note that indices is only used once `var_values` is big enough to be
300299
// heap-allocated.
301300
indices: FxHashMap<GenericArg<'tcx>, BoundVar>,
301+
sub_root_lookup_table: FxHashMap<ty::TyVid, usize>,
302302
canonicalize_mode: &'cx dyn CanonicalizeMode,
303303
needs_canonical_flags: TypeFlags,
304304

@@ -367,9 +367,10 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
367367
// FIXME: perf problem described in #55921.
368368
ui = ty::UniverseIndex::ROOT;
369369
}
370+
let sub_root = self.get_or_insert_sub_root(vid);
370371
self.canonicalize_ty_var(
371372
CanonicalVarInfo {
372-
kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
373+
kind: CanonicalVarKind::Ty { universe: ui, sub_root },
373374
},
374375
t,
375376
)
@@ -382,21 +383,15 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
382383
if nt != t {
383384
return self.fold_ty(nt);
384385
} else {
385-
self.canonicalize_ty_var(
386-
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) },
387-
t,
388-
)
386+
self.canonicalize_ty_var(CanonicalVarInfo { kind: CanonicalVarKind::Int }, t)
389387
}
390388
}
391389
ty::Infer(ty::FloatVar(vid)) => {
392390
let nt = self.infcx.unwrap().opportunistic_resolve_float_var(vid);
393391
if nt != t {
394392
return self.fold_ty(nt);
395393
} else {
396-
self.canonicalize_ty_var(
397-
CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) },
398-
t,
399-
)
394+
self.canonicalize_ty_var(CanonicalVarInfo { kind: CanonicalVarKind::Float }, t)
400395
}
401396
}
402397

@@ -576,6 +571,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
576571
variables: SmallVec::from_slice(base.variables),
577572
query_state,
578573
indices: FxHashMap::default(),
574+
sub_root_lookup_table: Default::default(),
579575
binder_index: ty::INNERMOST,
580576
};
581577
if canonicalizer.query_state.var_values.spilled() {
@@ -670,6 +666,13 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
670666
}
671667
}
672668

669+
fn get_or_insert_sub_root(&mut self, vid: ty::TyVid) -> ty::BoundVar {
670+
let root_vid = self.infcx.unwrap().sub_root_var(vid);
671+
let idx =
672+
*self.sub_root_lookup_table.entry(root_vid).or_insert_with(|| self.variables.len());
673+
ty::BoundVar::from(idx)
674+
}
675+
673676
/// Replaces the universe indexes used in `var_values` with their index in
674677
/// `query_state.universe_map`. This minimizes the maximum universe used in
675678
/// the canonicalized value.
@@ -690,11 +693,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
690693
.iter()
691694
.map(|v| CanonicalVarInfo {
692695
kind: match v.kind {
693-
CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
696+
CanonicalVarKind::Int | CanonicalVarKind::Float => {
694697
return *v;
695698
}
696-
CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
697-
CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
699+
CanonicalVarKind::Ty { universe, sub_root } => {
700+
CanonicalVarKind::Ty { universe: reverse_universe_map[&universe], sub_root }
698701
}
699702
CanonicalVarKind::Region(u) => {
700703
CanonicalVarKind::Region(reverse_universe_map[&u])

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

+17-17
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,22 @@ 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))
115-
}
116-
117-
CanonicalTyVarKind::Int => self.next_int_var(),
118-
119-
CanonicalTyVarKind::Float => self.next_float_var(),
120-
};
121-
ty.into()
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+
let &ty::Infer(ty::TyVar(sub_root)) = prev.expect_ty().kind() else {
115+
unreachable!("expected `sub_root` to be an inference variable");
116+
};
117+
self.inner.borrow_mut().type_variables().sub(vid, sub_root);
118+
}
119+
Ty::new_var(self.tcx, vid).into()
122120
}
121+
CanonicalVarKind::Int => self.next_int_var().into(),
122+
CanonicalVarKind::Float => self.next_float_var().into(),
123123

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

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

+43-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,48 @@ 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+
let &ty::Infer(ty::TyVar(vid)) = v.expect_ty().kind() else {
477+
unreachable!("expected `sub_root` to be an inference variable");
478+
};
479+
let &ty::Infer(ty::TyVar(sub_root)) = prev.expect_ty().kind()
480+
else {
481+
unreachable!("expected `sub_root` to be an inference variable");
482+
};
483+
self.inner.borrow_mut().type_variables().sub(vid, sub_root);
484+
}
473485
}
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-
)
486+
v
480487
}
481-
}),
482-
),
483-
};
488+
None => self.instantiate_canonical_var(cause.span, info, &var_values, |u| {
489+
universe_map[u.as_usize()]
490+
}),
491+
}
492+
} else {
493+
// For placeholders which were already part of the input, we simply map this
494+
// universal bound variable back the placeholder of the input.
495+
opt_values[BoundVar::new(index)]
496+
.expect("expected placeholder to be unified with itself during response")
497+
};
498+
var_values.push(value)
499+
}
500+
501+
let result_args = CanonicalVarValues { var_values: self.tcx.mk_args(&var_values) };
484502

485503
let mut obligations = PredicateObligations::new();
486504

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: rustc_type_ir::TyVid, b: rustc_type_ir::TyVid) {
132+
self.inner.borrow_mut().type_variables().sub(a, b);
133+
}
134+
128135
fn equate_int_vids_raw(&self, a: rustc_type_ir::IntVid, b: rustc_type_ir::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)