Provide suggestion when trying to use method on numeric literal
This commit is contained in:
parent
885011ef1f
commit
87242f3cc7
8 changed files with 161 additions and 33 deletions
|
@ -195,15 +195,53 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut err = if !actual.references_error() {
|
let mut err = if !actual.references_error() {
|
||||||
struct_span_err!(
|
// Suggest clamping down the type if the method that is being attempted to
|
||||||
tcx.sess,
|
// be used exists at all, and the type is an ambiuous numeric type
|
||||||
span,
|
// ({integer}/{float}).
|
||||||
E0599,
|
let mut candidates = all_traits(self.tcx)
|
||||||
"no {} named `{}` found for type `{}` in the current scope",
|
.filter(|info| {
|
||||||
type_str,
|
self.associated_item(info.def_id, item_name, Namespace::Value).is_some()
|
||||||
item_name,
|
});
|
||||||
ty_string
|
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 snippet = tcx.sess.codemap().span_to_snippet(expr.span)
|
||||||
|
.unwrap_or("4".to_string());
|
||||||
|
let concrete_type = if actual.is_integral() {
|
||||||
|
"u32"
|
||||||
|
} else {
|
||||||
|
"f32"
|
||||||
|
};
|
||||||
|
err.span_suggestion(expr.span,
|
||||||
|
&format!("you must specify a concrete type for \
|
||||||
|
this numeric value, like `{}`",
|
||||||
|
concrete_type),
|
||||||
|
format!("({} as {})",
|
||||||
|
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 {
|
} else {
|
||||||
tcx.sess.diagnostic().struct_dummy()
|
tcx.sess.diagnostic().struct_dummy()
|
||||||
};
|
};
|
||||||
|
@ -305,12 +343,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||||
bound_list));
|
bound_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.suggest_traits_to_import(&mut err,
|
if actual.is_numeric() && actual.is_fresh() {
|
||||||
span,
|
|
||||||
rcvr_ty,
|
} else {
|
||||||
item_name,
|
self.suggest_traits_to_import(&mut err,
|
||||||
rcvr_expr,
|
span,
|
||||||
out_of_scope_traits);
|
rcvr_ty,
|
||||||
|
item_name,
|
||||||
|
rcvr_expr,
|
||||||
|
out_of_scope_traits);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(lev_candidate) = lev_candidate {
|
if let Some(lev_candidate) = lev_candidate {
|
||||||
err.help(&format!("did you mean `{}`?", lev_candidate.name));
|
err.help(&format!("did you mean `{}`?", lev_candidate.name));
|
||||||
|
|
|
@ -4641,6 +4641,31 @@ 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 as f32).powi(2);
|
||||||
|
let x: f32 = 2.0;
|
||||||
|
let _ = x.powi(2);
|
||||||
|
```
|
||||||
|
"##,
|
||||||
}
|
}
|
||||||
|
|
||||||
register_diagnostics! {
|
register_diagnostics! {
|
||||||
|
|
|
@ -17,7 +17,7 @@ struct S;
|
||||||
impl issue_41652_b::Tr for S {
|
impl issue_41652_b::Tr for S {
|
||||||
fn f() {
|
fn f() {
|
||||||
3.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
|
--> $DIR/issue_41652.rs:19:11
|
||||||
|
|
|
|
||||||
19 | 3.f()
|
19 | 3.f()
|
||||||
| ^
|
| ^
|
||||||
|
help: you must specify a concrete type for this numeric value, like `u32`
|
||||||
|
|
|
|
||||||
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
|
19 | (3 as u32).f()
|
||||||
= 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
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
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() {
|
fn main() {
|
||||||
fake_method_stmt!();
|
fake_method_stmt!();
|
||||||
fake_field_stmt!();
|
fake_field_stmt!();
|
||||||
fake_anon_field_stmt!();
|
fake_anon_field_stmt!();
|
||||||
|
real_method_stmt!();
|
||||||
|
|
||||||
let _ = fake_method_expr!();
|
let _ = fake_method_expr!();
|
||||||
let _ = fake_field_expr!();
|
let _ = fake_field_expr!();
|
||||||
let _ = fake_anon_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
|
15 | 1.fake() //~ ERROR no method
|
||||||
| ^^^^
|
| ^^^^
|
||||||
...
|
...
|
||||||
50 | fake_method_stmt!();
|
62 | fake_method_stmt!();
|
||||||
| -------------------- in this macro invocation
|
| -------------------- in this macro invocation
|
||||||
|
|
||||||
error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
|
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
|
21 | 1.fake //~ ERROR doesn't have fields
|
||||||
| ^^^^
|
| ^^^^
|
||||||
...
|
...
|
||||||
51 | fake_field_stmt!();
|
63 | fake_field_stmt!();
|
||||||
| ------------------- in this macro invocation
|
| ------------------- in this macro invocation
|
||||||
|
|
||||||
error[E0609]: no field `0` on type `{integer}`
|
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
|
27 | (1).0 //~ ERROR no field
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
...
|
...
|
||||||
52 | fake_anon_field_stmt!();
|
64 | fake_anon_field_stmt!();
|
||||||
| ------------------------ in this macro invocation
|
| ------------------------ 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 as 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
|
error[E0599]: no method named `fake` found for type `{integer}` in the current scope
|
||||||
--> $DIR/macro-backtrace-invalid-internals.rs:33:13
|
--> $DIR/macro-backtrace-invalid-internals.rs:33:13
|
||||||
|
|
|
|
||||||
33 | 1.fake() //~ ERROR no method
|
33 | 1.fake() //~ ERROR no method
|
||||||
| ^^^^
|
| ^^^^
|
||||||
...
|
...
|
||||||
54 | let _ = fake_method_expr!();
|
67 | let _ = fake_method_expr!();
|
||||||
| ------------------- in this macro invocation
|
| ------------------- in this macro invocation
|
||||||
|
|
||||||
error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
|
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
|
39 | 1.fake //~ ERROR doesn't have fields
|
||||||
| ^^^^
|
| ^^^^
|
||||||
...
|
...
|
||||||
55 | let _ = fake_field_expr!();
|
68 | let _ = fake_field_expr!();
|
||||||
| ------------------ in this macro invocation
|
| ------------------ in this macro invocation
|
||||||
|
|
||||||
error[E0609]: no field `0` on type `{integer}`
|
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
|
45 | (1).0 //~ ERROR no field
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
...
|
...
|
||||||
56 | let _ = fake_anon_field_expr!();
|
69 | let _ = fake_anon_field_expr!();
|
||||||
| ----------------------- in this macro invocation
|
| ----------------------- 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 as f32).powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 8 previous errors
|
||||||
|
|
||||||
|
|
15
src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs
Normal file
15
src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// 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}`
|
||||||
|
println!("{:?}", x);
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
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 as f32).powi(2);
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue