From 7a9e0df26efe95fff61ceef2bc1860f0e61f5fa5 Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 29 Nov 2025 10:27:34 +0800 Subject: [PATCH] Fix span note for question mark expression --- .../traits/fulfillment_errors.rs | 32 ++++++++------- .../question-mark-result-err-mismatch.rs | 2 +- .../question-mark-result-err-mismatch.stderr | 2 +- tests/ui/traits/question-mark-span-144304.rs | 7 ++++ .../traits/question-mark-span-144304.stderr | 41 +++++++++++++++++++ 5 files changed, 67 insertions(+), 17 deletions(-) create mode 100644 tests/ui/traits/question-mark-span-144304.rs create mode 100644 tests/ui/traits/question-mark-span-144304.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 8c867f842b89a..d96a1b0a8c0eb 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1229,7 +1229,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { chain.push((expr.span, prev_ty)); let mut prev = None; - for (span, err_ty) in chain.into_iter().rev() { + let mut iter = chain.into_iter().rev().peekable(); + while let Some((span, err_ty)) = iter.next() { + let is_last = iter.peek().is_none(); let err_ty = get_e_type(err_ty); let err_ty = match (err_ty, prev) { (Some(err_ty), Some(prev)) if !self.can_eq(obligation.param_env, err_ty, prev) => { @@ -1241,27 +1243,27 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { continue; } }; - if self + + let implements_from = self .infcx .type_implements_trait( self.tcx.get_diagnostic_item(sym::From).unwrap(), [self_ty, err_ty], obligation.param_env, ) - .must_apply_modulo_regions() - { - if !suggested { - let err_ty = self.tcx.short_string(err_ty, err.long_ty_path()); - err.span_label(span, format!("this has type `Result<_, {err_ty}>`")); - } + .must_apply_modulo_regions(); + + let err_ty_str = self.tcx.short_string(err_ty, err.long_ty_path()); + let label = if !implements_from && is_last { + format!( + "this can't be annotated with `?` because it has type `Result<_, {err_ty_str}>`" + ) } else { - let err_ty = self.tcx.short_string(err_ty, err.long_ty_path()); - err.span_label( - span, - format!( - "this can't be annotated with `?` because it has type `Result<_, {err_ty}>`", - ), - ); + format!("this has type `Result<_, {err_ty_str}>`") + }; + + if !suggested || !implements_from { + err.span_label(span, label); } prev = Some(err_ty); } diff --git a/tests/ui/traits/question-mark-result-err-mismatch.rs b/tests/ui/traits/question-mark-result-err-mismatch.rs index df1d5105a34a1..dfea4b93f46da 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.rs +++ b/tests/ui/traits/question-mark-result-err-mismatch.rs @@ -9,7 +9,7 @@ fn foo() -> Result { //~ NOTE expected `String` because of this }); let one = x .map(|s| ()) - .map_err(|e| { //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>` + .map_err(|e| { //~ NOTE this has type `Result<_, ()>` e; //~ HELP remove this semicolon }) .map(|()| "")?; //~ ERROR `?` couldn't convert the error to `String` diff --git a/tests/ui/traits/question-mark-result-err-mismatch.stderr b/tests/ui/traits/question-mark-result-err-mismatch.stderr index 0f83c9e73a314..be3f17cfc5274 100644 --- a/tests/ui/traits/question-mark-result-err-mismatch.stderr +++ b/tests/ui/traits/question-mark-result-err-mismatch.stderr @@ -9,7 +9,7 @@ LL | .map_err(|e| { LL | | e; | | - help: remove this semicolon LL | | }) - | |__________- this can't be annotated with `?` because it has type `Result<_, ()>` + | |__________- this has type `Result<_, ()>` LL | .map(|()| "")?; | ^ the trait `From<()>` is not implemented for `String` | diff --git a/tests/ui/traits/question-mark-span-144304.rs b/tests/ui/traits/question-mark-span-144304.rs new file mode 100644 index 0000000000000..2d5d45b3b9c26 --- /dev/null +++ b/tests/ui/traits/question-mark-span-144304.rs @@ -0,0 +1,7 @@ +fn f() -> Result<(), i32> { + Err("str").map_err(|e| e)?; //~ ERROR `?` couldn't convert the error to `i32` + Err("str").map_err(|e| e.to_string())?; //~ ERROR `?` couldn't convert the error to `i32` + Ok(()) +} + +fn main() {} diff --git a/tests/ui/traits/question-mark-span-144304.stderr b/tests/ui/traits/question-mark-span-144304.stderr new file mode 100644 index 0000000000000..a1aa805980bf5 --- /dev/null +++ b/tests/ui/traits/question-mark-span-144304.stderr @@ -0,0 +1,41 @@ +error[E0277]: `?` couldn't convert the error to `i32` + --> $DIR/question-mark-span-144304.rs:2:30 + | +LL | fn f() -> Result<(), i32> { + | --------------- expected `i32` because of this +LL | Err("str").map_err(|e| e)?; + | ---------- ^ the trait `From<&str>` is not implemented for `i32` + | | + | this has type `Result<_, &str>` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = help: the following other types implement trait `From`: + `i32` implements `From` + `i32` implements `From` + `i32` implements `From` + `i32` implements `From` + `i32` implements `From` + +error[E0277]: `?` couldn't convert the error to `i32` + --> $DIR/question-mark-span-144304.rs:3:42 + | +LL | fn f() -> Result<(), i32> { + | --------------- expected `i32` because of this +LL | Err("str").map_err(|e| e)?; +LL | Err("str").map_err(|e| e.to_string())?; + | ---------- --------------------------^ the trait `From` is not implemented for `i32` + | | | + | | this can't be annotated with `?` because it has type `Result<_, String>` + | this has type `Result<_, &str>` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = help: the following other types implement trait `From`: + `i32` implements `From` + `i32` implements `From` + `i32` implements `From` + `i32` implements `From` + `i32` implements `From` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`.