3
3
//! reference to a type with the field `bar`. This is an approximation of the
4
4
//! logic in rustc (which lives in rustc_hir_analysis/check/autoderef.rs).
5
5
6
+ use std:: mem;
7
+
6
8
use chalk_ir:: cast:: Cast ;
7
9
use hir_def:: lang_item:: LangItem ;
8
10
use hir_expand:: name:: Name ;
@@ -37,7 +39,7 @@ pub fn autoderef(
37
39
) -> impl Iterator < Item = Ty > {
38
40
let mut table = InferenceTable :: new ( db, env) ;
39
41
let ty = table. instantiate_canonical ( ty) ;
40
- let mut autoderef = Autoderef :: new ( & mut table, ty, false ) ;
42
+ let mut autoderef = Autoderef :: new_no_tracking ( & mut table, ty, false ) ;
41
43
let mut v = Vec :: new ( ) ;
42
44
while let Some ( ( ty, _steps) ) = autoderef. next ( ) {
43
45
// `ty` may contain unresolved inference variables. Since there's no chance they would be
@@ -58,41 +60,76 @@ pub fn autoderef(
58
60
v. into_iter ( )
59
61
}
60
62
63
+ trait TrackAutoderefSteps {
64
+ fn len ( & self ) -> usize ;
65
+ fn push ( & mut self , kind : AutoderefKind , ty : & Ty ) ;
66
+ }
67
+
68
+ impl TrackAutoderefSteps for usize {
69
+ fn len ( & self ) -> usize {
70
+ * self
71
+ }
72
+ fn push ( & mut self , _: AutoderefKind , _: & Ty ) {
73
+ * self += 1 ;
74
+ }
75
+ }
76
+ impl TrackAutoderefSteps for Vec < ( AutoderefKind , Ty ) > {
77
+ fn len ( & self ) -> usize {
78
+ self . len ( )
79
+ }
80
+ fn push ( & mut self , kind : AutoderefKind , ty : & Ty ) {
81
+ self . push ( ( kind, ty. clone ( ) ) ) ;
82
+ }
83
+ }
84
+
61
85
#[ derive( Debug ) ]
62
- pub ( crate ) struct Autoderef < ' a , ' db > {
63
- pub ( crate ) table : & ' a mut InferenceTable < ' db > ,
86
+ pub ( crate ) struct Autoderef < ' table , ' db , T = Vec < ( AutoderefKind , Ty ) > > {
87
+ pub ( crate ) table : & ' table mut InferenceTable < ' db > ,
64
88
ty : Ty ,
65
89
at_start : bool ,
66
- steps : Vec < ( AutoderefKind , Ty ) > ,
90
+ steps : T ,
67
91
explicit : bool ,
68
92
}
69
93
70
- impl < ' a , ' db > Autoderef < ' a , ' db > {
71
- pub ( crate ) fn new ( table : & ' a mut InferenceTable < ' db > , ty : Ty , explicit : bool ) -> Self {
94
+ impl < ' table , ' db > Autoderef < ' table , ' db > {
95
+ pub ( crate ) fn new ( table : & ' table mut InferenceTable < ' db > , ty : Ty , explicit : bool ) -> Self {
72
96
let ty = table. resolve_ty_shallow ( & ty) ;
73
97
Autoderef { table, ty, at_start : true , steps : Vec :: new ( ) , explicit }
74
98
}
75
99
76
- pub ( crate ) fn step_count ( & self ) -> usize {
77
- self . steps . len ( )
78
- }
79
-
80
100
pub ( crate ) fn steps ( & self ) -> & [ ( AutoderefKind , Ty ) ] {
81
101
& self . steps
82
102
}
103
+ }
104
+
105
+ impl < ' table , ' db > Autoderef < ' table , ' db , usize > {
106
+ pub ( crate ) fn new_no_tracking (
107
+ table : & ' table mut InferenceTable < ' db > ,
108
+ ty : Ty ,
109
+ explicit : bool ,
110
+ ) -> Self {
111
+ let ty = table. resolve_ty_shallow ( & ty) ;
112
+ Autoderef { table, ty, at_start : true , steps : 0 , explicit }
113
+ }
114
+ }
115
+
116
+ #[ allow( private_bounds) ]
117
+ impl < ' table , ' db , T : TrackAutoderefSteps > Autoderef < ' table , ' db , T > {
118
+ pub ( crate ) fn step_count ( & self ) -> usize {
119
+ self . steps . len ( )
120
+ }
83
121
84
122
pub ( crate ) fn final_ty ( & self ) -> Ty {
85
123
self . ty . clone ( )
86
124
}
87
125
}
88
126
89
- impl Iterator for Autoderef < ' _ , ' _ > {
127
+ impl < T : TrackAutoderefSteps > Iterator for Autoderef < ' _ , ' _ , T > {
90
128
type Item = ( Ty , usize ) ;
91
129
92
130
#[ tracing:: instrument( skip_all) ]
93
131
fn next ( & mut self ) -> Option < Self :: Item > {
94
- if self . at_start {
95
- self . at_start = false ;
132
+ if mem:: take ( & mut self . at_start ) {
96
133
return Some ( ( self . ty . clone ( ) , 0 ) ) ;
97
134
}
98
135
@@ -102,7 +139,7 @@ impl Iterator for Autoderef<'_, '_> {
102
139
103
140
let ( kind, new_ty) = autoderef_step ( self . table , self . ty . clone ( ) , self . explicit ) ?;
104
141
105
- self . steps . push ( ( kind, self . ty . clone ( ) ) ) ;
142
+ self . steps . push ( kind, & self . ty ) ;
106
143
self . ty = new_ty;
107
144
108
145
Some ( ( self . ty . clone ( ) , self . step_count ( ) ) )
@@ -129,12 +166,8 @@ pub(crate) fn builtin_deref<'ty>(
129
166
match ty. kind ( Interner ) {
130
167
TyKind :: Ref ( .., ty) => Some ( ty) ,
131
168
TyKind :: Raw ( .., ty) if explicit => Some ( ty) ,
132
- & TyKind :: Adt ( chalk_ir:: AdtId ( adt) , ref substs) => {
133
- if crate :: lang_items:: is_box ( db, adt) {
134
- substs. at ( Interner , 0 ) . ty ( Interner )
135
- } else {
136
- None
137
- }
169
+ & TyKind :: Adt ( chalk_ir:: AdtId ( adt) , ref substs) if crate :: lang_items:: is_box ( db, adt) => {
170
+ substs. at ( Interner , 0 ) . ty ( Interner )
138
171
}
139
172
_ => None ,
140
173
}
0 commit comments