From b36bf76dec593269b3c5006c38063315bed5ad51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sat, 19 Jan 2019 20:18:56 -0800 Subject: [PATCH 1/2] Suggest correct cast for struct fields with shorthand syntax --- src/librustc_typeck/check/demand.rs | 48 ++++++++++++++----- .../type-mismatch-struct-field-shorthand-2.rs | 9 ++++ ...e-mismatch-struct-field-shorthand-2.stderr | 30 ++++++++++++ ...type-mismatch-struct-field-shorthand.fixed | 12 +++++ .../type-mismatch-struct-field-shorthand.rs | 12 +++++ ...ype-mismatch-struct-field-shorthand.stderr | 33 +++++++++++++ 6 files changed, 132 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.rs create mode 100644 src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr create mode 100644 src/test/ui/suggestions/type-mismatch-struct-field-shorthand.fixed create mode 100644 src/test/ui/suggestions/type-mismatch-struct-field-shorthand.rs create mode 100644 src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index c0cedd77440..2aecc0f2ace 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -454,12 +454,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { false } - pub fn check_for_cast(&self, - err: &mut DiagnosticBuilder<'tcx>, - expr: &hir::Expr, - checked_ty: Ty<'tcx>, - expected_ty: Ty<'tcx>) - -> bool { + pub fn check_for_cast( + &self, + err: &mut DiagnosticBuilder<'tcx>, + expr: &hir::Expr, + checked_ty: Ty<'tcx>, + expected_ty: Ty<'tcx>, + ) -> bool { let parent_id = self.tcx.hir().get_parent_node(expr.id); if let Some(parent) = self.tcx.hir().find(parent_id) { // Shouldn't suggest `.into()` on `const`s. @@ -487,17 +488,40 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // For now, don't suggest casting with `as`. let can_cast = false; + let mut prefix = String::new(); + if let Some(hir::Node::Expr(hir::Expr { + node: hir::ExprKind::Struct(_, fields, _), + .. + })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.id)) { + // `expr` is a literal field for a struct, only suggest if appropriate + for field in fields { + if field.expr.id == expr.id { + // This is a field literal + prefix = format!("{}: ", field.ident); + break; + } + } + if &prefix == "" { + // Likely a field was meant, but this field wasn't found. Do not suggest anything. + return false; + } + } + let needs_paren = expr.precedence().order() < (PREC_POSTFIX as i8); if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) { let msg = format!("you can cast an `{}` to `{}`", checked_ty, expected_ty); - let cast_suggestion = format!("{}{}{} as {}", - if needs_paren { "(" } else { "" }, - src, - if needs_paren { ")" } else { "" }, - expected_ty); + let cast_suggestion = format!( + "{}{}{}{} as {}", + prefix, + if needs_paren { "(" } else { "" }, + src, + if needs_paren { ")" } else { "" }, + expected_ty, + ); let into_suggestion = format!( - "{}{}{}.into()", + "{}{}{}{}.into()", + prefix, if needs_paren { "(" } else { "" }, src, if needs_paren { ")" } else { "" }, diff --git a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.rs b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.rs new file mode 100644 index 00000000000..2ce12220723 --- /dev/null +++ b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.rs @@ -0,0 +1,9 @@ +struct RGB { r: f64, g: f64, b: f64 } + +fn main() { + let (r, g, c): (f32, f32, f32) = (0., 0., 0.); + let _ = RGB { r, g, c }; + //~^ ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR struct `RGB` has no field named `c` +} diff --git a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr new file mode 100644 index 00000000000..d0f9e1f7f7c --- /dev/null +++ b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand-2.stderr @@ -0,0 +1,30 @@ +error[E0308]: mismatched types + --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:19 + | +LL | let _ = RGB { r, g, c }; + | ^ expected f64, found f32 +help: you can cast an `f32` to `f64` in a lossless way + | +LL | let _ = RGB { r: r.into(), g, c }; + | ^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:22 + | +LL | let _ = RGB { r, g, c }; + | ^ expected f64, found f32 +help: you can cast an `f32` to `f64` in a lossless way + | +LL | let _ = RGB { r, g: g.into(), c }; + | ^^^^^^^^^^^ + +error[E0560]: struct `RGB` has no field named `c` + --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:25 + | +LL | let _ = RGB { r, g, c }; + | ^ help: a field with a similar name exists: `b` + +error: aborting due to 3 previous errors + +Some errors occurred: E0308, E0560. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.fixed b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.fixed new file mode 100644 index 00000000000..91758c0b218 --- /dev/null +++ b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.fixed @@ -0,0 +1,12 @@ +// run-rustfix +#![allow(dead_code)] + +struct RGB { r: f64, g: f64, b: f64 } + +fn main() { + let (r, g, b): (f32, f32, f32) = (0., 0., 0.); + let _ = RGB { r: r.into(), g: g.into(), b: b.into() }; + //~^ ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types +} diff --git a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.rs b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.rs new file mode 100644 index 00000000000..9d3a17a72b2 --- /dev/null +++ b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.rs @@ -0,0 +1,12 @@ +// run-rustfix +#![allow(dead_code)] + +struct RGB { r: f64, g: f64, b: f64 } + +fn main() { + let (r, g, b): (f32, f32, f32) = (0., 0., 0.); + let _ = RGB { r, g, b }; + //~^ ERROR mismatched types + //~| ERROR mismatched types + //~| ERROR mismatched types +} diff --git a/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr new file mode 100644 index 00000000000..6bc16ba8b70 --- /dev/null +++ b/src/test/ui/suggestions/type-mismatch-struct-field-shorthand.stderr @@ -0,0 +1,33 @@ +error[E0308]: mismatched types + --> $DIR/type-mismatch-struct-field-shorthand.rs:8:19 + | +LL | let _ = RGB { r, g, b }; + | ^ expected f64, found f32 +help: you can cast an `f32` to `f64` in a lossless way + | +LL | let _ = RGB { r: r.into(), g, b }; + | ^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/type-mismatch-struct-field-shorthand.rs:8:22 + | +LL | let _ = RGB { r, g, b }; + | ^ expected f64, found f32 +help: you can cast an `f32` to `f64` in a lossless way + | +LL | let _ = RGB { r, g: g.into(), b }; + | ^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/type-mismatch-struct-field-shorthand.rs:8:25 + | +LL | let _ = RGB { r, g, b }; + | ^ expected f64, found f32 +help: you can cast an `f32` to `f64` in a lossless way + | +LL | let _ = RGB { r, g, b: b.into() }; + | ^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. From 5b44b3cb1b2bc2f93520fe1339d93efe8439238c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 20 Jan 2019 09:11:42 -0800 Subject: [PATCH 2/2] review comment --- src/librustc_typeck/check/demand.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 2aecc0f2ace..d985bdae491 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -495,7 +495,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.id)) { // `expr` is a literal field for a struct, only suggest if appropriate for field in fields { - if field.expr.id == expr.id { + if field.expr.id == expr.id && field.is_shorthand { // This is a field literal prefix = format!("{}: ", field.ident); break;