33//! reference to a type with the field `bar`. This is an approximation of the
44//! logic in rustc (which lives in rustc_hir_analysis/check/autoderef.rs).
55
6+ use std:: mem;
7+
68use chalk_ir:: cast:: Cast ;
79use hir_def:: lang_item:: LangItem ;
810use hir_expand:: name:: Name ;
@@ -37,7 +39,7 @@ pub fn autoderef(
3739) -> impl Iterator < Item = Ty > {
3840 let mut table = InferenceTable :: new ( db, env) ;
3941 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 ) ;
4143 let mut v = Vec :: new ( ) ;
4244 while let Some ( ( ty, _steps) ) = autoderef. next ( ) {
4345 // `ty` may contain unresolved inference variables. Since there's no chance they would be
@@ -58,41 +60,76 @@ pub fn autoderef(
5860 v. into_iter ( )
5961}
6062
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+
6185#[ 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 > ,
6488 ty : Ty ,
6589 at_start : bool ,
66- steps : Vec < ( AutoderefKind , Ty ) > ,
90+ steps : T ,
6791 explicit : bool ,
6892}
6993
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 {
7296 let ty = table. resolve_ty_shallow ( & ty) ;
7397 Autoderef { table, ty, at_start : true , steps : Vec :: new ( ) , explicit }
7498 }
7599
76- pub ( crate ) fn step_count ( & self ) -> usize {
77- self . steps . len ( )
78- }
79-
80100 pub ( crate ) fn steps ( & self ) -> & [ ( AutoderefKind , Ty ) ] {
81101 & self . steps
82102 }
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+ }
83121
84122 pub ( crate ) fn final_ty ( & self ) -> Ty {
85123 self . ty . clone ( )
86124 }
87125}
88126
89- impl Iterator for Autoderef < ' _ , ' _ > {
127+ impl < T : TrackAutoderefSteps > Iterator for Autoderef < ' _ , ' _ , T > {
90128 type Item = ( Ty , usize ) ;
91129
92130 #[ tracing:: instrument( skip_all) ]
93131 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 ) {
96133 return Some ( ( self . ty . clone ( ) , 0 ) ) ;
97134 }
98135
@@ -102,7 +139,7 @@ impl Iterator for Autoderef<'_, '_> {
102139
103140 let ( kind, new_ty) = autoderef_step ( self . table , self . ty . clone ( ) , self . explicit ) ?;
104141
105- self . steps . push ( ( kind, self . ty . clone ( ) ) ) ;
142+ self . steps . push ( kind, & self . ty ) ;
106143 self . ty = new_ty;
107144
108145 Some ( ( self . ty . clone ( ) , self . step_count ( ) ) )
@@ -129,12 +166,8 @@ pub(crate) fn builtin_deref<'ty>(
129166 match ty. kind ( Interner ) {
130167 TyKind :: Ref ( .., ty) => Some ( ty) ,
131168 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 )
138171 }
139172 _ => None ,
140173 }
0 commit comments