fix method substs

This commit is contained in:
Ali MJ Al-Nasrawy 2022-10-29 20:13:40 +03:00
parent be5a45d392
commit 37b40e471a
4 changed files with 53 additions and 46 deletions

View File

@ -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>) {

View File

@ -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)
}

View File

@ -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>() {

View File

@ -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::<Ty<'a>>();
| ^^^^^^^ 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