Skip to content

Commit f1836c4

Browse files
committed
update infer cost computation for types
1 parent c2ed087 commit f1836c4

File tree

6 files changed

+101
-37
lines changed

6 files changed

+101
-37
lines changed

compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -602,41 +602,58 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
602602
/// Sources with a small cost are prefer and should result
603603
/// in a clearer and idiomatic suggestion.
604604
fn source_cost(&self, source: &InferSource<'tcx>) -> usize {
605-
let tcx = self.infcx.tcx;
606-
607-
fn arg_cost<'tcx>(arg: GenericArg<'tcx>) -> usize {
608-
match arg.unpack() {
609-
GenericArgKind::Lifetime(_) => 0, // erased
610-
GenericArgKind::Type(ty) => ty_cost(ty),
611-
GenericArgKind::Const(_) => 3, // some non-zero value
612-
}
605+
#[derive(Clone, Copy)]
606+
struct CostCtxt<'tcx> {
607+
tcx: TyCtxt<'tcx>,
613608
}
614-
fn ty_cost<'tcx>(ty: Ty<'tcx>) -> usize {
615-
match ty.kind() {
616-
ty::Closure(..) => 100,
617-
ty::FnDef(..) => 20,
618-
ty::FnPtr(..) => 10,
619-
ty::Infer(..) => 0,
620-
_ => 1,
609+
impl<'tcx> CostCtxt<'tcx> {
610+
fn arg_cost(self, arg: GenericArg<'tcx>) -> usize {
611+
match arg.unpack() {
612+
GenericArgKind::Lifetime(_) => 0, // erased
613+
GenericArgKind::Type(ty) => self.ty_cost(ty),
614+
GenericArgKind::Const(_) => 3, // some non-zero value
615+
}
616+
}
617+
fn ty_cost(self, ty: Ty<'tcx>) -> usize {
618+
match ty.kind() {
619+
ty::Closure(..) => 1000,
620+
ty::FnDef(..) => 150,
621+
ty::FnPtr(..) => 30,
622+
ty::Adt(def, substs) => {
623+
5 + self
624+
.tcx
625+
.generics_of(def.did())
626+
.own_substs_no_defaults(self.tcx, substs)
627+
.iter()
628+
.map(|&arg| self.arg_cost(arg))
629+
.sum::<usize>()
630+
}
631+
ty::Tuple(args) => 5 + args.iter().map(|arg| self.ty_cost(arg)).sum::<usize>(),
632+
ty::Infer(..) => 0,
633+
_ => 1,
634+
}
621635
}
622636
}
623637

624638
// The sources are listed in order of preference here.
639+
let tcx = self.infcx.tcx;
640+
let ctx = CostCtxt { tcx };
625641
match source.kind {
626-
InferSourceKind::LetBinding { ty, .. } => ty_cost(ty),
627-
InferSourceKind::ClosureArg { ty, .. } => 5 + ty_cost(ty),
642+
InferSourceKind::LetBinding { ty, .. } => ctx.ty_cost(ty),
643+
InferSourceKind::ClosureArg { ty, .. } => ctx.ty_cost(ty),
628644
InferSourceKind::GenericArg { def_id, generic_args, .. } => {
629645
let variant_cost = match tcx.def_kind(def_id) {
630-
DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15, // `None::<u32>` and friends are ugly.
631-
_ => 12,
646+
// `None::<u32>` and friends are ugly.
647+
DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15,
648+
_ => 10,
632649
};
633-
variant_cost + generic_args.iter().map(|&arg| arg_cost(arg)).sum::<usize>()
650+
variant_cost + generic_args.iter().map(|&arg| ctx.arg_cost(arg)).sum::<usize>()
634651
}
635652
InferSourceKind::FullyQualifiedMethodCall { substs, .. } => {
636-
20 + substs.iter().map(|arg| arg_cost(arg)).sum::<usize>()
653+
20 + substs.iter().map(|arg| ctx.arg_cost(arg)).sum::<usize>()
637654
}
638655
InferSourceKind::ClosureReturn { ty, should_wrap_expr, .. } => {
639-
30 + ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
656+
30 + ctx.ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
640657
}
641658
}
642659
}
@@ -646,6 +663,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
646663
#[instrument(level = "debug", skip(self))]
647664
fn update_infer_source(&mut self, new_source: InferSource<'tcx>) {
648665
let cost = self.source_cost(&new_source) + self.attempt;
666+
debug!(?cost);
649667
self.attempt += 1;
650668
if cost < self.infer_source_cost {
651669
self.infer_source_cost = cost;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Test that we suggest specifying the generic argument of `channel`
2+
// instead of the return type of that function, which is a lot more
3+
// complex.
4+
use std::sync::mpsc::channel;
5+
6+
fn no_tuple() {
7+
let _data =
8+
channel(); //~ ERROR type annotations needed
9+
}
10+
11+
fn tuple() {
12+
let (_sender, _receiver) =
13+
channel(); //~ ERROR type annotations needed
14+
}
15+
16+
fn main() {
17+
no_tuple();
18+
tuple();
19+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0282]: type annotations needed
2+
--> $DIR/channel.rs:8:9
3+
|
4+
LL | channel();
5+
| ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `channel`
6+
|
7+
help: consider specifying the generic argument
8+
|
9+
LL | channel::<T>();
10+
| +++++
11+
12+
error[E0282]: type annotations needed
13+
--> $DIR/channel.rs:13:9
14+
|
15+
LL | channel();
16+
| ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `channel`
17+
|
18+
help: consider specifying the generic argument
19+
|
20+
LL | channel::<T>();
21+
| +++++
22+
23+
error: aborting due to 2 previous errors
24+
25+
For more information about this error, try `rustc --explain E0282`.

src/test/ui/issues/issue-25368.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ use std::marker::PhantomData;
55
struct Foo<T> {foo: PhantomData<T>}
66

77
fn main() {
8-
let (tx, rx) = //~ ERROR type annotations needed
8+
let (tx, rx) =
99
channel();
10-
// FIXME(#89862): Suggest adding a generic argument to `channel` instead
1110
spawn(move || {
1211
tx.send(Foo{ foo: PhantomData });
12+
//~^ ERROR type annotations needed
1313
});
1414
}

src/test/ui/issues/issue-25368.stderr

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
error[E0282]: type annotations needed for `(Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`
2-
--> $DIR/issue-25368.rs:8:9
1+
error[E0282]: type annotations needed
2+
--> $DIR/issue-25368.rs:11:27
33
|
4-
LL | let (tx, rx) =
5-
| ^^^^^^^^
4+
LL | tx.send(Foo{ foo: PhantomData });
5+
| ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData`
66
|
7-
help: consider giving this pattern a type, where the type for type parameter `T` is specified
7+
help: consider specifying the generic argument
88
|
9-
LL | let (tx, rx): (Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>) =
10-
| +++++++++++++++++++++++++++++++++++++++++++++++++++++
9+
LL | tx.send(Foo{ foo: PhantomData::<T> });
10+
| +++++
1111

1212
error: aborting due to previous error
1313

src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
error[E0282]: type annotations needed for `(Vec<T>,)`
2-
--> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:9
1+
error[E0282]: type annotations needed
2+
--> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18
33
|
44
LL | let (x, ) = (vec![], );
5-
| ^^^^^
5+
| ^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Vec`
66
|
7-
help: consider giving this pattern a type, where the type for type parameter `T` is specified
7+
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
8+
help: consider specifying the generic argument
9+
--> $SRC_DIR/alloc/src/macros.rs:LL:COL
810
|
9-
LL | let (x, ): (Vec<T>,) = (vec![], );
10-
| +++++++++++
11+
LL | $crate::__rust_force_expr!($crate::vec::Vec::<T>::new())
12+
| +++++
1113

1214
error: aborting due to previous error
1315

0 commit comments

Comments
 (0)