From 87242f3cc7e82e60b308598f9abd29eb3c0c3be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 3 Jan 2018 19:18:17 -0800 Subject: [PATCH] Provide suggestion when trying to use method on numeric literal --- src/librustc_typeck/check/method/suggest.rs | 72 +++++++++++++++---- src/librustc_typeck/diagnostics.rs | 25 +++++++ src/test/ui/issue-41652/issue_41652.rs | 2 +- src/test/ui/issue-41652/issue_41652.stderr | 14 ++-- .../macro-backtrace-invalid-internals.rs | 14 ++++ .../macro-backtrace-invalid-internals.stderr | 40 +++++++++-- .../method-on-ambiguous-numeric-type.rs | 15 ++++ .../method-on-ambiguous-numeric-type.stderr | 12 ++++ 8 files changed, 161 insertions(+), 33 deletions(-) create mode 100644 src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs create mode 100644 src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f29009c1973a2..60ebe3c2c7b71 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 770d0cd4f1fc4..204e57f12aa75 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 f38c682d31974..a4e92820e21e5 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 5d14369790823..2b12efc5fad59 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 037f0d839e2b6..58a30e86f222b 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 42144f63c3710..1600bb4fd5470 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 0000000000000..d0ae520f57bf1 --- /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 or the MIT license +// , 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 0000000000000..f315517d9406c --- /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 +