1
Fork 0

Provide suggestion when trying to use method on numeric literal

This commit is contained in:
Esteban Küber 2018-01-03 19:18:17 -08:00
parent 885011ef1f
commit 87242f3cc7
8 changed files with 161 additions and 33 deletions

View file

@ -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));

View file

@ -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! {

View file

@ -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}`
} }
} }

View file

@ -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

View file

@ -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!();
} }

View file

@ -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

View 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);
}

View file

@ -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