update infer cost computation for types
This commit is contained in:
parent
c2ed08715b
commit
f1836c453a
6 changed files with 101 additions and 37 deletions
|
@ -602,41 +602,58 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
|
||||||
/// Sources with a small cost are prefer and should result
|
/// Sources with a small cost are prefer and should result
|
||||||
/// in a clearer and idiomatic suggestion.
|
/// in a clearer and idiomatic suggestion.
|
||||||
fn source_cost(&self, source: &InferSource<'tcx>) -> usize {
|
fn source_cost(&self, source: &InferSource<'tcx>) -> usize {
|
||||||
let tcx = self.infcx.tcx;
|
#[derive(Clone, Copy)]
|
||||||
|
struct CostCtxt<'tcx> {
|
||||||
fn arg_cost<'tcx>(arg: GenericArg<'tcx>) -> usize {
|
tcx: TyCtxt<'tcx>,
|
||||||
|
}
|
||||||
|
impl<'tcx> CostCtxt<'tcx> {
|
||||||
|
fn arg_cost(self, arg: GenericArg<'tcx>) -> usize {
|
||||||
match arg.unpack() {
|
match arg.unpack() {
|
||||||
GenericArgKind::Lifetime(_) => 0, // erased
|
GenericArgKind::Lifetime(_) => 0, // erased
|
||||||
GenericArgKind::Type(ty) => ty_cost(ty),
|
GenericArgKind::Type(ty) => self.ty_cost(ty),
|
||||||
GenericArgKind::Const(_) => 3, // some non-zero value
|
GenericArgKind::Const(_) => 3, // some non-zero value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn ty_cost<'tcx>(ty: Ty<'tcx>) -> usize {
|
fn ty_cost(self, ty: Ty<'tcx>) -> usize {
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Closure(..) => 100,
|
ty::Closure(..) => 1000,
|
||||||
ty::FnDef(..) => 20,
|
ty::FnDef(..) => 150,
|
||||||
ty::FnPtr(..) => 10,
|
ty::FnPtr(..) => 30,
|
||||||
|
ty::Adt(def, substs) => {
|
||||||
|
5 + self
|
||||||
|
.tcx
|
||||||
|
.generics_of(def.did())
|
||||||
|
.own_substs_no_defaults(self.tcx, substs)
|
||||||
|
.iter()
|
||||||
|
.map(|&arg| self.arg_cost(arg))
|
||||||
|
.sum::<usize>()
|
||||||
|
}
|
||||||
|
ty::Tuple(args) => 5 + args.iter().map(|arg| self.ty_cost(arg)).sum::<usize>(),
|
||||||
ty::Infer(..) => 0,
|
ty::Infer(..) => 0,
|
||||||
_ => 1,
|
_ => 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The sources are listed in order of preference here.
|
// The sources are listed in order of preference here.
|
||||||
|
let tcx = self.infcx.tcx;
|
||||||
|
let ctx = CostCtxt { tcx };
|
||||||
match source.kind {
|
match source.kind {
|
||||||
InferSourceKind::LetBinding { ty, .. } => ty_cost(ty),
|
InferSourceKind::LetBinding { ty, .. } => ctx.ty_cost(ty),
|
||||||
InferSourceKind::ClosureArg { ty, .. } => 5 + ty_cost(ty),
|
InferSourceKind::ClosureArg { ty, .. } => ctx.ty_cost(ty),
|
||||||
InferSourceKind::GenericArg { def_id, generic_args, .. } => {
|
InferSourceKind::GenericArg { def_id, generic_args, .. } => {
|
||||||
let variant_cost = match tcx.def_kind(def_id) {
|
let variant_cost = match tcx.def_kind(def_id) {
|
||||||
DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15, // `None::<u32>` and friends are ugly.
|
// `None::<u32>` and friends are ugly.
|
||||||
_ => 12,
|
DefKind::Variant | DefKind::Ctor(CtorOf::Variant, _) => 15,
|
||||||
|
_ => 10,
|
||||||
};
|
};
|
||||||
variant_cost + generic_args.iter().map(|&arg| arg_cost(arg)).sum::<usize>()
|
variant_cost + generic_args.iter().map(|&arg| ctx.arg_cost(arg)).sum::<usize>()
|
||||||
}
|
}
|
||||||
InferSourceKind::FullyQualifiedMethodCall { substs, .. } => {
|
InferSourceKind::FullyQualifiedMethodCall { substs, .. } => {
|
||||||
20 + substs.iter().map(|arg| arg_cost(arg)).sum::<usize>()
|
20 + substs.iter().map(|arg| ctx.arg_cost(arg)).sum::<usize>()
|
||||||
}
|
}
|
||||||
InferSourceKind::ClosureReturn { ty, should_wrap_expr, .. } => {
|
InferSourceKind::ClosureReturn { ty, should_wrap_expr, .. } => {
|
||||||
30 + ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
|
30 + ctx.ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -646,6 +663,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn update_infer_source(&mut self, new_source: InferSource<'tcx>) {
|
fn update_infer_source(&mut self, new_source: InferSource<'tcx>) {
|
||||||
let cost = self.source_cost(&new_source) + self.attempt;
|
let cost = self.source_cost(&new_source) + self.attempt;
|
||||||
|
debug!(?cost);
|
||||||
self.attempt += 1;
|
self.attempt += 1;
|
||||||
if cost < self.infer_source_cost {
|
if cost < self.infer_source_cost {
|
||||||
self.infer_source_cost = cost;
|
self.infer_source_cost = cost;
|
||||||
|
|
19
src/test/ui/inference/need_type_info/channel.rs
Normal file
19
src/test/ui/inference/need_type_info/channel.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// Test that we suggest specifying the generic argument of `channel`
|
||||||
|
// instead of the return type of that function, which is a lot more
|
||||||
|
// complex.
|
||||||
|
use std::sync::mpsc::channel;
|
||||||
|
|
||||||
|
fn no_tuple() {
|
||||||
|
let _data =
|
||||||
|
channel(); //~ ERROR type annotations needed
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuple() {
|
||||||
|
let (_sender, _receiver) =
|
||||||
|
channel(); //~ ERROR type annotations needed
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
no_tuple();
|
||||||
|
tuple();
|
||||||
|
}
|
25
src/test/ui/inference/need_type_info/channel.stderr
Normal file
25
src/test/ui/inference/need_type_info/channel.stderr
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
error[E0282]: type annotations needed
|
||||||
|
--> $DIR/channel.rs:8:9
|
||||||
|
|
|
||||||
|
LL | channel();
|
||||||
|
| ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `channel`
|
||||||
|
|
|
||||||
|
help: consider specifying the generic argument
|
||||||
|
|
|
||||||
|
LL | channel::<T>();
|
||||||
|
| +++++
|
||||||
|
|
||||||
|
error[E0282]: type annotations needed
|
||||||
|
--> $DIR/channel.rs:13:9
|
||||||
|
|
|
||||||
|
LL | channel();
|
||||||
|
| ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `channel`
|
||||||
|
|
|
||||||
|
help: consider specifying the generic argument
|
||||||
|
|
|
||||||
|
LL | channel::<T>();
|
||||||
|
| +++++
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0282`.
|
|
@ -5,10 +5,10 @@ use std::marker::PhantomData;
|
||||||
struct Foo<T> {foo: PhantomData<T>}
|
struct Foo<T> {foo: PhantomData<T>}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let (tx, rx) = //~ ERROR type annotations needed
|
let (tx, rx) =
|
||||||
channel();
|
channel();
|
||||||
// FIXME(#89862): Suggest adding a generic argument to `channel` instead
|
|
||||||
spawn(move || {
|
spawn(move || {
|
||||||
tx.send(Foo{ foo: PhantomData });
|
tx.send(Foo{ foo: PhantomData });
|
||||||
|
//~^ ERROR type annotations needed
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
error[E0282]: type annotations needed for `(Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>)`
|
error[E0282]: type annotations needed
|
||||||
--> $DIR/issue-25368.rs:8:9
|
--> $DIR/issue-25368.rs:11:27
|
||||||
|
|
|
|
||||||
LL | let (tx, rx) =
|
LL | tx.send(Foo{ foo: PhantomData });
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `PhantomData`
|
||||||
|
|
|
|
||||||
help: consider giving this pattern a type, where the type for type parameter `T` is specified
|
help: consider specifying the generic argument
|
||||||
|
|
|
|
||||||
LL | let (tx, rx): (Sender<Foo<T>>, std::sync::mpsc::Receiver<Foo<T>>) =
|
LL | tx.send(Foo{ foo: PhantomData::<T> });
|
||||||
| +++++++++++++++++++++++++++++++++++++++++++++++++++++
|
| +++++
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
error[E0282]: type annotations needed for `(Vec<T>,)`
|
error[E0282]: type annotations needed
|
||||||
--> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:9
|
--> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18
|
||||||
|
|
|
|
||||||
LL | let (x, ) = (vec![], );
|
LL | let (x, ) = (vec![], );
|
||||||
| ^^^^^
|
| ^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Vec`
|
||||||
|
|
|
|
||||||
help: consider giving this pattern a type, where the type for type parameter `T` is specified
|
= note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
help: consider specifying the generic argument
|
||||||
|
--> $SRC_DIR/alloc/src/macros.rs:LL:COL
|
||||||
|
|
|
|
||||||
LL | let (x, ): (Vec<T>,) = (vec![], );
|
LL | $crate::__rust_force_expr!($crate::vec::Vec::<T>::new())
|
||||||
| +++++++++++
|
| +++++
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue