@@ -13,9 +13,33 @@ use tracing::debug;
1313
1414use 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
3274pub(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,
0 commit comments