1
+ use crate :: mir:: Mutability ;
1
2
use crate :: ty:: { self , Ty , TyCtxt } ;
2
3
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
3
4
use rustc_hir:: def_id:: DefId ;
27
28
UintSimplifiedType ( ty:: UintTy ) ,
28
29
FloatSimplifiedType ( ty:: FloatTy ) ,
29
30
AdtSimplifiedType ( D ) ,
31
+ ForeignSimplifiedType ( D ) ,
30
32
StrSimplifiedType ,
31
33
ArraySimplifiedType ,
32
- PtrSimplifiedType ,
34
+ SliceSimplifiedType ,
35
+ RefSimplifiedType ( Mutability ) ,
36
+ PtrSimplifiedType ( Mutability ) ,
33
37
NeverSimplifiedType ,
34
38
TupleSimplifiedType ( usize ) ,
35
39
/// A trait object, all of whose components are markers
@@ -42,22 +46,48 @@ where
42
46
OpaqueSimplifiedType ( D ) ,
43
47
FunctionSimplifiedType ( usize ) ,
44
48
ParameterSimplifiedType ,
45
- ForeignSimplifiedType ( DefId ) ,
46
49
}
47
50
48
- /// Tries to simplify a type by dropping type parameters, deref'ing away any reference types, etc.
49
- /// The idea is to get something simple that we can use to quickly decide if two types could unify
50
- /// during method lookup.
51
+ #[ derive( PartialEq , Eq , Debug , Clone , Copy ) ]
52
+ pub enum SimplifyParams {
53
+ Yes ,
54
+ No ,
55
+ }
56
+
57
+ #[ derive( PartialEq , Eq , Debug , Clone , Copy ) ]
58
+ pub enum StripReferences {
59
+ Yes ,
60
+ No ,
61
+ }
62
+
63
+ /// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
64
+ ///
65
+ /// The idea is to get something simple that we can use to quickly decide if two types could unify,
66
+ /// for example during method lookup.
51
67
///
52
- /// If `can_simplify_params` is false, then we will fail to simplify type parameters entirely. This
53
- /// is useful when those type parameters would be instantiated with fresh type variables, since
54
- /// then we can't say much about whether two types would unify. Put another way,
55
- /// `can_simplify_params` should be true if type parameters appear free in `ty` and `false` if they
56
- /// are to be considered bound.
68
+ /// A special case here are parameters and projections. Projections can be normalized to
69
+ /// a different type, meaning that `<T as Trait>::Assoc` and `u8` can be unified, even though
70
+ /// their outermost layer is different while parameters like `T` of impls are later replaced
71
+ /// with an inference variable, which then also allows unification with other types.
72
+ ///
73
+ /// When using `SimplifyParams::Yes`, we still return a simplified type for params and projections²,
74
+ /// the reasoning for this can be seen at the places doing this.
75
+ ///
76
+ /// For diagnostics we strip references with `StripReferences::Yes`. This is currently the best
77
+ /// way to skip some unhelpful suggestions.
78
+ ///
79
+ /// ¹ meaning that if two outermost layers are different, then the whole types are also different.
80
+ /// ² FIXME(@lcnr): this seems like it can actually end up being unsound with the way it's used during
81
+ /// candidate selection. We do not consider non blanket impls for `<_ as Trait>::Assoc` even
82
+ /// though `_` can be inferred to a concrete type later at which point a concrete impl
83
+ /// could actually apply. After experimenting for about an hour I wasn't able to cause any issues
84
+ /// this way so I am not going to change this until we actually find an issue as I am really
85
+ /// interesting in getting an actual test for this.
57
86
pub fn simplify_type (
58
87
tcx : TyCtxt < ' _ > ,
59
88
ty : Ty < ' _ > ,
60
- can_simplify_params : bool ,
89
+ can_simplify_params : SimplifyParams ,
90
+ strip_references : StripReferences ,
61
91
) -> Option < SimplifiedType > {
62
92
match * ty. kind ( ) {
63
93
ty:: Bool => Some ( BoolSimplifiedType ) ,
@@ -67,19 +97,24 @@ pub fn simplify_type(
67
97
ty:: Float ( float_type) => Some ( FloatSimplifiedType ( float_type) ) ,
68
98
ty:: Adt ( def, _) => Some ( AdtSimplifiedType ( def. did ) ) ,
69
99
ty:: Str => Some ( StrSimplifiedType ) ,
70
- ty:: Array ( ..) | ty:: Slice ( _) => Some ( ArraySimplifiedType ) ,
71
- ty:: RawPtr ( _) => Some ( PtrSimplifiedType ) ,
100
+ ty:: Array ( ..) => Some ( ArraySimplifiedType ) ,
101
+ ty:: Slice ( ..) => Some ( SliceSimplifiedType ) ,
102
+ ty:: RawPtr ( ptr) => Some ( PtrSimplifiedType ( ptr. mutbl ) ) ,
72
103
ty:: Dynamic ( ref trait_info, ..) => match trait_info. principal_def_id ( ) {
73
104
Some ( principal_def_id) if !tcx. trait_is_auto ( principal_def_id) => {
74
105
Some ( TraitSimplifiedType ( principal_def_id) )
75
106
}
76
107
_ => Some ( MarkerTraitObjectSimplifiedType ) ,
77
108
} ,
78
- ty:: Ref ( _, ty, _) => {
79
- // since we introduce auto-refs during method lookup, we
80
- // just treat &T and T as equivalent from the point of
81
- // view of possibly unifying
82
- simplify_type ( tcx, ty, can_simplify_params)
109
+ ty:: Ref ( _, ty, mutbl) => {
110
+ if strip_references == StripReferences :: Yes {
111
+ // For diagnostics, when recommending similar impls we want to
112
+ // recommend impls even when there is a reference mismatch,
113
+ // so we treat &T and T equivalently in that case.
114
+ simplify_type ( tcx, ty, can_simplify_params, strip_references)
115
+ } else {
116
+ Some ( RefSimplifiedType ( mutbl) )
117
+ }
83
118
}
84
119
ty:: FnDef ( def_id, _) | ty:: Closure ( def_id, _) => Some ( ClosureSimplifiedType ( def_id) ) ,
85
120
ty:: Generator ( def_id, _, _) => Some ( GeneratorSimplifiedType ( def_id) ) ,
@@ -90,7 +125,7 @@ pub fn simplify_type(
90
125
ty:: Tuple ( ref tys) => Some ( TupleSimplifiedType ( tys. len ( ) ) ) ,
91
126
ty:: FnPtr ( ref f) => Some ( FunctionSimplifiedType ( f. skip_binder ( ) . inputs ( ) . len ( ) ) ) ,
92
127
ty:: Projection ( _) | ty:: Param ( _) => {
93
- if can_simplify_params {
128
+ if can_simplify_params == SimplifyParams :: Yes {
94
129
// In normalized types, projections don't unify with
95
130
// anything. when lazy normalization happens, this
96
131
// will change. It would still be nice to have a way
@@ -120,9 +155,12 @@ impl<D: Copy + Debug + Ord + Eq> SimplifiedTypeGen<D> {
120
155
UintSimplifiedType ( t) => UintSimplifiedType ( t) ,
121
156
FloatSimplifiedType ( t) => FloatSimplifiedType ( t) ,
122
157
AdtSimplifiedType ( d) => AdtSimplifiedType ( map ( d) ) ,
158
+ ForeignSimplifiedType ( d) => ForeignSimplifiedType ( map ( d) ) ,
123
159
StrSimplifiedType => StrSimplifiedType ,
124
160
ArraySimplifiedType => ArraySimplifiedType ,
125
- PtrSimplifiedType => PtrSimplifiedType ,
161
+ SliceSimplifiedType => SliceSimplifiedType ,
162
+ RefSimplifiedType ( m) => RefSimplifiedType ( m) ,
163
+ PtrSimplifiedType ( m) => PtrSimplifiedType ( m) ,
126
164
NeverSimplifiedType => NeverSimplifiedType ,
127
165
MarkerTraitObjectSimplifiedType => MarkerTraitObjectSimplifiedType ,
128
166
TupleSimplifiedType ( n) => TupleSimplifiedType ( n) ,
@@ -133,7 +171,6 @@ impl<D: Copy + Debug + Ord + Eq> SimplifiedTypeGen<D> {
133
171
OpaqueSimplifiedType ( d) => OpaqueSimplifiedType ( map ( d) ) ,
134
172
FunctionSimplifiedType ( n) => FunctionSimplifiedType ( n) ,
135
173
ParameterSimplifiedType => ParameterSimplifiedType ,
136
- ForeignSimplifiedType ( d) => ForeignSimplifiedType ( d) ,
137
174
}
138
175
}
139
176
}
@@ -149,12 +186,13 @@ where
149
186
| CharSimplifiedType
150
187
| StrSimplifiedType
151
188
| ArraySimplifiedType
152
- | PtrSimplifiedType
189
+ | SliceSimplifiedType
153
190
| NeverSimplifiedType
154
191
| ParameterSimplifiedType
155
192
| MarkerTraitObjectSimplifiedType => {
156
193
// nothing to do
157
194
}
195
+ RefSimplifiedType ( m) | PtrSimplifiedType ( m) => m. hash_stable ( hcx, hasher) ,
158
196
IntSimplifiedType ( t) => t. hash_stable ( hcx, hasher) ,
159
197
UintSimplifiedType ( t) => t. hash_stable ( hcx, hasher) ,
160
198
FloatSimplifiedType ( t) => t. hash_stable ( hcx, hasher) ,
0 commit comments