@@ -4748,9 +4748,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
4748
4748
4749
4749
assert ! ( segments. len( ) >= 1 ) ;
4750
4750
4751
- // In `<T as Trait<A, B>>::method`, `A` and `B` are mandatory.
4752
- let mut require_type_space = opt_self_ty. is_some ( ) ;
4753
-
4751
+ let mut ufcs_method = None ;
4754
4752
let mut segment_spaces: Vec < _ > ;
4755
4753
match def {
4756
4754
// Case 1 and 1b. Reference to a *type* or *enum variant*.
@@ -4777,8 +4775,8 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
4777
4775
}
4778
4776
4779
4777
// Case 3. Reference to a method.
4780
- def:: DefMethod ( _, providence ) => {
4781
- match providence {
4778
+ def:: DefMethod ( _, provenance ) => {
4779
+ match provenance {
4782
4780
def:: FromTrait ( trait_did) => {
4783
4781
callee:: check_legal_trait_for_method_call ( fcx. ccx , span, trait_did)
4784
4782
}
@@ -4791,9 +4789,9 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
4791
4789
segment_spaces. push ( Some ( subst:: FnSpace ) ) ;
4792
4790
} else {
4793
4791
// `<T>::method` will end up here, and so can `T::method`.
4794
- assert ! ( opt_self_ty. is_some( ) ) ;
4795
- require_type_space = false ;
4792
+ let self_ty = opt_self_ty. expect ( "UFCS sugared method missing Self" ) ;
4796
4793
segment_spaces = vec ! [ Some ( subst:: FnSpace ) ] ;
4794
+ ufcs_method = Some ( ( provenance, self_ty) ) ;
4797
4795
}
4798
4796
}
4799
4797
@@ -4812,6 +4810,11 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
4812
4810
}
4813
4811
assert_eq ! ( segment_spaces. len( ) , segments. len( ) ) ;
4814
4812
4813
+ // In `<T as Trait<A, B>>::method`, `A` and `B` are mandatory, but
4814
+ // `opt_self_ty` can also be Some for `Foo::method`, where Foo's
4815
+ // type parameters are not mandatory.
4816
+ let require_type_space = opt_self_ty. is_some ( ) && ufcs_method. is_none ( ) ;
4817
+
4815
4818
debug ! ( "segment_spaces={:?}" , segment_spaces) ;
4816
4819
4817
4820
// Next, examine the definition, and determine how many type
@@ -4879,6 +4882,28 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
4879
4882
// the referenced item.
4880
4883
let ty_substituted = fcx. instantiate_type_scheme ( span, & substs, & type_scheme. ty ) ;
4881
4884
4885
+
4886
+ if let Some ( ( def:: FromImpl ( impl_def_id) , self_ty) ) = ufcs_method {
4887
+ // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
4888
+ // is inherent, there is no `Self` parameter, instead, the impl needs
4889
+ // type parameters, which we can infer by unifying the provided `Self`
4890
+ // with the substituted impl type.
4891
+ let impl_scheme = ty:: lookup_item_type ( fcx. tcx ( ) , impl_def_id) ;
4892
+ assert_eq ! ( substs. types. len( subst:: TypeSpace ) ,
4893
+ impl_scheme. generics. types. len( subst:: TypeSpace ) ) ;
4894
+ assert_eq ! ( substs. regions( ) . len( subst:: TypeSpace ) ,
4895
+ impl_scheme. generics. regions. len( subst:: TypeSpace ) ) ;
4896
+
4897
+ let impl_ty = fcx. instantiate_type_scheme ( span, & substs, & impl_scheme. ty ) ;
4898
+ if fcx. mk_subty ( false , infer:: Misc ( span) , self_ty, impl_ty) . is_err ( ) {
4899
+ fcx. tcx ( ) . sess . span_bug ( span,
4900
+ & format ! (
4901
+ "instantiate_path: (UFCS) {} was a subtype of {} but now is not?" ,
4902
+ self_ty. repr( fcx. tcx( ) ) ,
4903
+ impl_ty. repr( fcx. tcx( ) ) ) ) ;
4904
+ }
4905
+ }
4906
+
4882
4907
fcx. write_ty ( node_id, ty_substituted) ;
4883
4908
fcx. write_substs ( node_id, ty:: ItemSubsts { substs : substs } ) ;
4884
4909
return ;
0 commit comments