Skip to content

Commit 35fc072

Browse files
committed
eagerly compute sub_relations again
1 parent 2a341bd commit 35fc072

File tree

15 files changed

+152
-111
lines changed

15 files changed

+152
-111
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
2121
use rustc_session::Session;
2222
use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym};
2323
use rustc_trait_selection::error_reporting::TypeErrCtxt;
24-
use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations;
2524
use rustc_trait_selection::traits::{
2625
self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt,
2726
};
@@ -188,14 +187,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
188187
///
189188
/// [`InferCtxtErrorExt::err_ctxt`]: rustc_trait_selection::error_reporting::InferCtxtErrorExt::err_ctxt
190189
pub(crate) fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
191-
let mut sub_relations = SubRelations::default();
192-
sub_relations.add_constraints(
193-
self,
194-
self.fulfillment_cx.borrow_mut().pending_obligations().iter().map(|o| o.predicate),
195-
);
196190
TypeErrCtxt {
197191
infcx: &self.infcx,
198-
sub_relations: RefCell::new(sub_relations),
199192
typeck_results: Some(self.typeck_results.borrow()),
200193
fallback_has_occurred: self.fallback_has_occurred.get(),
201194
normalize_fn_sig: Box::new(|fn_sig| {

compiler/rustc_infer/src/infer/context.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
179179
self.inner.borrow_mut().type_variables().equate(a, b);
180180
}
181181

182+
fn sub_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) {
183+
self.sub_ty_vids_raw(a, b);
184+
}
185+
182186
fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid) {
183187
self.inner.borrow_mut().int_unification_table().union(a, b);
184188
}

compiler/rustc_infer/src/infer/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,7 @@ impl<'tcx> InferCtxt<'tcx> {
764764
let r_b = self.shallow_resolve(predicate.skip_binder().b);
765765
match (r_a.kind(), r_b.kind()) {
766766
(&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
767+
self.sub_ty_vids_raw(a_vid, b_vid);
767768
return Err((a_vid, b_vid));
768769
}
769770
_ => {}
@@ -1124,6 +1125,14 @@ impl<'tcx> InferCtxt<'tcx> {
11241125
self.inner.borrow_mut().type_variables().root_var(var)
11251126
}
11261127

1128+
pub fn sub_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) {
1129+
self.inner.borrow_mut().type_variables().sub(a, b);
1130+
}
1131+
1132+
pub fn sub_root_var(&self, var: ty::TyVid) -> ty::TyVid {
1133+
self.inner.borrow_mut().type_variables().sub_root_var(var)
1134+
}
1135+
11271136
pub fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
11281137
self.inner.borrow_mut().const_unification_table().find(var).vid
11291138
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,10 @@ impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> {
519519
let origin = inner.type_variables().var_origin(vid);
520520
let new_var_id =
521521
inner.type_variables().new_var(self.for_universe, origin);
522+
// Record that `vid` and `new_var_id` have to be subtypes
523+
// of each other. This is currently only used for diagnostics.
524+
// To see why, see the docs in the `type_variables` module.
525+
inner.type_variables().sub(vid, new_var_id);
522526
// If we're in the new solver and create a new inference
523527
// variable inside of an alias we eagerly constrain that
524528
// inference variable to prevent unexpected ambiguity errors.

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub struct Snapshot<'tcx> {
2020
pub(crate) enum UndoLog<'tcx> {
2121
DuplicateOpaqueType,
2222
OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>),
23-
TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
23+
TypeVariables(type_variable::UndoLog<'tcx>),
2424
ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
2525
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
2626
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
@@ -49,6 +49,8 @@ impl_from! {
4949
RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
5050

5151
TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
52+
TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidSubKey>>),
53+
TypeVariables(type_variable::UndoLog<'tcx>),
5254
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
5355
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
5456

compiler/rustc_infer/src/infer/type_variable.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,48 @@ use tracing::debug;
1313

1414
use crate::infer::InferCtxtUndoLogs;
1515

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<TyVidSubKey>>),
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<TyVidSubKey>>> for UndoLog<'tcx> {
32+
fn from(l: sv::UndoLog<ut::Delegate<TyVidSubKey>>) -> Self {
33+
UndoLog::SubRelation(l)
34+
}
35+
}
36+
1637
impl<'tcx> Rollback<sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>> for TypeVariableStorage<'tcx> {
1738
fn reverse(&mut self, undo: sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>) {
1839
self.eq_relations.reverse(undo)
1940
}
2041
}
2142

43+
impl<'tcx> Rollback<sv::UndoLog<ut::Delegate<TyVidSubKey>>> for TypeVariableStorage<'tcx> {
44+
fn reverse(&mut self, undo: sv::UndoLog<ut::Delegate<TyVidSubKey>>) {
45+
self.sub_relations.reverse(undo)
46+
}
47+
}
48+
49+
impl<'tcx> Rollback<UndoLog<'tcx>> for TypeVariableStorage<'tcx> {
50+
fn reverse(&mut self, undo: UndoLog<'tcx>) {
51+
match undo {
52+
UndoLog::EqRelation(undo) => self.eq_relations.reverse(undo),
53+
UndoLog::SubRelation(undo) => self.sub_relations.reverse(undo),
54+
}
55+
}
56+
}
57+
2258
#[derive(Clone, Default)]
2359
pub(crate) struct TypeVariableStorage<'tcx> {
2460
/// The origins of each type variable.
@@ -27,6 +63,23 @@ pub(crate) struct TypeVariableStorage<'tcx> {
2763
/// constraint `?X == ?Y`. This table also stores, for each key,
2864
/// the known value.
2965
eq_relations: ut::UnificationTableStorage<TyVidEqKey<'tcx>>,
66+
/// Only used by `-Znext-solver` and for diagnostics.
67+
///
68+
/// When reporting ambiguity errors, we sometimes want to
69+
/// treat all inference vars which are subtypes of each
70+
/// others as if they are equal. For this case we compute
71+
/// the transitive closure of our subtype obligations here.
72+
///
73+
/// E.g. when encountering ambiguity errors, we want to suggest
74+
/// specifying some method argument or to add a type annotation
75+
/// to a local variable. Because subtyping cannot change the
76+
/// shape of a type, it's fine if the cause of the ambiguity error
77+
/// is only related to the suggested variable via subtyping.
78+
///
79+
/// Even for something like `let x = returns_arg(); x.method();` the
80+
/// type of `x` is only a supertype of the argument of `returns_arg`. We
81+
/// still want to suggest specifying the type of the argument.
82+
sub_relations: ut::UnificationTableStorage<TyVidSubKey>,
3083
}
3184

3285
pub(crate) struct TypeVariableTable<'a, 'tcx> {
@@ -109,6 +162,16 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
109162
debug_assert!(self.probe(a).is_unknown());
110163
debug_assert!(self.probe(b).is_unknown());
111164
self.eq_relations().union(a, b);
165+
self.sub_relations().union(a, b);
166+
}
167+
168+
/// Records that `a <: b`, depending on `dir`.
169+
///
170+
/// Precondition: neither `a` nor `b` are known.
171+
pub(crate) fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) {
172+
debug_assert!(self.probe(a).is_unknown());
173+
debug_assert!(self.probe(b).is_unknown());
174+
self.sub_relations().union(a, b);
112175
}
113176

114177
/// Instantiates `vid` with the type `ty`.
@@ -142,6 +205,10 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
142205
origin: TypeVariableOrigin,
143206
) -> ty::TyVid {
144207
let eq_key = self.eq_relations().new_key(TypeVariableValue::Unknown { universe });
208+
209+
let sub_key = self.sub_relations().new_key(());
210+
debug_assert_eq!(eq_key.vid, sub_key.vid);
211+
145212
let index = self.storage.values.push(TypeVariableData { origin });
146213
debug_assert_eq!(eq_key.vid, index);
147214

@@ -164,6 +231,18 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
164231
self.eq_relations().find(vid).vid
165232
}
166233

234+
/// Returns the "root" variable of `vid` in the `sub_relations`
235+
/// equivalence table. All type variables that have been are
236+
/// related via equality or subtyping will yield the same root
237+
/// variable (per the union-find algorithm), so `sub_root_var(a)
238+
/// == sub_root_var(b)` implies that:
239+
/// ```text
240+
/// exists X. (a <: X || X <: a) && (b <: X || X <: b)
241+
/// ```
242+
pub(crate) fn sub_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid {
243+
self.sub_relations().find(vid).vid
244+
}
245+
167246
/// Retrieves the type to which `vid` has been instantiated, if
168247
/// any.
169248
pub(crate) fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> {
@@ -181,6 +260,11 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
181260
self.storage.eq_relations.with_log(self.undo_log)
182261
}
183262

263+
#[inline]
264+
fn sub_relations(&mut self) -> super::UnificationTable<'_, 'tcx, TyVidSubKey> {
265+
self.storage.sub_relations.with_log(self.undo_log)
266+
}
267+
184268
/// Returns a range of the type variables created during the snapshot.
185269
pub(crate) fn vars_since_snapshot(
186270
&mut self,
@@ -243,6 +327,33 @@ impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> {
243327
}
244328
}
245329

330+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
331+
pub(crate) struct TyVidSubKey {
332+
vid: ty::TyVid,
333+
}
334+
335+
impl From<ty::TyVid> for TyVidSubKey {
336+
#[inline] // make this function eligible for inlining - it is quite hot.
337+
fn from(vid: ty::TyVid) -> Self {
338+
TyVidSubKey { vid }
339+
}
340+
}
341+
342+
impl ut::UnifyKey for TyVidSubKey {
343+
type Value = ();
344+
#[inline]
345+
fn index(&self) -> u32 {
346+
self.vid.as_u32()
347+
}
348+
#[inline]
349+
fn from_index(i: u32) -> TyVidSubKey {
350+
TyVidSubKey { vid: ty::TyVid::from_u32(i) }
351+
}
352+
fn tag() -> &'static str {
353+
"TyVidSubKey"
354+
}
355+
}
356+
246357
impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> {
247358
type Error = ut::NoError;
248359

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,10 @@ where
930930
&& goal.param_env.visit_with(&mut visitor).is_continue()
931931
}
932932

933+
pub(super) fn sub_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) {
934+
self.delegate.sub_ty_vids_raw(a, b)
935+
}
936+
933937
#[instrument(level = "trace", skip(self, param_env), ret)]
934938
pub(super) fn eq<T: Relate<I>>(
935939
&mut self,

compiler/rustc_next_trait_solver/src/solve/mod.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,15 @@ where
122122

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

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ mod suggest;
9191
pub mod need_type_info;
9292
pub mod nice_region_error;
9393
pub mod region;
94-
pub mod sub_relations;
9594

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

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -894,7 +894,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
894894
use ty::{Infer, TyVar};
895895
match (inner_ty.kind(), target_ty.kind()) {
896896
(&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => {
897-
self.tecx.sub_relations.borrow_mut().unified(self.tecx, a_vid, b_vid)
897+
self.tecx.sub_root_var(a_vid) == self.tecx.sub_root_var(b_vid)
898898
}
899899
_ => false,
900900
}

0 commit comments

Comments
 (0)