@@ -154,6 +154,42 @@ enum ProbeResult {
154154 Match ,
155155}
156156
157+ /// When adjusting a receiver we often want to do one of
158+ ///
159+ /// - Add a `&` (or `&mut`), converting the recevier from `T` to `&T` (or `&mut T`)
160+ /// - If the receiver has type `*mut T`, convert it to `*const T`
161+ ///
162+ /// This type tells us which one to do.
163+ ///
164+ /// Note that in principle we could do both at the same time. For example, when the receiver has
165+ /// type `T`, we could autoref it to `&T`, then convert to `*const T`. Or, when it has type `*mut
166+ /// T`, we could convert it to `*const T`, then autoref to `&*const T`. However, currently we do
167+ /// (at most) one of these. Either the receiver has type `T` and we convert it to `&T` (or with
168+ /// `mut`), or it has type `*mut T` and we convert it to `*const T`.
169+ #[ derive( Debug , PartialEq , Clone ) ]
170+ pub enum AutorefOrPtrAdjustment < ' tcx > {
171+ /// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it.
172+ /// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing.
173+ Autoref {
174+ mutbl : hir:: Mutability ,
175+
176+ /// Indicates that the source expression should be "unsized" to a target type. This should
177+ /// probably eventually go away in favor of just coercing method receivers.
178+ unsize : Option < Ty < ' tcx > > ,
179+ } ,
180+ /// Receiver has type `*mut T`, convert to `*const T`
181+ ToConstPtr ,
182+ }
183+
184+ impl < ' tcx > AutorefOrPtrAdjustment < ' tcx > {
185+ fn get_unsize ( & self ) -> Option < Ty < ' tcx > > {
186+ match self {
187+ AutorefOrPtrAdjustment :: Autoref { mutbl : _, unsize } => unsize. clone ( ) ,
188+ AutorefOrPtrAdjustment :: ToConstPtr => None ,
189+ }
190+ }
191+ }
192+
157193#[ derive( Debug , PartialEq , Clone ) ]
158194pub struct Pick < ' tcx > {
159195 pub item : ty:: AssocItem ,
@@ -165,17 +201,9 @@ pub struct Pick<'tcx> {
165201 /// A = expr | *expr | **expr | ...
166202 pub autoderefs : usize ,
167203
168- /// Indicates that an autoref is applied after the optional autoderefs
169- ///
170- /// B = A | &A | &mut A
171- pub autoref : Option < hir:: Mutability > ,
172-
173- /// Indicates that the source expression should be "unsized" to a
174- /// target type. This should probably eventually go away in favor
175- /// of just coercing method receivers.
176- ///
177- /// C = B | unsize(B)
178- pub unsize : Option < Ty < ' tcx > > ,
204+ /// Indicates that we want to add an autoref (and maybe also unsize it), or if the receiver is
205+ /// `*mut T`, convert it to `*const T`.
206+ pub autoref_or_ptr_adjustment : Option < AutorefOrPtrAdjustment < ' tcx > > ,
179207}
180208
181209#[ derive( Clone , Debug , PartialEq , Eq ) ]
@@ -714,16 +742,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
714742
715743 debug ! ( "assemble_inherent_impl_probe {:?}" , impl_def_id) ;
716744
745+ let ( impl_ty, impl_substs) = self . impl_ty_and_substs ( impl_def_id) ;
746+ let impl_ty = impl_ty. subst ( self . tcx , impl_substs) ;
747+
717748 for item in self . impl_or_trait_item ( impl_def_id) {
718749 if !self . has_applicable_self ( & item) {
719750 // No receiver declared. Not a candidate.
720751 self . record_static_candidate ( ImplSource ( impl_def_id) ) ;
721752 continue ;
722753 }
723754
724- let ( impl_ty, impl_substs) = self . impl_ty_and_substs ( impl_def_id) ;
725- let impl_ty = impl_ty. subst ( self . tcx , impl_substs) ;
726-
727755 // Determine the receiver type that the method itself expects.
728756 let xform_tys = self . xform_self_ty ( & item, impl_ty, impl_substs) ;
729757
@@ -1086,6 +1114,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10861114 self . pick_by_value_method ( step, self_ty) . or_else ( || {
10871115 self . pick_autorefd_method ( step, self_ty, hir:: Mutability :: Not )
10881116 . or_else ( || self . pick_autorefd_method ( step, self_ty, hir:: Mutability :: Mut ) )
1117+ . or_else ( || self . pick_const_ptr_method ( step, self_ty) )
10891118 } )
10901119 } )
10911120 . next ( )
@@ -1113,7 +1142,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11131142 // Insert a `&*` or `&mut *` if this is a reference type:
11141143 if let ty:: Ref ( _, _, mutbl) = * step. self_ty . value . value . kind ( ) {
11151144 pick. autoderefs += 1 ;
1116- pick. autoref = Some ( mutbl) ;
1145+ pick. autoref_or_ptr_adjustment = Some ( AutorefOrPtrAdjustment :: Autoref {
1146+ mutbl,
1147+ unsize : pick. autoref_or_ptr_adjustment . and_then ( |a| a. get_unsize ( ) ) ,
1148+ } )
11171149 }
11181150
11191151 pick
@@ -1136,8 +1168,39 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11361168 self . pick_method ( autoref_ty) . map ( |r| {
11371169 r. map ( |mut pick| {
11381170 pick. autoderefs = step. autoderefs ;
1139- pick. autoref = Some ( mutbl) ;
1140- pick. unsize = step. unsize . then_some ( self_ty) ;
1171+ pick. autoref_or_ptr_adjustment = Some ( AutorefOrPtrAdjustment :: Autoref {
1172+ mutbl,
1173+ unsize : step. unsize . then_some ( self_ty) ,
1174+ } ) ;
1175+ pick
1176+ } )
1177+ } )
1178+ }
1179+
1180+ /// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a
1181+ /// special case for this is because going from `*mut T` to `*const T` with autoderefs and
1182+ /// autorefs would require dereferencing the pointer, which is not safe.
1183+ fn pick_const_ptr_method (
1184+ & mut self ,
1185+ step : & CandidateStep < ' tcx > ,
1186+ self_ty : Ty < ' tcx > ,
1187+ ) -> Option < PickResult < ' tcx > > {
1188+ // Don't convert an unsized reference to ptr
1189+ if step. unsize {
1190+ return None ;
1191+ }
1192+
1193+ let ty = match self_ty. kind ( ) {
1194+ ty:: RawPtr ( ty:: TypeAndMut { ty, mutbl : hir:: Mutability :: Mut } ) => ty,
1195+ _ => return None ,
1196+ } ;
1197+
1198+ let const_self_ty = ty:: TypeAndMut { ty, mutbl : hir:: Mutability :: Not } ;
1199+ let const_ptr_ty = self . tcx . mk_ptr ( const_self_ty) ;
1200+ self . pick_method ( const_ptr_ty) . map ( |r| {
1201+ r. map ( |mut pick| {
1202+ pick. autoderefs = step. autoderefs ;
1203+ pick. autoref_or_ptr_adjustment = Some ( AutorefOrPtrAdjustment :: ToConstPtr ) ;
11411204 pick
11421205 } )
11431206 } )
@@ -1510,8 +1573,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
15101573 kind : TraitPick ,
15111574 import_ids : probes[ 0 ] . 0 . import_ids . clone ( ) ,
15121575 autoderefs : 0 ,
1513- autoref : None ,
1514- unsize : None ,
1576+ autoref_or_ptr_adjustment : None ,
15151577 } )
15161578 }
15171579
@@ -1748,8 +1810,7 @@ impl<'tcx> Candidate<'tcx> {
17481810 } ,
17491811 import_ids : self . import_ids . clone ( ) ,
17501812 autoderefs : 0 ,
1751- autoref : None ,
1752- unsize : None ,
1813+ autoref_or_ptr_adjustment : None ,
17531814 }
17541815 }
17551816}
0 commit comments