diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 6c2dfaf4413..e9e43950fb2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -24,7 +24,7 @@ use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::{ self, AdtKind, CanonicalUserType, DefIdTree, GenericParamDefKind, Ty, UserType, }; -use rustc_middle::ty::{GenericArgKind, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts}; +use rustc_middle::ty::{GenericArgKind, SubstsRef, UserSelfTy, UserSubsts}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; @@ -161,47 +161,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id))); self.write_substs(hir_id, method.substs); - - // When the method is confirmed, the `method.substs` includes - // parameters from not just the method, but also the impl of - // the method -- in particular, the `Self` type will be fully - // resolved. However, those are not something that the "user - // specified" -- i.e., those types come from the inferred type - // of the receiver, not something the user wrote. So when we - // create the user-substs, we want to replace those earlier - // types with just the types that the user actually wrote -- - // that is, those that appear on the *method itself*. - // - // As an example, if the user wrote something like - // `foo.bar::(...)` -- the `Self` type here will be the - // type of `foo` (possibly adjusted), but we don't want to - // include that. We want just the `[_, u32]` part. - if !method.substs.is_empty() { - let method_generics = self.tcx.generics_of(method.def_id); - if !method_generics.params.is_empty() { - let user_type_annotation = self.probe(|_| { - let user_substs = UserSubsts { - substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| { - let i = param.index as usize; - if i < method_generics.parent_count { - self.var_for_def(DUMMY_SP, param) - } else { - method.substs[i] - } - }), - user_self_ty: None, // not relevant here - }; - - self.canonicalize_user_type_annotation(UserType::TypeOf( - method.def_id, - user_substs, - )) - }); - - debug!("write_method_call: user_type_annotation={:?}", user_type_annotation); - self.write_user_type_annotation(hir_id, user_type_annotation); - } - } } pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) { diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index f2a41720b60..a2c6e246610 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -12,7 +12,8 @@ use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutabili use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{self, SubstsRef}; use rustc_middle::ty::{self, GenericParamDefKind, Ty}; -use rustc_span::Span; +use rustc_middle::ty::{InternalSubsts, UserSubsts, UserType}; +use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::traits; use std::iter; @@ -397,6 +398,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.cfcx.var_for_def(self.cfcx.span, param) } } + let substs = >::create_substs_for_generic_args( self.tcx, pick.item.def_id, @@ -406,7 +408,45 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { &arg_count_correct, &mut MethodSubstsCtxt { cfcx: self, pick, seg }, ); - // FIXME(aliemjay): Type annotation should be registered before normalization. + + // When the method is confirmed, the `substs` includes + // parameters from not just the method, but also the impl of + // the method -- in particular, the `Self` type will be fully + // resolved. However, those are not something that the "user + // specified" -- i.e., those types come from the inferred type + // of the receiver, not something the user wrote. So when we + // create the user-substs, we want to replace those earlier + // types with just the types that the user actually wrote -- + // that is, those that appear on the *method itself*. + // + // As an example, if the user wrote something like + // `foo.bar::(...)` -- the `Self` type here will be the + // type of `foo` (possibly adjusted), but we don't want to + // include that. We want just the `[_, u32]` part. + if !substs.is_empty() && !generics.params.is_empty() { + let user_type_annotation = self.probe(|_| { + let user_substs = UserSubsts { + substs: InternalSubsts::for_item(self.tcx, pick.item.def_id, |param, _| { + let i = param.index as usize; + if i < generics.parent_count { + self.fcx.var_for_def(DUMMY_SP, param) + } else { + substs[i] + } + }), + user_self_ty: None, // not relevant here + }; + + self.fcx.canonicalize_user_type_annotation(UserType::TypeOf( + pick.item.def_id, + user_substs, + )) + }); + + debug!("instantiate_method_substs: user_type_annotation={:?}", user_type_annotation); + self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation); + } + self.normalize(self.span, substs) } diff --git a/src/test/ui/nll/user-annotations/normalization-2.rs b/src/test/ui/nll/user-annotations/normalization-2.rs index 92600155c7f..232b957d51f 100644 --- a/src/test/ui/nll/user-annotations/normalization-2.rs +++ b/src/test/ui/nll/user-annotations/normalization-2.rs @@ -68,8 +68,8 @@ fn test_variants<'a, 'b, 'c>() { } fn test_method_call<'a>(x: MyTy<()>) { - // FIXME This should fail. x.method2::>(); + //~^ ERROR lifetime may not live long enough } fn test_struct_path<'a, 'b, 'c, 'd>() { diff --git a/src/test/ui/nll/user-annotations/normalization-2.stderr b/src/test/ui/nll/user-annotations/normalization-2.stderr index 5dbdb2ecea8..50382cfd953 100644 --- a/src/test/ui/nll/user-annotations/normalization-2.stderr +++ b/src/test/ui/nll/user-annotations/normalization-2.stderr @@ -114,6 +114,14 @@ help: the following changes may resolve your lifetime errors = help: replace `'b` with `'static` = help: replace `'c` with `'static` +error: lifetime may not live long enough + --> $DIR/normalization-2.rs:71:7 + | +LL | fn test_method_call<'a>(x: MyTy<()>) { + | -- lifetime `'a` defined here +LL | x.method2::>(); + | ^^^^^^^ requires that `'a` must outlive `'static` + error: lifetime may not live long enough --> $DIR/normalization-2.rs:88:5 | @@ -190,5 +198,5 @@ help: the following changes may resolve your lifetime errors = help: replace `'b` with `'static` = help: replace `'c` with `'static` -error: aborting due to 18 previous errors +error: aborting due to 19 previous errors