@@ -13,9 +13,33 @@ use tracing::debug;
13
13
14
14
use crate :: infer:: InferCtxtUndoLogs ;
15
15
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
+ }
19
43
}
20
44
}
21
45
@@ -27,6 +51,24 @@ pub(crate) struct TypeVariableStorage<'tcx> {
27
51
/// constraint `?X == ?Y`. This table also stores, for each key,
28
52
/// the known value.
29
53
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 > ,
30
72
}
31
73
32
74
pub ( crate ) struct TypeVariableTable < ' a , ' tcx > {
@@ -109,6 +151,16 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
109
151
debug_assert ! ( self . probe( a) . is_unknown( ) ) ;
110
152
debug_assert ! ( self . probe( b) . is_unknown( ) ) ;
111
153
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) ;
112
164
}
113
165
114
166
/// Instantiates `vid` with the type `ty`.
@@ -142,6 +194,10 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
142
194
origin : TypeVariableOrigin ,
143
195
) -> ty:: TyVid {
144
196
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
+
145
201
let index = self . storage . values . push ( TypeVariableData { origin } ) ;
146
202
debug_assert_eq ! ( eq_key. vid, index) ;
147
203
@@ -164,6 +220,18 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
164
220
self . eq_relations ( ) . find ( vid) . vid
165
221
}
166
222
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
+
167
235
/// Retrieves the type to which `vid` has been instantiated, if
168
236
/// any.
169
237
pub ( crate ) fn probe ( & mut self , vid : ty:: TyVid ) -> TypeVariableValue < ' tcx > {
@@ -181,6 +249,11 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> {
181
249
self . storage . eq_relations . with_log ( self . undo_log )
182
250
}
183
251
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
+
184
257
/// Returns a range of the type variables created during the snapshot.
185
258
pub ( crate ) fn vars_since_snapshot (
186
259
& mut self ,
0 commit comments