Fix span note for question mark expression

This commit is contained in:
yukang 2025-11-29 10:27:34 +08:00
parent 1eb0657f78
commit d0bd4df3aa
5 changed files with 68 additions and 17 deletions

View file

@ -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);
}

View file

@ -9,7 +9,7 @@ fn foo() -> Result<String, String> { //~ 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`

View file

@ -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`
|

View file

@ -0,0 +1,8 @@
//@ ignore-arm - armhf-gnu have more types implement trait `From<T>`, let's skip it
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() {}

View file

@ -0,0 +1,41 @@
error[E0277]: `?` couldn't convert the error to `i32`
--> $DIR/question-mark-span-144304.rs:3: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<T>`:
`i32` implements `From<bool>`
`i32` implements `From<i16>`
`i32` implements `From<i8>`
`i32` implements `From<u16>`
`i32` implements `From<u8>`
error[E0277]: `?` couldn't convert the error to `i32`
--> $DIR/question-mark-span-144304.rs:4: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<String>` 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<T>`:
`i32` implements `From<bool>`
`i32` implements `From<i16>`
`i32` implements `From<i8>`
`i32` implements `From<u16>`
`i32` implements `From<u8>`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.