From 378300a63d1951e2718a6b0a077439fc1b14742b Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 17 Jun 2021 06:35:42 +0900 Subject: [PATCH] Make diagnostics clearer for `?` operators --- compiler/rustc_errors/src/diagnostic.rs | 12 ++++++++++++ .../src/infer/error_reporting/mod.rs | 19 ++++++++++++++++--- src/test/ui/inference/issue-71309.rs | 7 +++++++ src/test/ui/inference/issue-71309.stderr | 15 +++++++++++++++ ...ue-51632-try-desugar-incompatible-types.rs | 2 +- ...1632-try-desugar-incompatible-types.stderr | 3 ++- 6 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/inference/issue-71309.rs create mode 100644 src/test/ui/inference/issue-71309.stderr diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 232cf4bdb7f61..41a73268f4673 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -74,6 +74,10 @@ impl DiagnosticStyledString { pub fn highlighted>(t: S) -> DiagnosticStyledString { DiagnosticStyledString(vec![StringPart::Highlighted(t.into())]) } + + pub fn content(&self) -> String { + self.0.iter().map(|x| x.content()).collect::() + } } #[derive(Debug, PartialEq, Eq)] @@ -82,6 +86,14 @@ pub enum StringPart { Highlighted(String), } +impl StringPart { + pub fn content(&self) -> &str { + match self { + &StringPart::Normal(ref s) | &StringPart::Highlighted(ref s) => s, + } + } +} + impl Diagnostic { pub fn new(level: Level, message: &str) -> Self { Diagnostic::new_with_code(level, None, message) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 1139b714d0a1f..b8089b2499b66 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1971,6 +1971,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { trace: TypeTrace<'tcx>, terr: &TypeError<'tcx>, ) -> DiagnosticBuilder<'tcx> { + use crate::traits::ObligationCauseCode::MatchExpressionArm; + debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); let span = trace.cause.span(self.tcx); @@ -2013,6 +2015,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => {} } } + if let MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = + trace.cause.code + { + if let hir::MatchSource::TryDesugar = source { + if let Some((expected_ty, found_ty)) = self.values_str(trace.values) { + err.note(&format!( + "`?` operator cannot convert from `{}` to `{}`", + found_ty.content(), + expected_ty.content(), + )); + } + } + } err } FailureCode::Error0644(failure_str) => { @@ -2585,9 +2600,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { CompareImplTypeObligation { .. } => Error0308("type not compatible with trait"), MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => { Error0308(match source { - hir::MatchSource::TryDesugar => { - "try expression alternatives have incompatible types" - } + hir::MatchSource::TryDesugar => "`?` operator has incompatible types", _ => "`match` arms have incompatible types", }) } diff --git a/src/test/ui/inference/issue-71309.rs b/src/test/ui/inference/issue-71309.rs new file mode 100644 index 0000000000000..c31107d8fed05 --- /dev/null +++ b/src/test/ui/inference/issue-71309.rs @@ -0,0 +1,7 @@ +fn foo(x: Result) -> Result<(), ()> { + let y: u32 = x?; + //~^ ERROR: `?` operator has incompatible types + Ok(()) +} + +fn main() {} diff --git a/src/test/ui/inference/issue-71309.stderr b/src/test/ui/inference/issue-71309.stderr new file mode 100644 index 0000000000000..af8714f1c8083 --- /dev/null +++ b/src/test/ui/inference/issue-71309.stderr @@ -0,0 +1,15 @@ +error[E0308]: `?` operator has incompatible types + --> $DIR/issue-71309.rs:2:18 + | +LL | let y: u32 = x?; + | ^^ expected `u32`, found `i32` + | + = note: `?` operator cannot convert from `i32` to `u32` +help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit + | +LL | let y: u32 = x?.try_into().unwrap(); + | ++++++++++++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.rs b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.rs index bb74f0e0dc3c7..35402dff67553 100644 --- a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.rs +++ b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.rs @@ -6,7 +6,7 @@ fn missing_discourses() -> Result { fn forbidden_narratives() -> Result { missing_discourses()? - //~^ ERROR try expression alternatives have incompatible types + //~^ ERROR: `?` operator has incompatible types } fn main() {} diff --git a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr index 2c821aa23088d..0f61e03c3b58f 100644 --- a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr +++ b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr @@ -1,9 +1,10 @@ -error[E0308]: try expression alternatives have incompatible types +error[E0308]: `?` operator has incompatible types --> $DIR/issue-51632-try-desugar-incompatible-types.rs:8:5 | LL | missing_discourses()? | ^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found `isize` | + = note: `?` operator cannot convert from `isize` to `Result` = note: expected enum `Result` found type `isize` help: try removing this `?`