about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2018-01-03 19:18:17 -0800
committerEsteban Küber <esteban@kuber.com.ar>2018-01-03 21:46:43 -0800
commit87242f3cc7e82e60b308598f9abd29eb3c0c3be7 (patch)
treea6563113693b4d76d8fbee4cf10036ed40e56cbd
parent885011ef1fd8fbe8c5be50a0713c03c980772be3 (diff)
Provide suggestion when trying to use method on numeric literal
-rw-r--r--src/librustc_typeck/check/method/suggest.rs72
-rw-r--r--src/librustc_typeck/diagnostics.rs25
-rw-r--r--src/test/ui/issue-41652/issue_41652.rs2
-rw-r--r--src/test/ui/issue-41652/issue_41652.stderr14
-rw-r--r--src/test/ui/macros/macro-backtrace-invalid-internals.rs14
-rw-r--r--src/test/ui/macros/macro-backtrace-invalid-internals.stderr40
-rw-r--r--src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs15
-rw-r--r--src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr12
8 files changed, 161 insertions, 33 deletions
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index f29009c1973..60ebe3c2c7b 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -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));
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 770d0cd4f1f..204e57f12aa 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -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! {
diff --git a/src/test/ui/issue-41652/issue_41652.rs b/src/test/ui/issue-41652/issue_41652.rs
index f38c682d319..a4e92820e21 100644
--- a/src/test/ui/issue-41652/issue_41652.rs
+++ b/src/test/ui/issue-41652/issue_41652.rs
@@ -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}`
     }
 }
 
diff --git a/src/test/ui/issue-41652/issue_41652.stderr b/src/test/ui/issue-41652/issue_41652.stderr
index 5d143697908..2b12efc5fad 100644
--- a/src/test/ui/issue-41652/issue_41652.stderr
+++ b/src/test/ui/issue-41652/issue_41652.stderr
@@ -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
 
diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.rs b/src/test/ui/macros/macro-backtrace-invalid-internals.rs
index 037f0d839e2..58a30e86f22 100644
--- a/src/test/ui/macros/macro-backtrace-invalid-internals.rs
+++ b/src/test/ui/macros/macro-backtrace-invalid-internals.rs
@@ -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!();
 }
diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr
index 42144f63c37..1600bb4fd54 100644
--- a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr
+++ b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr
@@ -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
 
diff --git a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs
new file mode 100644
index 00000000000..d0ae520f57b
--- /dev/null
+++ b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs
@@ -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);
+}
diff --git a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr
new file mode 100644
index 00000000000..f315517d940
--- /dev/null
+++ b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr
@@ -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
+