Skip to content

Commit 2ee771f

Browse files
committed
fix method substs
1 parent 32b4b8a commit 2ee771f

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, EarlyBinder, 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;
@@ -162,47 +162,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
162162
pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) {
163163
self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id)));
164164
self.write_substs(hir_id, method.substs);
165-
166-
// When the method is confirmed, the `method.substs` includes
167-
// parameters from not just the method, but also the impl of
168-
// the method -- in particular, the `Self` type will be fully
169-
// resolved. However, those are not something that the "user
170-
// specified" -- i.e., those types come from the inferred type
171-
// of the receiver, not something the user wrote. So when we
172-
// create the user-substs, we want to replace those earlier
173-
// types with just the types that the user actually wrote --
174-
// that is, those that appear on the *method itself*.
175-
//
176-
// As an example, if the user wrote something like
177-
// `foo.bar::<u32>(...)` -- the `Self` type here will be the
178-
// type of `foo` (possibly adjusted), but we don't want to
179-
// include that. We want just the `[_, u32]` part.
180-
if !method.substs.is_empty() {
181-
let method_generics = self.tcx.generics_of(method.def_id);
182-
if !method_generics.params.is_empty() {
183-
let user_type_annotation = self.probe(|_| {
184-
let user_substs = UserSubsts {
185-
substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| {
186-
let i = param.index as usize;
187-
if i < method_generics.parent_count {
188-
self.var_for_def(DUMMY_SP, param)
189-
} else {
190-
method.substs[i]
191-
}
192-
}),
193-
user_self_ty: None, // not relevant here
194-
};
195-
196-
self.canonicalize_user_type_annotation(UserType::TypeOf(
197-
method.def_id,
198-
user_substs,
199-
))
200-
});
201-
202-
debug!("write_method_call: user_type_annotation={:?}", user_type_annotation);
203-
self.write_user_type_annotation(hir_id, user_type_annotation);
204-
}
205-
}
206165
}
207166

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

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)