@@ -96,6 +96,7 @@ use middle::typeck::{MethodOrigin, MethodParam, MethodTypeParam};
96
96
use middle:: typeck:: { MethodStatic , MethodStaticUnboxedClosure , MethodObject , MethodTraitObject } ;
97
97
use middle:: typeck:: check:: regionmanip:: replace_late_bound_regions;
98
98
use middle:: typeck:: TypeAndSubsts ;
99
+ use middle:: typeck:: check:: vtable;
99
100
use middle:: ty_fold:: TypeFoldable ;
100
101
use util:: common:: indenter;
101
102
use util:: ppaux;
@@ -173,46 +174,178 @@ pub fn lookup<'a, 'tcx>(
173
174
174
175
pub fn lookup_in_trait < ' a , ' tcx > (
175
176
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, ... .
177
+ span : Span ,
178
+ self_expr : Option < & ' a ast:: Expr > ,
179
+ m_name : ast:: Name ,
180
+ trait_def_id : DefId ,
181
+ self_ty : ty:: t ,
182
+ opt_input_types : Option < Vec < ty:: t > > )
184
183
-> Option < MethodCallee >
185
184
{
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
- } ;
185
+ lookup_in_trait_adjusted ( fcx, span, self_expr, m_name, trait_def_id,
186
+ ty:: AutoDerefRef { autoderefs : 0 , autoref : None } ,
187
+ self_ty, opt_input_types)
188
+ }
200
189
201
- debug ! ( "method lookup_in_trait(self_ty={}, self_expr={}, m_name={}, trait_did={})" ,
190
+ pub fn lookup_in_trait_adjusted < ' a , ' tcx > (
191
+ fcx : & ' a FnCtxt < ' a , ' tcx > ,
192
+ span : Span ,
193
+ self_expr : Option < & ' a ast:: Expr > ,
194
+ m_name : ast:: Name ,
195
+ trait_def_id : DefId ,
196
+ autoderefref : ty:: AutoDerefRef ,
197
+ self_ty : ty:: t ,
198
+ opt_input_types : Option < Vec < ty:: t > > )
199
+ -> Option < MethodCallee >
200
+ {
201
+ debug ! ( "method lookup_in_trait(self_ty={}, self_expr={}, m_name={}, trait_def_id={})" ,
202
202
self_ty. repr( fcx. tcx( ) ) ,
203
203
self_expr. repr( fcx. tcx( ) ) ,
204
204
m_name. repr( fcx. tcx( ) ) ,
205
- trait_did. repr( fcx. tcx( ) ) ) ;
205
+ trait_def_id. repr( fcx. tcx( ) ) ) ;
206
+
207
+ let trait_def = ty:: lookup_trait_def ( fcx. tcx ( ) , trait_def_id) ;
208
+
209
+ let expected_number_of_input_types = trait_def. generics . types . len ( subst:: TypeSpace ) ;
210
+ let input_types = match opt_input_types {
211
+ Some ( input_types) => {
212
+ assert_eq ! ( expected_number_of_input_types, input_types. len( ) ) ;
213
+ input_types
214
+ }
215
+
216
+ None => {
217
+ fcx. inh . infcx . next_ty_vars ( expected_number_of_input_types)
218
+ }
219
+ } ;
220
+
221
+ let number_assoc_types = trait_def. generics . types . len ( subst:: AssocSpace ) ;
222
+ let assoc_types = fcx. inh . infcx . next_ty_vars ( number_assoc_types) ;
206
223
207
- lcx . push_bound_candidates ( self_ty , Some ( trait_did ) ) ;
208
- lcx . push_extension_candidate ( trait_did ) ;
224
+ assert_eq ! ( trait_def . generics . types . len ( subst :: FnSpace ) , 0 ) ;
225
+ assert ! ( trait_def . generics . regions . is_empty ( ) ) ;
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 a trait-reference `self_ty : Trait<input_tys>`
228
+ let substs = subst:: Substs :: new_trait ( input_types, Vec :: new ( ) , assoc_types, self_ty) ;
229
+ let trait_ref = Rc :: new ( ty:: TraitRef :: new ( trait_def_id, substs) ) ;
230
+
231
+ // Construct an obligation
232
+ let obligation = traits:: Obligation :: misc ( span, trait_ref. clone ( ) ) ;
233
+
234
+ // Now we want to know if this can be matched
235
+ let mut selcx = traits:: SelectionContext :: new ( fcx. infcx ( ) ,
236
+ & fcx. inh . param_env ,
237
+ fcx) ;
238
+ if !selcx. evaluate_obligation_intracrate ( & obligation) {
239
+ debug ! ( "--> Cannot match obligation" ) ;
240
+ return None ; // Cannot be matched, no such method resolution is possible.
241
+ }
242
+
243
+ // Trait must have a method named `m_name` and it should not have
244
+ // type parameters or early-bound regions.
245
+ let tcx = fcx. tcx ( ) ;
246
+ let ( method_num, method_ty) = trait_method ( tcx, trait_def_id, m_name) . unwrap ( ) ;
247
+ assert_eq ! ( method_ty. generics. types. len( subst:: FnSpace ) , 0 ) ;
248
+ assert_eq ! ( method_ty. generics. regions. len( subst:: FnSpace ) , 0 ) ;
249
+
250
+ // Substitute the trait parameters into the method type and
251
+ // instantiate late-bound regions to get the actual method type.
252
+ let ref bare_fn_ty = method_ty. fty ;
253
+ let fn_sig = bare_fn_ty. sig . subst ( tcx, & trait_ref. substs ) ;
254
+ let fn_sig = replace_late_bound_regions_with_fresh_var ( fcx. infcx ( ) , span,
255
+ fn_sig. binder_id , & fn_sig) ;
256
+ let transformed_self_ty = fn_sig. inputs [ 0 ] ;
257
+ let fty = ty:: mk_bare_fn ( tcx, ty:: BareFnTy {
258
+ sig : fn_sig,
259
+ fn_style : bare_fn_ty. fn_style ,
260
+ abi : bare_fn_ty. abi . clone ( ) ,
261
+ } ) ;
262
+
263
+ debug ! ( "matched method fty={} obligation={}" ,
264
+ fty. repr( fcx. tcx( ) ) ,
265
+ obligation. repr( fcx. tcx( ) ) ) ;
266
+
267
+ // Register obligations for the parameters. This will include the
268
+ // `Self` parameter, which in turn has a bound of the main trait,
269
+ // so this also effectively registers `obligation` as well. (We
270
+ // used to register `obligation` explicitly, but that resulted in
271
+ // double error messages being reported.)
272
+ fcx. add_obligations_for_parameters (
273
+ traits:: ObligationCause :: misc ( span) ,
274
+ & trait_ref. substs ,
275
+ & method_ty. generics ) ;
276
+
277
+ // FIXME(#18653) -- Try to resolve obligations, giving us more
278
+ // typing information, which can sometimes be needed to avoid
279
+ // pathological region inference failures.
280
+ vtable:: select_new_fcx_obligations ( fcx) ;
281
+
282
+ // Insert any adjustments needed (always an autoref of some mutability).
283
+ match self_expr {
284
+ None => { }
285
+
286
+ Some ( self_expr) => {
287
+ debug ! ( "inserting adjustment if needed (self-id = {}, \
288
+ base adjustment = {}, explicit self = {})",
289
+ self_expr. id, autoderefref, method_ty. explicit_self) ;
290
+
291
+ match method_ty. explicit_self {
292
+ ty:: ByValueExplicitSelfCategory => {
293
+ // Trait method is fn(self), no transformation needed.
294
+ if !autoderefref. is_identity ( ) {
295
+ fcx. write_adjustment (
296
+ self_expr. id ,
297
+ span,
298
+ ty:: AdjustDerefRef ( autoderefref) ) ;
299
+ }
300
+ }
301
+
302
+ ty:: ByReferenceExplicitSelfCategory ( ..) => {
303
+ // Trait method is fn(&self) or fn(&mut self), need an
304
+ // autoref. Pull the region etc out of the type of first argument.
305
+ match ty:: get ( transformed_self_ty) . sty {
306
+ ty:: ty_rptr( region, ty:: mt { mutbl, ty : _ } ) => {
307
+ let ty:: AutoDerefRef { autoderefs, autoref } = autoderefref;
308
+ let autoref = autoref. map ( |r| box r) ;
309
+ fcx. write_adjustment (
310
+ self_expr. id ,
311
+ span,
312
+ ty:: AdjustDerefRef ( ty:: AutoDerefRef {
313
+ autoderefs : autoderefs,
314
+ autoref : Some ( ty:: AutoPtr ( region, mutbl, autoref) )
315
+ } ) ) ;
316
+ }
317
+
318
+ _ => {
319
+ fcx. tcx ( ) . sess . span_bug (
320
+ span,
321
+ format ! (
322
+ "trait method is &self but first arg is: {}" ,
323
+ transformed_self_ty. repr( fcx. tcx( ) ) ) . as_slice ( ) ) ;
324
+ }
325
+ }
326
+ }
327
+
328
+ _ => {
329
+ fcx. tcx ( ) . sess . span_bug (
330
+ span,
331
+ format ! (
332
+ "unexpected explicit self type in operator method: {}" ,
333
+ method_ty. explicit_self) . as_slice ( ) ) ;
334
+ }
335
+ }
336
+ }
215
337
}
338
+
339
+ let callee = MethodCallee {
340
+ origin : MethodTypeParam ( MethodParam { trait_ref : trait_ref. clone ( ) ,
341
+ method_num : method_num} ) ,
342
+ ty : fty,
343
+ substs : trait_ref. substs . clone ( )
344
+ } ;
345
+
346
+ debug ! ( "callee = {}" , callee. repr( fcx. tcx( ) ) ) ;
347
+
348
+ Some ( callee)
216
349
}
217
350
218
351
pub fn report_error ( fcx : & FnCtxt ,
@@ -1446,9 +1579,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
1446
1579
}
1447
1580
}
1448
1581
1449
- fn fixup_derefs_on_method_receiver_if_necessary (
1450
- & self ,
1451
- method_callee : & MethodCallee ) {
1582
+ fn fixup_derefs_on_method_receiver_if_necessary ( & self ,
1583
+ method_callee : & MethodCallee ) {
1452
1584
let sig = match ty:: get ( method_callee. ty ) . sty {
1453
1585
ty:: ty_bare_fn( ref f) => f. sig . clone ( ) ,
1454
1586
ty:: ty_closure( ref f) => f. sig . clone ( ) ,
@@ -1485,6 +1617,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
1485
1617
}
1486
1618
}
1487
1619
1620
+ debug ! ( "fixup_derefs_on_method_receiver_if_necessary: exprs={}" ,
1621
+ exprs. repr( self . tcx( ) ) ) ;
1622
+
1488
1623
// Fix up autoderefs and derefs.
1489
1624
for ( i, expr) in exprs. iter ( ) . rev ( ) . enumerate ( ) {
1490
1625
// Count autoderefs.
@@ -1500,6 +1635,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
1500
1635
Some ( _) | None => 0 ,
1501
1636
} ;
1502
1637
1638
+ debug ! ( "fixup_derefs_on_method_receiver_if_necessary: i={} expr={} autoderef_count={}" ,
1639
+ i, expr. repr( self . tcx( ) ) , autoderef_count) ;
1640
+
1503
1641
if autoderef_count > 0 {
1504
1642
check:: autoderef ( self . fcx ,
1505
1643
expr. span ,
@@ -1518,24 +1656,59 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
1518
1656
// Don't retry the first one or we might infinite loop!
1519
1657
if i != 0 {
1520
1658
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,
1659
+ ast:: ExprIndex ( ref base_expr, _) => {
1660
+ let mut base_adjustment =
1661
+ match self . fcx . inh . adjustments . borrow ( ) . find ( & base_expr. id ) {
1662
+ Some ( & ty:: AdjustDerefRef ( ref adr) ) => ( * adr) . clone ( ) ,
1663
+ None => ty:: AutoDerefRef { autoderefs : 0 , autoref : None } ,
1664
+ Some ( _) => {
1665
+ self . tcx ( ) . sess . span_bug (
1666
+ base_expr. span ,
1667
+ "unexpected adjustment type" ) ;
1668
+ }
1669
+ } ;
1670
+
1671
+ // If this is an overloaded index, the
1672
+ // adjustment will include an extra layer of
1673
+ // autoref because the method is an &self/&mut
1674
+ // self method. We have to peel it off to get
1675
+ // the raw adjustment that `try_index_step`
1676
+ // expects. This is annoying and horrible. We
1677
+ // ought to recode this routine so it doesn't
1678
+ // (ab)use the normal type checking paths.
1679
+ base_adjustment. autoref = match base_adjustment. autoref {
1680
+ None => { None }
1681
+ Some ( AutoPtr ( _, _, None ) ) => { None }
1682
+ Some ( AutoPtr ( _, _, Some ( box r) ) ) => { Some ( r) }
1683
+ Some ( _) => {
1684
+ self . tcx ( ) . sess . span_bug (
1685
+ base_expr. span ,
1686
+ "unexpected adjustment autoref" ) ;
1687
+ }
1688
+ } ;
1689
+
1690
+ let adjusted_base_ty =
1691
+ self . fcx . adjust_expr_ty (
1526
1692
& * * base_expr,
1527
- self . fcx . expr_ty ( & * * base_expr) ,
1528
- index_expr,
1529
- PreferMutLvalue ) ;
1693
+ Some ( & ty:: AdjustDerefRef ( base_adjustment. clone ( ) ) ) ) ;
1694
+
1695
+ check:: try_index_step (
1696
+ self . fcx ,
1697
+ MethodCall :: expr ( expr. id ) ,
1698
+ * expr,
1699
+ & * * base_expr,
1700
+ adjusted_base_ty,
1701
+ base_adjustment,
1702
+ PreferMutLvalue ) ;
1530
1703
}
1531
1704
ast:: ExprUnary ( ast:: UnDeref , ref base_expr) => {
1532
1705
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 ) ;
1706
+ self . fcx ,
1707
+ expr. span ,
1708
+ Some ( MethodCall :: expr ( expr. id ) ) ,
1709
+ Some ( & * * base_expr) ,
1710
+ self . fcx . expr_ty ( & * * base_expr) ,
1711
+ PreferMutLvalue ) ;
1539
1712
}
1540
1713
_ => { }
1541
1714
}
@@ -1623,15 +1796,25 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
1623
1796
fn replace_late_bound_regions_with_fresh_var < T > ( & self , binder_id : ast:: NodeId , value : & T ) -> T
1624
1797
where T : TypeFoldable + Repr
1625
1798
{
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
1799
+ replace_late_bound_regions_with_fresh_var ( self . fcx . infcx ( ) , self . span , binder_id, value)
1632
1800
}
1633
1801
}
1634
1802
1803
+ fn replace_late_bound_regions_with_fresh_var < T > ( infcx : & infer:: InferCtxt ,
1804
+ span : Span ,
1805
+ binder_id : ast:: NodeId ,
1806
+ value : & T )
1807
+ -> T
1808
+ where T : TypeFoldable + Repr
1809
+ {
1810
+ let ( _, value) = replace_late_bound_regions (
1811
+ infcx. tcx ,
1812
+ binder_id,
1813
+ value,
1814
+ |br| infcx. next_region_var ( infer:: LateBoundRegion ( span, br) ) ) ;
1815
+ value
1816
+ }
1817
+
1635
1818
fn trait_method ( tcx : & ty:: ctxt ,
1636
1819
trait_def_id : ast:: DefId ,
1637
1820
method_name : ast:: Name )
0 commit comments