Skip to content

Commit cb71df2

Browse files
committed
eagerly compute sub_relations again
While still only using them for diagnostics. 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.
1 parent cb31a00 commit cb71df2

File tree

14 files changed

+107
-107
lines changed

14 files changed

+107
-107
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/context.rs

+4
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
125125
self.inner.borrow_mut().type_variables().equate(a, b);
126126
}
127127

128+
fn sub_ty_vids_raw(&self, a: rustc_type_ir::TyVid, b: rustc_type_ir::TyVid) {
129+
self.inner.borrow_mut().type_variables().sub(a, b);
130+
}
131+
128132
fn equate_int_vids_raw(&self, a: rustc_type_ir::IntVid, b: rustc_type_ir::IntVid) {
129133
self.inner.borrow_mut().int_unification_table().union(a, b);
130134
}

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

compiler/rustc_infer/src/infer/type_variable.rs

+76-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,33 @@ use tracing::debug;
1313

1414
use crate::infer::InferCtxtUndoLogs;
1515

16-
impl<'tcx> Rollback<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for TypeVariableStorage<'tcx> {
17-
fn reverse(&mut self, undo: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) {
18-
self.eq_relations.reverse(undo)
16+
/// Represents a single undo-able action that affects a type inference variable.
17+
#[derive(Clone)]
18+
pub(crate) enum UndoLog<'tcx> {
19+
EqRelation(sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>),
20+
SubRelation(sv::UndoLog<ut::Delegate<ty::TyVid>>),
21+
}
22+
23+
/// Convert from a specific kind of undo to the more general UndoLog
24+
impl<'tcx> From<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for UndoLog<'tcx> {
25+
fn from(l: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) -> Self {
26+
UndoLog::EqRelation(l)
27+
}
28+
}
29+
30+
/// Convert from a specific kind of undo to the more general UndoLog
31+
impl<'tcx> From<sv::UndoLog<ut::Delegate<ty::TyVid>>> for UndoLog<'tcx> {
32+
fn from(l: sv::UndoLog<ut::Delegate<ty::TyVid>>) -> Self {
33+
UndoLog::SubRelation(l)
34+
}
35+
}
36+
37+
impl<'tcx> Rollback<UndoLog<'tcx>> for TypeVariableStorage<'tcx> {
38+
fn reverse(&mut self, undo: UndoLog<'tcx>) {
39+
match undo {
40+
UndoLog::EqRelation(undo) => self.eq_relations.reverse(undo),
41+
UndoLog::SubRelation(undo) => self.sub_relations.reverse(undo),
42+
}
1943
}
2044
}
2145

@@ -27,6 +51,24 @@ pub(crate) struct TypeVariableStorage<'tcx> {
2751
/// constraint `?X == ?Y`. This table also stores, for each key,
2852
/// the known value.
2953
eq_relations: ut::UnificationTableStorage<TyVidEqKey<'tcx>>,
54+
55+
/// Only used by `-Znext-solver` andfor diagnostics.
56+
///
57+
/// When reporting ambiguity errors, we sometimes want to
58+
/// treat all inference vars which are subtypes of each
59+
/// others as if they are equal. For this case we compute
60+
/// the transitive closure of our subtype obligations here.
61+
///
62+
/// E.g. when encountering ambiguity errors, we want to suggest
63+
/// specifying some method argument or to add a type annotation
64+
/// to a local variable. Because subtyping cannot change the
65+
/// shape of a type, it's fine if the cause of the ambiguity error
66+
/// is only related to the suggested variable via subtyping.
67+
///
68+
/// Even for something like `let x = returns_arg(); x.method();` the
69+
/// type of `x` is only a supertype of the argument of `returns_arg`. We
70+
/// still want to suggest specifying the type of the argument.
71+
sub_relations: ut::UnificationTableStorage<ty::TyVid>,
3072
}
3173

3274
pub(crate) struct TypeVariableTable<'a, 'tcx> {
@@ -109,6 +151,16 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
109151
debug_assert!(self.probe(a).is_unknown());
110152
debug_assert!(self.probe(b).is_unknown());
111153
self.eq_relations().union(a, b);
154+
self.sub_relations().union(a, b);
155+
}
156+
157+
/// Records that `a <: b`, depending on `dir`.
158+
///
159+
/// Precondition: neither `a` nor `b` are known.
160+
pub(crate) fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) {
161+
debug_assert!(self.probe(a).is_unknown());
162+
debug_assert!(self.probe(b).is_unknown());
163+
self.sub_relations().union(a, b);
112164
}
113165

114166
/// Instantiates `vid` with the type `ty`.
@@ -142,6 +194,10 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
142194
origin: TypeVariableOrigin,
143195
) -> ty::TyVid {
144196
let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe });
197+
198+
let sub_key = self.sub_relations().new_key(());
199+
debug_assert_eq!(eq_key.vid, sub_key);
200+
145201
let index = self.storage.values.push(TypeVariableData { origin });
146202
debug_assert_eq!(eq_key.vid, index);
147203

@@ -164,6 +220,18 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
164220
self.eq_relations().find(vid).vid
165221
}
166222

223+
/// Returns the "root" variable of `vid` in the `sub_relations`
224+
/// equivalence table. All type variables that have been are
225+
/// related via equality or subtyping will yield the same root
226+
/// variable (per the union-find algorithm), so `sub_root_var(a)
227+
/// == sub_root_var(b)` implies that:
228+
/// ```text
229+
/// exists X. (a <: X || X <: a) && (b <: X || X <: b)
230+
/// ```
231+
pub(crate) fn sub_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
232+
self.sub_relations().find(vid)
233+
}
234+
167235
/// Retrieves the type to which `vid` has been instantiated, if
168236
/// any.
169237
pub(crate) fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> {
@@ -181,6 +249,11 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
181249
self.storage.eq_relations.with_log(self.undo_log)
182250
}
183251

252+
#[inline]
253+
fn sub_relations(&mut self) -> super::UnificationTable<'_, 'tcx, ty::TyVid> {
254+
self.storage.sub_relations.with_log(self.undo_log)
255+
}
256+
184257
/// Returns a range of the type variables created during the snapshot.
185258
pub(crate) fn vars_since_snapshot(
186259
&mut self,

compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,10 @@ where
844844
&& goal.param_env.visit_with(&mut visitor).is_continue()
845845
}
846846

847+
pub(super) fn sub_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) {
848+
self.delegate.sub_ty_vids_raw(a, b)
849+
}
850+
847851
#[instrument(level = "trace", skip(self, param_env), ret)]
848852
pub(super) fn eq<T: Relate<I>>(
849853
&mut self,

compiler/rustc_next_trait_solver/src/solve/mod.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,15 @@ where
120120

121121
#[instrument(level = "trace", skip(self))]
122122
fn compute_subtype_goal(&mut self, goal: Goal<I, ty::SubtypePredicate<I>>) -> QueryResult<I> {
123-
if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() {
124-
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
125-
} else {
126-
self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?;
127-
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
123+
match (goal.predicate.a.kind(), goal.predicate.b.kind()) {
124+
(ty::Infer(ty::TyVar(a_vid)), ty::Infer(ty::TyVar(b_vid))) => {
125+
self.sub_ty_vids_raw(a_vid, b_vid);
126+
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
127+
}
128+
_ => {
129+
self.sub(goal.param_env, goal.predicate.a, goal.predicate.b)?;
130+
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
131+
}
128132
}
129133
}
130134

compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ mod suggest;
9292
pub mod need_type_info;
9393
pub mod nice_region_error;
9494
pub mod region;
95-
pub mod sub_relations;
9695

9796
/// Makes a valid string literal from a string by escaping special characters (" and \),
9897
/// unless they are already escaped.

compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -946,7 +946,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
946946
use ty::{Infer, TyVar};
947947
match (inner_ty.kind(), target_ty.kind()) {
948948
(&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
949-
self.tecx.sub_relations.borrow_mut().unified(self.tecx, a_vid, b_vid)
949+
self.tecx.sub_root_var(a_vid) == self.tecx.sub_root_var(b_vid)
950950
}
951951
_ => false,
952952
}

compiler/rustc_trait_selection/src/error_reporting/infer/sub_relations.rs

-81
This file was deleted.

compiler/rustc_trait_selection/src/error_reporting/mod.rs

-4
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ use rustc_macros::extension;
77
use rustc_middle::bug;
88
use rustc_middle::ty::{self, Ty};
99

10-
use crate::error_reporting::infer::sub_relations;
11-
1210
pub mod infer;
1311
pub mod traits;
1412

@@ -21,7 +19,6 @@ pub mod traits;
2119
/// methods which should not be used during the happy path.
2220
pub struct TypeErrCtxt<'a, 'tcx> {
2321
pub infcx: &'a InferCtxt<'tcx>,
24-
pub sub_relations: std::cell::RefCell<sub_relations::SubRelations>,
2522

2623
pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
2724
pub fallback_has_occurred: bool,
@@ -38,7 +35,6 @@ impl<'tcx> InferCtxt<'tcx> {
3835
fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> {
3936
TypeErrCtxt {
4037
infcx: self,
41-
sub_relations: Default::default(),
4238
typeck_results: None,
4339
fallback_has_occurred: false,
4440
normalize_fn_sig: Box::new(|fn_sig| fn_sig),

compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs

-4
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
141141
&self,
142142
mut errors: Vec<FulfillmentError<'tcx>>,
143143
) -> ErrorGuaranteed {
144-
self.sub_relations
145-
.borrow_mut()
146-
.add_constraints(self, errors.iter().map(|e| e.obligation.predicate));
147-
148144
#[derive(Debug)]
149145
struct ErrorDescriptor<'tcx> {
150146
goal: Goal<'tcx, ty::Predicate<'tcx>>,

compiler/rustc_type_ir/src/infer_ctxt.rs

+1
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ pub trait InferCtxtLike: Sized {
186186
) -> U;
187187

188188
fn equate_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid);
189+
fn sub_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid);
189190
fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid);
190191
fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid);
191192
fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid);

0 commit comments

Comments
 (0)