From 84629a5ab1b9e93c631c25a002b08c57ae8c1d4e Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 16 Aug 2022 10:50:04 +0800 Subject: [PATCH 1/2] Extend invalid floating point literal suffix suggestion --- compiler/rustc_typeck/src/check/expr.rs | 30 ++++++++---- src/test/ui/attempted-access-non-fatal.rs | 4 ++ src/test/ui/attempted-access-non-fatal.stderr | 46 ++++++++++++++++++- 3 files changed, 71 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index a685add7f56a6..92bf03ea66578 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -2159,7 +2159,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { E0610, "`{expr_t}` is a primitive type and therefore doesn't have fields", ); - let is_valid_suffix = |field: String| { + let is_valid_suffix = |field: &str| { if field == "f32" || field == "f64" { return true; } @@ -2184,20 +2184,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let suffix = chars.collect::(); suffix.is_empty() || suffix == "f32" || suffix == "f64" }; + let is_likely_suffix = |fist_chars: &[char], field: &str| { + field.len() >= 1 + && field.to_lowercase().starts_with(fist_chars) + && field[1..].chars().all(|c| c.is_ascii_digit()) + }; if let ty::Infer(ty::IntVar(_)) = expr_t.kind() && let ExprKind::Lit(Spanned { node: ast::LitKind::Int(_, ast::LitIntType::Unsuffixed), .. }) = base.kind && !base.span.from_expansion() - && is_valid_suffix(field_name) { - err.span_suggestion_verbose( - field.span.shrink_to_lo(), - "If the number is meant to be a floating point number, consider adding a `0` after the period", - '0', - Applicability::MaybeIncorrect, - ); + let msg = "If the number is meant to be a floating point number, consider adding a `0` after the period"; + if is_valid_suffix(&field_name) { + err.span_suggestion_verbose( + field.span.shrink_to_lo(), + msg, + '0', + Applicability::MaybeIncorrect, + ); + } else if is_likely_suffix(&['f', 'l'], &field_name) { + err.span_suggestion_verbose( + field.span, + format!("{}, valid float format are `f32` and `f64`", msg), + "0f32", + Applicability::MaybeIncorrect, + ); + } } err.emit(); } diff --git a/src/test/ui/attempted-access-non-fatal.rs b/src/test/ui/attempted-access-non-fatal.rs index e50c1f23c51cc..15deb9e2f609a 100644 --- a/src/test/ui/attempted-access-non-fatal.rs +++ b/src/test/ui/attempted-access-non-fatal.rs @@ -3,4 +3,8 @@ fn main() { let x = 0; let _ = x.foo; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] let _ = x.bar; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] + let _ = 0.f; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] + let _ = 2.l; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] + let _ = 12.F; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] + let _ = 34.L; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] } diff --git a/src/test/ui/attempted-access-non-fatal.stderr b/src/test/ui/attempted-access-non-fatal.stderr index 5b7db0e9d6fb4..856dba2b2e4c7 100644 --- a/src/test/ui/attempted-access-non-fatal.stderr +++ b/src/test/ui/attempted-access-non-fatal.stderr @@ -10,6 +10,50 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields LL | let _ = x.bar; | ^^^ -error: aborting due to 2 previous errors +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/attempted-access-non-fatal.rs:6:15 + | +LL | let _ = 0.f; + | ^ + | +help: If the number is meant to be a floating point number, consider adding a `0` after the period, valid float format are `f32` and `f64` + | +LL | let _ = 0.0f32; + | ~~~~ + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/attempted-access-non-fatal.rs:7:15 + | +LL | let _ = 2.l; + | ^ + | +help: If the number is meant to be a floating point number, consider adding a `0` after the period, valid float format are `f32` and `f64` + | +LL | let _ = 2.0f32; + | ~~~~ + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/attempted-access-non-fatal.rs:8:16 + | +LL | let _ = 12.F; + | ^ + | +help: If the number is meant to be a floating point number, consider adding a `0` after the period, valid float format are `f32` and `f64` + | +LL | let _ = 12.0f32; + | ~~~~ + +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields + --> $DIR/attempted-access-non-fatal.rs:9:16 + | +LL | let _ = 34.L; + | ^ + | +help: If the number is meant to be a floating point number, consider adding a `0` after the period, valid float format are `f32` and `f64` + | +LL | let _ = 34.0f32; + | ~~~~ + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0610`. From 89a51a1a483fcf411ab0d9e6416b6d91600d69d9 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 16 Aug 2022 19:12:36 +0800 Subject: [PATCH 2/2] use proper words in help message for floating point --- compiler/rustc_typeck/src/check/expr.rs | 21 ++++++++++++------- src/test/ui/attempted-access-non-fatal.stderr | 12 +++++------ ...ssing-zero-to-floating-point-number.stderr | 14 ++++++------- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 92bf03ea66578..51182d2a40d28 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -2184,10 +2184,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let suffix = chars.collect::(); suffix.is_empty() || suffix == "f32" || suffix == "f64" }; - let is_likely_suffix = |fist_chars: &[char], field: &str| { - field.len() >= 1 - && field.to_lowercase().starts_with(fist_chars) + let maybe_partial_suffix = |field: &str| -> Option<&str> { + let first_chars = ['f', 'l']; + if field.len() >= 1 + && field.to_lowercase().starts_with(first_chars) && field[1..].chars().all(|c| c.is_ascii_digit()) + { + if field.to_lowercase().starts_with(['f']) { Some("f32") } else { Some("f64") } + } else { + None + } }; if let ty::Infer(ty::IntVar(_)) = expr_t.kind() && let ExprKind::Lit(Spanned { @@ -2196,19 +2202,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) = base.kind && !base.span.from_expansion() { - let msg = "If the number is meant to be a floating point number, consider adding a `0` after the period"; if is_valid_suffix(&field_name) { err.span_suggestion_verbose( field.span.shrink_to_lo(), - msg, + "if intended to be a floating point literal, consider adding a `0` after the period", '0', Applicability::MaybeIncorrect, ); - } else if is_likely_suffix(&['f', 'l'], &field_name) { + } else if let Some(correct_suffix) = maybe_partial_suffix(&field_name) { err.span_suggestion_verbose( field.span, - format!("{}, valid float format are `f32` and `f64`", msg), - "0f32", + format!("if intended to be a floating point literal, consider adding a `0` after the period and a `{correct_suffix}` suffix"), + format!("0{correct_suffix}"), Applicability::MaybeIncorrect, ); } diff --git a/src/test/ui/attempted-access-non-fatal.stderr b/src/test/ui/attempted-access-non-fatal.stderr index 856dba2b2e4c7..bff669727a1b8 100644 --- a/src/test/ui/attempted-access-non-fatal.stderr +++ b/src/test/ui/attempted-access-non-fatal.stderr @@ -16,7 +16,7 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields LL | let _ = 0.f; | ^ | -help: If the number is meant to be a floating point number, consider adding a `0` after the period, valid float format are `f32` and `f64` +help: if intended to be a floating point literal, consider adding a `0` after the period and a `f32` suffix | LL | let _ = 0.0f32; | ~~~~ @@ -27,9 +27,9 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields LL | let _ = 2.l; | ^ | -help: If the number is meant to be a floating point number, consider adding a `0` after the period, valid float format are `f32` and `f64` +help: if intended to be a floating point literal, consider adding a `0` after the period and a `f64` suffix | -LL | let _ = 2.0f32; +LL | let _ = 2.0f64; | ~~~~ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields @@ -38,7 +38,7 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields LL | let _ = 12.F; | ^ | -help: If the number is meant to be a floating point number, consider adding a `0` after the period, valid float format are `f32` and `f64` +help: if intended to be a floating point literal, consider adding a `0` after the period and a `f32` suffix | LL | let _ = 12.0f32; | ~~~~ @@ -49,9 +49,9 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields LL | let _ = 34.L; | ^ | -help: If the number is meant to be a floating point number, consider adding a `0` after the period, valid float format are `f32` and `f64` +help: if intended to be a floating point literal, consider adding a `0` after the period and a `f64` suffix | -LL | let _ = 34.0f32; +LL | let _ = 34.0f64; | ~~~~ error: aborting due to 6 previous errors diff --git a/src/test/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.stderr b/src/test/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.stderr index e8e069708a864..503015f3bec61 100644 --- a/src/test/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.stderr +++ b/src/test/ui/typeck/suggest-adding-missing-zero-to-floating-point-number.stderr @@ -4,7 +4,7 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields LL | 2.e1; | ^^ | -help: If the number is meant to be a floating point number, consider adding a `0` after the period +help: if intended to be a floating point literal, consider adding a `0` after the period | LL | 2.0e1; | + @@ -15,7 +15,7 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields LL | 2.E1; | ^^ | -help: If the number is meant to be a floating point number, consider adding a `0` after the period +help: if intended to be a floating point literal, consider adding a `0` after the period | LL | 2.0E1; | + @@ -26,7 +26,7 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields LL | 2.f32; | ^^^ | -help: If the number is meant to be a floating point number, consider adding a `0` after the period +help: if intended to be a floating point literal, consider adding a `0` after the period | LL | 2.0f32; | + @@ -37,7 +37,7 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields LL | 2.f64; | ^^^ | -help: If the number is meant to be a floating point number, consider adding a `0` after the period +help: if intended to be a floating point literal, consider adding a `0` after the period | LL | 2.0f64; | + @@ -48,7 +48,7 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields LL | 2.e+12; | ^ | -help: If the number is meant to be a floating point number, consider adding a `0` after the period +help: if intended to be a floating point literal, consider adding a `0` after the period | LL | 2.0e+12; | + @@ -59,7 +59,7 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields LL | 2.e-12; | ^ | -help: If the number is meant to be a floating point number, consider adding a `0` after the period +help: if intended to be a floating point literal, consider adding a `0` after the period | LL | 2.0e-12; | + @@ -70,7 +70,7 @@ error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields LL | 2.e1f32; | ^^^^^ | -help: If the number is meant to be a floating point number, consider adding a `0` after the period +help: if intended to be a floating point literal, consider adding a `0` after the period | LL | 2.0e1f32; | +