@@ -154,6 +154,42 @@ enum ProbeResult {
154
154
Match ,
155
155
}
156
156
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
+
157
193
#[ derive( Debug , PartialEq , Clone ) ]
158
194
pub struct Pick < ' tcx > {
159
195
pub item : ty:: AssocItem ,
@@ -165,17 +201,9 @@ pub struct Pick<'tcx> {
165
201
/// A = expr | *expr | **expr | ...
166
202
pub autoderefs : usize ,
167
203
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 > > ,
179
207
}
180
208
181
209
#[ derive( Clone , Debug , PartialEq , Eq ) ]
@@ -714,16 +742,16 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
714
742
715
743
debug ! ( "assemble_inherent_impl_probe {:?}" , impl_def_id) ;
716
744
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
+
717
748
for item in self . impl_or_trait_item ( impl_def_id) {
718
749
if !self . has_applicable_self ( & item) {
719
750
// No receiver declared. Not a candidate.
720
751
self . record_static_candidate ( ImplSource ( impl_def_id) ) ;
721
752
continue ;
722
753
}
723
754
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
-
727
755
// Determine the receiver type that the method itself expects.
728
756
let xform_tys = self . xform_self_ty ( & item, impl_ty, impl_substs) ;
729
757
@@ -1086,6 +1114,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1086
1114
self . pick_by_value_method ( step, self_ty) . or_else ( || {
1087
1115
self . pick_autorefd_method ( step, self_ty, hir:: Mutability :: Not )
1088
1116
. or_else ( || self . pick_autorefd_method ( step, self_ty, hir:: Mutability :: Mut ) )
1117
+ . or_else ( || self . pick_const_ptr_method ( step, self_ty) )
1089
1118
} )
1090
1119
} )
1091
1120
. next ( )
@@ -1113,7 +1142,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1113
1142
// Insert a `&*` or `&mut *` if this is a reference type:
1114
1143
if let ty:: Ref ( _, _, mutbl) = * step. self_ty . value . value . kind ( ) {
1115
1144
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
+ } )
1117
1149
}
1118
1150
1119
1151
pick
@@ -1136,8 +1168,39 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1136
1168
self . pick_method ( autoref_ty) . map ( |r| {
1137
1169
r. map ( |mut pick| {
1138
1170
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 ) ;
1141
1204
pick
1142
1205
} )
1143
1206
} )
@@ -1510,8 +1573,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
1510
1573
kind : TraitPick ,
1511
1574
import_ids : probes[ 0 ] . 0 . import_ids . clone ( ) ,
1512
1575
autoderefs : 0 ,
1513
- autoref : None ,
1514
- unsize : None ,
1576
+ autoref_or_ptr_adjustment : None ,
1515
1577
} )
1516
1578
}
1517
1579
@@ -1748,8 +1810,7 @@ impl<'tcx> Candidate<'tcx> {
1748
1810
} ,
1749
1811
import_ids : self . import_ids . clone ( ) ,
1750
1812
autoderefs : 0 ,
1751
- autoref : None ,
1752
- unsize : None ,
1813
+ autoref_or_ptr_adjustment : None ,
1753
1814
}
1754
1815
}
1755
1816
}
0 commit comments