@@ -173,46 +173,170 @@ pub fn lookup<'a, 'tcx>(
173173
174174pub fn lookup_in_trait < ' a , ' tcx > (
175175 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 > > )
184182 -> Option < MethodCallee >
185183{
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+ }
200188
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={})" ,
202201 self_ty. repr( fcx. tcx( ) ) ,
203202 self_expr. repr( fcx. tcx( ) ) ,
204203 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( ) ) ;
206222
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) ) ;
209226
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.
215237 }
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)
216340}
217341
218342pub fn report_error ( fcx : & FnCtxt ,
@@ -1446,9 +1570,8 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
14461570 }
14471571 }
14481572
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 ) {
14521575 let sig = match ty:: get ( method_callee. ty ) . sty {
14531576 ty:: ty_bare_fn( ref f) => f. sig . clone ( ) ,
14541577 ty:: ty_closure( ref f) => f. sig . clone ( ) ,
@@ -1485,6 +1608,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
14851608 }
14861609 }
14871610
1611+ debug ! ( "fixup_derefs_on_method_receiver_if_necessary: exprs={}" ,
1612+ exprs. repr( self . tcx( ) ) ) ;
1613+
14881614 // Fix up autoderefs and derefs.
14891615 for ( i, expr) in exprs. iter ( ) . rev ( ) . enumerate ( ) {
14901616 // Count autoderefs.
@@ -1500,6 +1626,9 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
15001626 Some ( _) | None => 0 ,
15011627 } ;
15021628
1629+ debug ! ( "fixup_derefs_on_method_receiver_if_necessary: i={} expr={} autoderef_count={}" ,
1630+ i, expr. repr( self . tcx( ) ) , autoderef_count) ;
1631+
15031632 if autoderef_count > 0 {
15041633 check:: autoderef ( self . fcx ,
15051634 expr. span ,
@@ -1518,24 +1647,59 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
15181647 // Don't retry the first one or we might infinite loop!
15191648 if i != 0 {
15201649 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 (
15261683 & * * 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 ) ;
15301694 }
15311695 ast:: ExprUnary ( ast:: UnDeref , ref base_expr) => {
15321696 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 ) ;
15391703 }
15401704 _ => { }
15411705 }
@@ -1623,15 +1787,25 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
16231787 fn replace_late_bound_regions_with_fresh_var < T > ( & self , binder_id : ast:: NodeId , value : & T ) -> T
16241788 where T : TypeFoldable + Repr
16251789 {
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)
16321791 }
16331792}
16341793
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+
16351809fn trait_method ( tcx : & ty:: ctxt ,
16361810 trait_def_id : ast:: DefId ,
16371811 method_name : ast:: Name )
0 commit comments