提交 a29461f3 编写于 作者: B bors

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.
......@@ -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,6 +195,66 @@ pub fn report_method_error(&self,
}
};
let mut err = if !actual.references_error() {
// 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,
......@@ -204,6 +264,7 @@ pub fn report_method_error(&self,
item_name,
ty_string
)
}
} else {
tcx.sess.diagnostic().struct_dummy()
};
......@@ -305,12 +366,16 @@ pub fn report_method_error(&self,
bound_list));
}
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 @@ fn foo<U: Iterator>(&self, _: &U) { } // error method `foo` has incompatible
```
"##,
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 @@
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}`
}
}
......
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! 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
// 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);
}
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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册