Skip to content

Commit 37b40e4

Browse files
committed
fix method substs
1 parent be5a45d commit 37b40e4

File tree

4 files changed

+53
-46
lines changed

4 files changed

+53
-46
lines changed

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use rustc_middle::ty::visit::TypeVisitable;
2424
use rustc_middle::ty::{
2525
self, AdtKind, CanonicalUserType, DefIdTree, GenericParamDefKind, Ty, UserType,
2626
};
27-
use rustc_middle::ty::{GenericArgKind, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts};
27+
use rustc_middle::ty::{GenericArgKind, SubstsRef, UserSelfTy, UserSubsts};
2828
use rustc_session::lint;
2929
use rustc_span::def_id::LocalDefId;
3030
use rustc_span::hygiene::DesugaringKind;
@@ -161,47 +161,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
161161
pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) {
162162
self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id)));
163163
self.write_substs(hir_id, method.substs);
164-
165-
// When the method is confirmed, the `method.substs` includes
166-
// parameters from not just the method, but also the impl of
167-
// the method -- in particular, the `Self` type will be fully
168-
// resolved. However, those are not something that the "user
169-
// specified" -- i.e., those types come from the inferred type
170-
// of the receiver, not something the user wrote. So when we
171-
// create the user-substs, we want to replace those earlier
172-
// types with just the types that the user actually wrote --
173-
// that is, those that appear on the *method itself*.
174-
//
175-
// As an example, if the user wrote something like
176-
// `foo.bar::<u32>(...)` -- the `Self` type here will be the
177-
// type of `foo` (possibly adjusted), but we don't want to
178-
// include that. We want just the `[_, u32]` part.
179-
if !method.substs.is_empty() {
180-
let method_generics = self.tcx.generics_of(method.def_id);
181-
if !method_generics.params.is_empty() {
182-
let user_type_annotation = self.probe(|_| {
183-
let user_substs = UserSubsts {
184-
substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| {
185-
let i = param.index as usize;
186-
if i < method_generics.parent_count {
187-
self.var_for_def(DUMMY_SP, param)
188-
} else {
189-
method.substs[i]
190-
}
191-
}),
192-
user_self_ty: None, // not relevant here
193-
};
194-
195-
self.canonicalize_user_type_annotation(UserType::TypeOf(
196-
method.def_id,
197-
user_substs,
198-
))
199-
});
200-
201-
debug!("write_method_call: user_type_annotation={:?}", user_type_annotation);
202-
self.write_user_type_annotation(hir_id, user_type_annotation);
203-
}
204-
}
205164
}
206165

207166
pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) {

compiler/rustc_hir_typeck/src/method/confirm.rs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutabili
1212
use rustc_middle::ty::fold::TypeFoldable;
1313
use rustc_middle::ty::subst::{self, SubstsRef};
1414
use rustc_middle::ty::{self, GenericParamDefKind, Ty};
15-
use rustc_span::Span;
15+
use rustc_middle::ty::{InternalSubsts, UserSubsts, UserType};
16+
use rustc_span::{Span, DUMMY_SP};
1617
use rustc_trait_selection::traits;
1718

1819
use std::iter;
@@ -397,6 +398,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
397398
self.cfcx.var_for_def(self.cfcx.span, param)
398399
}
399400
}
401+
400402
let substs = <dyn AstConv<'_>>::create_substs_for_generic_args(
401403
self.tcx,
402404
pick.item.def_id,
@@ -406,7 +408,45 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
406408
&arg_count_correct,
407409
&mut MethodSubstsCtxt { cfcx: self, pick, seg },
408410
);
409-
// FIXME(aliemjay): Type annotation should be registered before normalization.
411+
412+
// When the method is confirmed, the `substs` includes
413+
// parameters from not just the method, but also the impl of
414+
// the method -- in particular, the `Self` type will be fully
415+
// resolved. However, those are not something that the "user
416+
// specified" -- i.e., those types come from the inferred type
417+
// of the receiver, not something the user wrote. So when we
418+
// create the user-substs, we want to replace those earlier
419+
// types with just the types that the user actually wrote --
420+
// that is, those that appear on the *method itself*.
421+
//
422+
// As an example, if the user wrote something like
423+
// `foo.bar::<u32>(...)` -- the `Self` type here will be the
424+
// type of `foo` (possibly adjusted), but we don't want to
425+
// include that. We want just the `[_, u32]` part.
426+
if !substs.is_empty() && !generics.params.is_empty() {
427+
let user_type_annotation = self.probe(|_| {
428+
let user_substs = UserSubsts {
429+
substs: InternalSubsts::for_item(self.tcx, pick.item.def_id, |param, _| {
430+
let i = param.index as usize;
431+
if i < generics.parent_count {
432+
self.fcx.var_for_def(DUMMY_SP, param)
433+
} else {
434+
substs[i]
435+
}
436+
}),
437+
user_self_ty: None, // not relevant here
438+
};
439+
440+
self.fcx.canonicalize_user_type_annotation(UserType::TypeOf(
441+
pick.item.def_id,
442+
user_substs,
443+
))
444+
});
445+
446+
debug!("instantiate_method_substs: user_type_annotation={:?}", user_type_annotation);
447+
self.fcx.write_user_type_annotation(self.call_expr.hir_id, user_type_annotation);
448+
}
449+
410450
self.normalize(self.span, substs)
411451
}
412452

src/test/ui/nll/user-annotations/normalization-2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ fn test_variants<'a, 'b, 'c>() {
6868
}
6969

7070
fn test_method_call<'a>(x: MyTy<()>) {
71-
// FIXME This should fail.
7271
x.method2::<Ty<'a>>();
72+
//~^ ERROR lifetime may not live long enough
7373
}
7474

7575
fn test_struct_path<'a, 'b, 'c, 'd>() {

src/test/ui/nll/user-annotations/normalization-2.stderr

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,14 @@ help: the following changes may resolve your lifetime errors
114114
= help: replace `'b` with `'static`
115115
= help: replace `'c` with `'static`
116116

117+
error: lifetime may not live long enough
118+
--> $DIR/normalization-2.rs:71:7
119+
|
120+
LL | fn test_method_call<'a>(x: MyTy<()>) {
121+
| -- lifetime `'a` defined here
122+
LL | x.method2::<Ty<'a>>();
123+
| ^^^^^^^ requires that `'a` must outlive `'static`
124+
117125
error: lifetime may not live long enough
118126
--> $DIR/normalization-2.rs:88:5
119127
|
@@ -190,5 +198,5 @@ help: the following changes may resolve your lifetime errors
190198
= help: replace `'b` with `'static`
191199
= help: replace `'c` with `'static`
192200

193-
error: aborting due to 18 previous errors
201+
error: aborting due to 19 previous errors
194202

0 commit comments

Comments
 (0)