Auto merge of #47171 - estebank:numeric-literal-suggestion, r=nikomatsakis
Provide suggestion when trying to use method on numeric literal New output: ``` error[E0688]: can't call method `powi` on ambiguous numeric type `{float}` --> $DIR/method-on-ambiguous-numeric-type.rs:12:17 | 12 | let x = 2.0.powi(2); | ^^^^ help: you must specify a concrete type for this numeric value, like `f32` | 12 | let x = 2.0_f32.powi(2); | ^^^^^^^ ``` Previous output: ``` error[E0599]: no method named `powi` found for type `{float}` in the current scope --> src/main.rs:12:17 | 12 | let x = 2.0.powi(2); | ^^^^ | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope, perhaps add a `use` for it: | 11 | use core::num::Float; | ``` Fix #40985.
This commit is contained in:
commit
a29461f322
9 changed files with 199 additions and 34 deletions
|
@ -241,7 +241,7 @@ pub struct LifetimeDef {
|
|||
}
|
||||
|
||||
/// A "Path" is essentially Rust's notion of a name; for instance:
|
||||
/// std::cmp::PartialEq . It's represented as a sequence of identifiers,
|
||||
/// `std::cmp::PartialEq`. It's represented as a sequence of identifiers,
|
||||
/// along with a bunch of supporting information.
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
|
||||
pub struct Path {
|
||||
|
|
|
@ -195,15 +195,76 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
};
|
||||
let mut err = if !actual.references_error() {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0599,
|
||||
"no {} named `{}` found for type `{}` in the current scope",
|
||||
type_str,
|
||||
item_name,
|
||||
ty_string
|
||||
)
|
||||
// Suggest clamping down the type if the method that is being attempted to
|
||||
// be used exists at all, and the type is an ambiuous numeric type
|
||||
// ({integer}/{float}).
|
||||
let mut candidates = all_traits(self.tcx)
|
||||
.filter(|info| {
|
||||
self.associated_item(info.def_id, item_name, Namespace::Value).is_some()
|
||||
});
|
||||
if let (true, false, Some(expr), Some(_)) = (actual.is_numeric(),
|
||||
actual.has_concrete_skeleton(),
|
||||
rcvr_expr,
|
||||
candidates.next()) {
|
||||
let mut err = struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0689,
|
||||
"can't call {} `{}` on ambiguous numeric type `{}`",
|
||||
type_str,
|
||||
item_name,
|
||||
ty_string
|
||||
);
|
||||
let concrete_type = if actual.is_integral() {
|
||||
"i32"
|
||||
} else {
|
||||
"f32"
|
||||
};
|
||||
match expr.node {
|
||||
hir::ExprLit(_) => { // numeric literal
|
||||
let snippet = tcx.sess.codemap().span_to_snippet(expr.span)
|
||||
.unwrap_or("<numeric literal>".to_string());
|
||||
// FIXME: use the literal for missing snippet
|
||||
|
||||
err.span_suggestion(expr.span,
|
||||
&format!("you must specify a concrete type for \
|
||||
this numeric value, like `{}`",
|
||||
concrete_type),
|
||||
format!("{}_{}",
|
||||
snippet,
|
||||
concrete_type));
|
||||
}
|
||||
hir::ExprPath(ref qpath) => { // local binding
|
||||
if let &hir::QPath::Resolved(_, ref path) = &qpath {
|
||||
if let hir::def::Def::Local(node_id) = path.def {
|
||||
let span = tcx.hir.span(node_id);
|
||||
let snippet = tcx.sess.codemap().span_to_snippet(span)
|
||||
.unwrap();
|
||||
err.span_suggestion(span,
|
||||
&format!("you must specify a type for \
|
||||
this binding, like `{}`",
|
||||
concrete_type),
|
||||
format!("{}: {}",
|
||||
snippet,
|
||||
concrete_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
err.emit();
|
||||
return;
|
||||
} else {
|
||||
struct_span_err!(
|
||||
tcx.sess,
|
||||
span,
|
||||
E0599,
|
||||
"no {} named `{}` found for type `{}` in the current scope",
|
||||
type_str,
|
||||
item_name,
|
||||
ty_string
|
||||
)
|
||||
}
|
||||
} else {
|
||||
tcx.sess.diagnostic().struct_dummy()
|
||||
};
|
||||
|
@ -305,12 +366,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||
bound_list));
|
||||
}
|
||||
|
||||
self.suggest_traits_to_import(&mut err,
|
||||
span,
|
||||
rcvr_ty,
|
||||
item_name,
|
||||
rcvr_expr,
|
||||
out_of_scope_traits);
|
||||
if actual.is_numeric() && actual.is_fresh() {
|
||||
|
||||
} else {
|
||||
self.suggest_traits_to_import(&mut err,
|
||||
span,
|
||||
rcvr_ty,
|
||||
item_name,
|
||||
rcvr_expr,
|
||||
out_of_scope_traits);
|
||||
}
|
||||
|
||||
if let Some(lev_candidate) = lev_candidate {
|
||||
err.help(&format!("did you mean `{}`?", lev_candidate.name));
|
||||
|
|
|
@ -4641,6 +4641,32 @@ impl Foo for () {
|
|||
```
|
||||
"##,
|
||||
|
||||
E0689: r##"
|
||||
This error indicates that the numeric value for the method being passed exists
|
||||
but the type of the numeric value or binding could not be identified.
|
||||
|
||||
The error happens on numeric literals:
|
||||
|
||||
```compile_fail,E0689
|
||||
2.0.powi(2);
|
||||
```
|
||||
|
||||
and on numeric bindings without an identified concrete type:
|
||||
|
||||
```compile_fail,E0689
|
||||
let x = 2.0;
|
||||
x.powi(2); // same error as above
|
||||
```
|
||||
|
||||
Because of this, you must give the numeric literal or binding a type:
|
||||
|
||||
```
|
||||
let _ = 2.0_f32.powi(2);
|
||||
let x: f32 = 2.0;
|
||||
let _ = x.powi(2);
|
||||
let _ = (2.0 as f32).powi(2);
|
||||
```
|
||||
"##,
|
||||
}
|
||||
|
||||
register_diagnostics! {
|
||||
|
|
|
@ -17,7 +17,7 @@ struct S;
|
|||
impl issue_41652_b::Tr for S {
|
||||
fn f() {
|
||||
3.f()
|
||||
//~^ ERROR no method named `f` found for type `{integer}` in the current scope
|
||||
//~^ ERROR can't call method `f` on ambiguous numeric type `{integer}`
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,12 @@
|
|||
error[E0599]: no method named `f` found for type `{integer}` in the current scope
|
||||
error[E0689]: can't call method `f` on ambiguous numeric type `{integer}`
|
||||
--> $DIR/issue_41652.rs:19:11
|
||||
|
|
||||
19 | 3.f()
|
||||
| ^
|
||||
help: you must specify a concrete type for this numeric value, like `i32`
|
||||
|
|
||||
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
|
||||
= help: try with `{integer}::f`
|
||||
note: candidate #1 is defined in the trait `issue_41652_b::Tr`
|
||||
--> $DIR/auxiliary/issue_41652_b.rs:14:5
|
||||
|
|
||||
14 | / fn f()
|
||||
15 | | where Self: Sized;
|
||||
| |__________________________^
|
||||
= help: to disambiguate the method call, write `issue_41652_b::Tr::f(3)` instead
|
||||
19 | 3_i32.f()
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
|
|
@ -46,12 +46,26 @@ macro_rules! fake_anon_field_expr {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! real_method_stmt {
|
||||
() => {
|
||||
2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! real_method_expr {
|
||||
() => {
|
||||
2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fake_method_stmt!();
|
||||
fake_field_stmt!();
|
||||
fake_anon_field_stmt!();
|
||||
real_method_stmt!();
|
||||
|
||||
let _ = fake_method_expr!();
|
||||
let _ = fake_field_expr!();
|
||||
let _ = fake_anon_field_expr!();
|
||||
let _ = real_method_expr!();
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ error[E0599]: no method named `fake` found for type `{integer}` in the current s
|
|||
15 | 1.fake() //~ ERROR no method
|
||||
| ^^^^
|
||||
...
|
||||
50 | fake_method_stmt!();
|
||||
62 | fake_method_stmt!();
|
||||
| -------------------- in this macro invocation
|
||||
|
||||
error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
|
||||
|
@ -13,7 +13,7 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
|
|||
21 | 1.fake //~ ERROR doesn't have fields
|
||||
| ^^^^
|
||||
...
|
||||
51 | fake_field_stmt!();
|
||||
63 | fake_field_stmt!();
|
||||
| ------------------- in this macro invocation
|
||||
|
||||
error[E0609]: no field `0` on type `{integer}`
|
||||
|
@ -22,16 +22,29 @@ error[E0609]: no field `0` on type `{integer}`
|
|||
27 | (1).0 //~ ERROR no field
|
||||
| ^^^^^
|
||||
...
|
||||
52 | fake_anon_field_stmt!();
|
||||
64 | fake_anon_field_stmt!();
|
||||
| ------------------------ in this macro invocation
|
||||
|
||||
error[E0689]: can't call method `powi` on ambiguous numeric type `{float}`
|
||||
--> $DIR/macro-backtrace-invalid-internals.rs:51:15
|
||||
|
|
||||
51 | 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
|
||||
| ^^^^
|
||||
...
|
||||
65 | real_method_stmt!();
|
||||
| -------------------- in this macro invocation
|
||||
help: you must specify a concrete type for this numeric value, like `f32`
|
||||
|
|
||||
51 | 2.0_f32.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0599]: no method named `fake` found for type `{integer}` in the current scope
|
||||
--> $DIR/macro-backtrace-invalid-internals.rs:33:13
|
||||
|
|
||||
33 | 1.fake() //~ ERROR no method
|
||||
| ^^^^
|
||||
...
|
||||
54 | let _ = fake_method_expr!();
|
||||
67 | let _ = fake_method_expr!();
|
||||
| ------------------- in this macro invocation
|
||||
|
||||
error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
|
||||
|
@ -40,7 +53,7 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
|
|||
39 | 1.fake //~ ERROR doesn't have fields
|
||||
| ^^^^
|
||||
...
|
||||
55 | let _ = fake_field_expr!();
|
||||
68 | let _ = fake_field_expr!();
|
||||
| ------------------ in this macro invocation
|
||||
|
||||
error[E0609]: no field `0` on type `{integer}`
|
||||
|
@ -49,8 +62,21 @@ error[E0609]: no field `0` on type `{integer}`
|
|||
45 | (1).0 //~ ERROR no field
|
||||
| ^^^^^
|
||||
...
|
||||
56 | let _ = fake_anon_field_expr!();
|
||||
69 | let _ = fake_anon_field_expr!();
|
||||
| ----------------------- in this macro invocation
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
error[E0689]: can't call method `powi` on ambiguous numeric type `{float}`
|
||||
--> $DIR/macro-backtrace-invalid-internals.rs:57:15
|
||||
|
|
||||
57 | 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
|
||||
| ^^^^
|
||||
...
|
||||
70 | let _ = real_method_expr!();
|
||||
| ------------------- in this macro invocation
|
||||
help: you must specify a concrete type for this numeric value, like `f32`
|
||||
|
|
||||
57 | 2.0_f32.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
|
|
18
src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs
Normal file
18
src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
let x = 2.0.powi(2);
|
||||
//~^ ERROR can't call method `powi` on ambiguous numeric type `{float}`
|
||||
let y = 2.0;
|
||||
let x = y.powi(2);
|
||||
//~^ ERROR can't call method `powi` on ambiguous numeric type `{float}`
|
||||
println!("{:?}", x);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
error[E0689]: can't call method `powi` on ambiguous numeric type `{float}`
|
||||
--> $DIR/method-on-ambiguous-numeric-type.rs:12:17
|
||||
|
|
||||
12 | let x = 2.0.powi(2);
|
||||
| ^^^^
|
||||
help: you must specify a concrete type for this numeric value, like `f32`
|
||||
|
|
||||
12 | let x = 2.0_f32.powi(2);
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0689]: can't call method `powi` on ambiguous numeric type `{float}`
|
||||
--> $DIR/method-on-ambiguous-numeric-type.rs:15:15
|
||||
|
|
||||
15 | let x = y.powi(2);
|
||||
| ^^^^
|
||||
help: you must specify a type for this binding, like `f32`
|
||||
|
|
||||
14 | let y: f32 = 2.0;
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
Loading…
Reference in a new issue