Skip to content

Commit 8501c9d

Browse files
committed
rustc_typeck: unify the impl type with the UFCS path prefix type.
1 parent f0efa2d commit 8501c9d

File tree

1 file changed

+32
-7
lines changed
  • src/librustc_typeck/check

1 file changed

+32
-7
lines changed

src/librustc_typeck/check/mod.rs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4748,9 +4748,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
47484748

47494749
assert!(segments.len() >= 1);
47504750

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;
47544752
let mut segment_spaces: Vec<_>;
47554753
match def {
47564754
// 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>,
47774775
}
47784776

47794777
// Case 3. Reference to a method.
4780-
def::DefMethod(_, providence) => {
4781-
match providence {
4778+
def::DefMethod(_, provenance) => {
4779+
match provenance {
47824780
def::FromTrait(trait_did) => {
47834781
callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did)
47844782
}
@@ -4791,9 +4789,9 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
47914789
segment_spaces.push(Some(subst::FnSpace));
47924790
} else {
47934791
// `<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");
47964793
segment_spaces = vec![Some(subst::FnSpace)];
4794+
ufcs_method = Some((provenance, self_ty));
47974795
}
47984796
}
47994797

@@ -4812,6 +4810,11 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
48124810
}
48134811
assert_eq!(segment_spaces.len(), segments.len());
48144812

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+
48154818
debug!("segment_spaces={:?}", segment_spaces);
48164819

48174820
// Next, examine the definition, and determine how many type
@@ -4879,6 +4882,28 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
48794882
// the referenced item.
48804883
let ty_substituted = fcx.instantiate_type_scheme(span, &substs, &type_scheme.ty);
48814884

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+
48824907
fcx.write_ty(node_id, ty_substituted);
48834908
fcx.write_substs(node_id, ty::ItemSubsts { substs: substs });
48844909
return;

0 commit comments

Comments
 (0)