@@ -173,46 +173,170 @@ pub fn lookup<'a, 'tcx>(
173
173
174
174
pub fn lookup_in_trait < ' a , ' tcx > (
175
175
fcx : & ' a FnCtxt < ' a , ' tcx > ,
176
-
177
- // In a call `a.b::<X, Y, ...>(...)`:
178
- span : Span , // The expression `a.b(...)`'s span.
179
- self_expr : Option < & ' a ast:: Expr > , // The expression `a`, if available.
180
- m_name : ast:: Name , // The name `b`.
181
- trait_did : DefId , // The trait to limit the lookup to.
182
- self_ty : ty:: t , // The type of `a`.
183
- supplied_tps : & ' a [ ty:: t ] ) // The list of types X, Y, ... .
176
+ span : Span ,
177
+ self_expr : Option < & ' a ast:: Expr > ,
178
+ m_name : ast:: Name ,
179
+ trait_def_id : DefId ,
180
+ self_ty : ty:: t ,
181
+ opt_input_types : Option < Vec < ty:: t > > )
184
182
-> Option < MethodCallee >
185
183
{
186
- let mut lcx = LookupContext {
187
- fcx : fcx,
188
- span : span,
189
- self_expr : self_expr,
190
- m_name : m_name,
191
- supplied_tps : supplied_tps,
192
- impl_dups : HashSet :: new ( ) ,
193
- inherent_candidates : Vec :: new ( ) ,
194
- extension_candidates : Vec :: new ( ) ,
195
- static_candidates : Vec :: new ( ) ,
196
- deref_args : check:: DoDerefArgs ,
197
- check_traits : CheckTraitsOnly ,
198
- autoderef_receiver : DontAutoderefReceiver ,
199
- } ;
184
+ lookup_in_trait_adjusted ( fcx, span, self_expr, m_name, trait_def_id,
185
+ ty:: AutoDerefRef { autoderefs : 0 , autoref : None } ,
186
+ self_ty, opt_input_types)
187
+ }
200
188
201
- debug ! ( "method lookup_in_trait(self_ty={}, self_expr={}, m_name={}, trait_did={})" ,
189
+ pub fn lookup_in_trait_adjusted < ' a , ' tcx > (
190
+ fcx : & ' a FnCtxt < ' a , ' tcx > ,
191
+ span : Span ,
192
+ self_expr : Option < & ' a ast:: Expr > ,
193
+ m_name : ast:: Name ,
194
+ trait_def_id : DefId ,
195
+ autoderefref : ty:: AutoDerefRef ,
196
+ self_ty : ty:: t ,
197
+ opt_input_types : Option < Vec < ty:: t > > )
198
+ -> Option < MethodCallee >
199
+ {
200
+ debug ! ( "method lookup_in_trait(self_ty={}, self_expr={}, m_name={}, trait_def_id={})" ,
202
201
self_ty. repr( fcx. tcx( ) ) ,
203
202
self_expr. repr( fcx. tcx( ) ) ,
204
203
m_name. repr( fcx. tcx( ) ) ,
205
- trait_did. repr( fcx. tcx( ) ) ) ;
204
+ trait_def_id. repr( fcx. tcx( ) ) ) ;
205
+
206
+ let trait_def = ty:: lookup_trait_def ( fcx. tcx ( ) , trait_def_id) ;
207
+
208
+ let expected_number_of_input_types = trait_def. generics . types . len ( subst:: TypeSpace ) ;
209
+ let input_types = match opt_input_types {
210
+ Some ( input_types) => {
211
+ assert_eq ! ( expected_number_of_input_types, input_types. len( ) ) ;
212
+ input_types
213
+ }
214
+
215
+ None => {
216
+ fcx. inh . infcx . next_ty_vars ( expected_number_of_input_types)
217
+ }
218
+ } ;
219
+
220
+ assert_eq ! ( trait_def. generics. types. len( subst:: FnSpace ) , 0 ) ;
221
+ assert ! ( trait_def. generics. regions. is_empty( ) ) ;
206
222
207
- lcx. push_bound_candidates ( self_ty, Some ( trait_did) ) ;
208
- lcx. push_extension_candidate ( trait_did) ;
223
+ // Construct a trait-reference `self_ty : Trait<input_tys>`
224
+ let substs = subst:: Substs :: new_trait ( input_types, Vec :: new ( ) , self_ty) ;
225
+ let trait_ref = Rc :: new ( ty:: TraitRef :: new ( trait_def_id, substs) ) ;
209
226
210
- // when doing a trait search, ambiguity can't really happen except
211
- // as part of the trait-lookup in general
212
- match lcx. search ( self_ty) {
213
- Ok ( callee) => Some ( callee) ,
214
- Err ( _) => None
227
+ // Construct an obligation
228
+ let obligation = traits:: Obligation :: misc ( span, trait_ref. clone ( ) ) ;
229
+
230
+ // Now we want to know if this can be matched
231
+ let mut selcx = traits:: SelectionContext :: new ( fcx. infcx ( ) ,
232
+ & fcx. inh . param_env ,
233
+ fcx) ;
234
+ if !selcx. evaluate_obligation_intracrate ( & obligation) {
235
+ debug ! ( "--> Cannot match obligation" ) ;
236
+ return None ; // Cannot be matched, no such method resolution is possible.
215
237
}
238
+
239
+ // Trait must have a method named `m_name` and it should not have
240
+ // type parameters or early-bound regions.
241
+ let tcx = fcx. tcx ( ) ;
242
+ let ( method_num, method_ty) = trait_method ( tcx, trait_def_id, m_name) . unwrap ( ) ;
243
+ assert_eq ! ( method_ty. generics. types. len( subst:: FnSpace ) , 0 ) ;
244
+ assert_eq ! ( method_ty. generics. regions. len( subst:: FnSpace ) , 0 ) ;
245
+
246
+ // Substitute the trait parameters into the method type and
247
+ // instantiate late-bound regions to get the actual method type.
248
+ let ref bare_fn_ty = method_ty. fty ;
249
+ let fn_sig = bare_fn_ty. sig . subst ( tcx, & trait_ref. substs ) ;
250
+ let fn_sig = replace_late_bound_regions_with_fresh_var ( fcx. infcx ( ) , span,
251
+ fn_sig. binder_id , & fn_sig) ;
252
+ let transformed_self_ty = fn_sig. inputs [ 0 ] ;
253
+ let fty = ty:: mk_bare_fn ( tcx, ty:: BareFnTy {
254
+ sig : fn_sig,
255
+ fn_style : bare_fn_ty. fn_style ,
256
+ abi : bare_fn_ty. abi . clone ( ) ,
257
+ } ) ;
258
+
259
+ debug ! ( "matched method fty={} obligation={}" ,
260
+ fty. repr( fcx. tcx( ) ) ,
261
+ obligation. repr( fcx. tcx( ) ) ) ;
262
+
263
+ // Register obligations for the parameters. This will include the
264
+ // `Self` parameter, which in turn has a bound of the main trait,
265
+ // so this also effectively registers `obligation` as well. (We
266
+ // used to register `obligation` explicitly, but that resulted in
267
+ // double error messages being reported.)
268
+ fcx. add_obligations_for_parameters (
269
+ traits:: ObligationCause :: misc ( span) ,
270
+ & trait_ref. substs ,
271
+ & method_ty. generics ) ;
272
+
273
+ // Insert any adjustments needed (always an autoref of some mutability).
274
+ match self_expr {
275
+ None => { }
276
+
277
+ Some ( self_expr) => {
278
+ debug ! ( "inserting adjustment if needed (self-id = {}, \
279
+ base adjustment = {}, explicit self = {})",
280
+ self_expr. id, autoderefref, method_ty. explicit_self) ;
281
+
282
+ match method_ty. explicit_self {
283
+ ty:: ByValueExplicitSelfCategory => {
284
+ // Trait method is fn(self), no transformation needed.
285
+ if !autoderefref. is_identity ( ) {
286
+ fcx. write_adjustment (
287
+ self_expr. id ,
288
+ span,
289
+ ty:: AdjustDerefRef ( autoderefref) ) ;
290
+ }
291
+ }
292
+
293
+ ty:: ByReferenceExplicitSelfCategory ( ..) => {
294
+ // Trait method is fn(&self) or fn(&mut self), need an
295
+ // autoref. Pull the region etc out of the type of first argument.
296
+ match ty:: get ( transformed_self_ty) . sty {
297
+ ty:: ty_rptr( region, ty:: mt { mutbl, ty : _ } ) => {
298
+ let ty:: AutoDerefRef { autoderefs, autoref } = autoderefref;
299
+ let autoref = autoref. map ( |r| box r) ;
300
+ fcx. write_adjustment (
301
+ self_expr. id ,
302
+ span,
303
+ ty:: AdjustDerefRef ( ty:: AutoDerefRef {
304
+ autoderefs : autoderefs,
305
+ autoref : Some ( ty:: AutoPtr ( region, mutbl, autoref) )
306
+ } ) ) ;
307
+ }
308
+
309
+ _ => {
310
+ fcx. tcx ( ) . sess . span_bug (
311
+ span,
312
+ format ! (
313
+ "trait method is &self but first arg is: {}" ,
314
+ transformed_self_ty. repr( fcx. tcx( ) ) ) . as_slice ( ) ) ;
315
+ }
316
+ }
317
+ }
318
+
319
+ _ => {
320
+ fcx. tcx ( ) . sess . span_bug (
321
+ span,
322
+ format ! (
323
+ "unexpected explicit self type in operator method: {}" ,
324
+ method_ty. explicit_self) . as_slice ( ) ) ;
325
+ }
326
+ }
327
+ }
328
+ }
329
+
330
+ let callee = MethodCallee {
331
+ origin : MethodTypeParam ( MethodParam { trait_ref : trait_ref. clone ( ) ,
332
+ method_num : method_num} ) ,
333
+ ty : fty,
334
+ substs : trait_ref. substs . clone ( )
335
+ } ;
336
+
337
+ debug ! ( "callee = {}" , callee. repr( fcx. tcx( ) ) ) ;
338
+
339
+ Some ( callee)
216
340
}
217
341
218
342
pub fn report_error ( fcx : & FnCtxt ,
@@ -1446,9 +1570,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
1446
1570
}
1447
1571
}
1448
1572
1449
- fn fixup_derefs_on_method_receiver_if_necessary (
1450
- & self ,
1451
- method_callee : & MethodCallee ) {
1573
+ fn fixup_derefs_on_method_receiver_if_necessary ( & self ,
1574
+ method_callee : & MethodCallee ) {
1452
1575
let sig = match ty:: get ( method_callee. ty ) . sty {
1453
1576
ty:: ty_bare_fn( ref f) => f. sig . clone ( ) ,
1454
1577
ty:: ty_closure( ref f) => f. sig . clone ( ) ,
@@ -1485,6 +1608,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
1485
1608
}
1486
1609
}
1487
1610
1611
+ debug ! ( "fixup_derefs_on_method_receiver_if_necessary: exprs={}" ,
1612
+ exprs. repr( self . tcx( ) ) ) ;
1613
+
1488
1614
// Fix up autoderefs and derefs.
1489
1615
for ( i, expr) in exprs. iter ( ) . rev ( ) . enumerate ( ) {
1490
1616
// Count autoderefs.
@@ -1500,6 +1626,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
1500
1626
Some ( _) | None => 0 ,
1501
1627
} ;
1502
1628
1629
+ debug ! ( "fixup_derefs_on_method_receiver_if_necessary: i={} expr={} autoderef_count={}" ,
1630
+ i, expr. repr( self . tcx( ) ) , autoderef_count) ;
1631
+
1503
1632
if autoderef_count > 0 {
1504
1633
check:: autoderef ( self . fcx ,
1505
1634
expr. span ,
@@ -1518,24 +1647,59 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
1518
1647
// Don't retry the first one or we might infinite loop!
1519
1648
if i != 0 {
1520
1649
match expr. node {
1521
- ast:: ExprIndex ( ref base_expr, ref index_expr) => {
1522
- check:: try_overloaded_index (
1523
- self . fcx ,
1524
- Some ( MethodCall :: expr ( expr. id ) ) ,
1525
- * expr,
1650
+ ast:: ExprIndex ( ref base_expr, _) => {
1651
+ let mut base_adjustment =
1652
+ match self . fcx . inh . adjustments . borrow ( ) . find ( & base_expr. id ) {
1653
+ Some ( & ty:: AdjustDerefRef ( ref adr) ) => ( * adr) . clone ( ) ,
1654
+ None => ty:: AutoDerefRef { autoderefs : 0 , autoref : None } ,
1655
+ Some ( _) => {
1656
+ self . tcx ( ) . sess . span_bug (
1657
+ base_expr. span ,
1658
+ "unexpected adjustment type" ) ;
1659
+ }
1660
+ } ;
1661
+
1662
+ // If this is an overloaded index, the
1663
+ // adjustment will include an extra layer of
1664
+ // autoref because the method is an &self/&mut
1665
+ // self method. We have to peel it off to get
1666
+ // the raw adjustment that `try_index_step`
1667
+ // expects. This is annoying and horrible. We
1668
+ // ought to recode this routine so it doesn't
1669
+ // (ab)use the normal type checking paths.
1670
+ base_adjustment. autoref = match base_adjustment. autoref {
1671
+ None => { None }
1672
+ Some ( AutoPtr ( _, _, None ) ) => { None }
1673
+ Some ( AutoPtr ( _, _, Some ( box r) ) ) => { Some ( r) }
1674
+ Some ( _) => {
1675
+ self . tcx ( ) . sess . span_bug (
1676
+ base_expr. span ,
1677
+ "unexpected adjustment autoref" ) ;
1678
+ }
1679
+ } ;
1680
+
1681
+ let adjusted_base_ty =
1682
+ self . fcx . adjust_expr_ty (
1526
1683
& * * base_expr,
1527
- self . fcx . expr_ty ( & * * base_expr) ,
1528
- index_expr,
1529
- PreferMutLvalue ) ;
1684
+ Some ( & ty:: AdjustDerefRef ( base_adjustment. clone ( ) ) ) ) ;
1685
+
1686
+ check:: try_index_step (
1687
+ self . fcx ,
1688
+ MethodCall :: expr ( expr. id ) ,
1689
+ * expr,
1690
+ & * * base_expr,
1691
+ adjusted_base_ty,
1692
+ base_adjustment,
1693
+ PreferMutLvalue ) ;
1530
1694
}
1531
1695
ast:: ExprUnary ( ast:: UnDeref , ref base_expr) => {
1532
1696
check:: try_overloaded_deref (
1533
- self . fcx ,
1534
- expr. span ,
1535
- Some ( MethodCall :: expr ( expr. id ) ) ,
1536
- Some ( & * * base_expr) ,
1537
- self . fcx . expr_ty ( & * * base_expr) ,
1538
- PreferMutLvalue ) ;
1697
+ self . fcx ,
1698
+ expr. span ,
1699
+ Some ( MethodCall :: expr ( expr. id ) ) ,
1700
+ Some ( & * * base_expr) ,
1701
+ self . fcx . expr_ty ( & * * base_expr) ,
1702
+ PreferMutLvalue ) ;
1539
1703
}
1540
1704
_ => { }
1541
1705
}
@@ -1623,15 +1787,25 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
1623
1787
fn replace_late_bound_regions_with_fresh_var < T > ( & self , binder_id : ast:: NodeId , value : & T ) -> T
1624
1788
where T : TypeFoldable + Repr
1625
1789
{
1626
- let ( _, value) = replace_late_bound_regions (
1627
- self . fcx . tcx ( ) ,
1628
- binder_id,
1629
- value,
1630
- |br| self . fcx . infcx ( ) . next_region_var ( infer:: LateBoundRegion ( self . span , br) ) ) ;
1631
- value
1790
+ replace_late_bound_regions_with_fresh_var ( self . fcx . infcx ( ) , self . span , binder_id, value)
1632
1791
}
1633
1792
}
1634
1793
1794
+ fn replace_late_bound_regions_with_fresh_var < T > ( infcx : & infer:: InferCtxt ,
1795
+ span : Span ,
1796
+ binder_id : ast:: NodeId ,
1797
+ value : & T )
1798
+ -> T
1799
+ where T : TypeFoldable + Repr
1800
+ {
1801
+ let ( _, value) = replace_late_bound_regions (
1802
+ infcx. tcx ,
1803
+ binder_id,
1804
+ value,
1805
+ |br| infcx. next_region_var ( infer:: LateBoundRegion ( span, br) ) ) ;
1806
+ value
1807
+ }
1808
+
1635
1809
fn trait_method ( tcx : & ty:: ctxt ,
1636
1810
trait_def_id : ast:: DefId ,
1637
1811
method_name : ast:: Name )
0 commit comments