about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAli MJ Al-Nasrawy <alimjalnasrawy@gmail.com>2022-10-29 20:13:40 +0300
committerAli MJ Al-Nasrawy <alimjalnasrawy@gmail.com>2023-01-07 13:38:40 +0300
commit37b40e471a62425cb34781bad763b5cb5047f13c (patch)
tree182d6d2b07716ac713d1d5a67a727a6a9e3adc91
parentbe5a45d39240ab3f6410c4808b0840142c657228 (diff)
downloadrust-37b40e471a62425cb34781bad763b5cb5047f13c.tar.gz
rust-37b40e471a62425cb34781bad763b5cb5047f13c.zip
fix method substs
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs43
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs44
-rw-r--r--src/test/ui/nll/user-annotations/normalization-2.rs2
-rw-r--r--src/test/ui/nll/user-annotations/normalization-2.stderr10
4 files changed, 53 insertions, 46 deletions
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::<u32>(...)` -- 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 = <dyn AstConv<'_>>::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::<u32>(...)` -- 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::<Ty<'a>>();
+    //~^ 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
@@ -115,6 +115,14 @@ help: the following changes may resolve your lifetime errors
    = 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::<Ty<'a>>();
+   |       ^^^^^^^ requires that `'a` must outlive `'static`
+
+error: lifetime may not live long enough
   --> $DIR/normalization-2.rs:88:5
    |
 LL | fn test_struct_path<'a, 'b, 'c, 'd>() {
@@ -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