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() {
|
||||
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 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 {
|
||||
tcx.sess.diagnostic().struct_dummy()
|
||||
};
|
||||
|
@ -305,12 +343,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,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! {
|
||||
|
|
|
@ -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 `u32`
|
||||
|
|
||||
= 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 as u32).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 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
|
||||
--> $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 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