Skip to content

Commit 7a9e0df

Browse files
committed
Fix span note for question mark expression
1 parent 1eb0657 commit 7a9e0df

File tree

5 files changed

+67
-17
lines changed

5 files changed

+67
-17
lines changed

compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,7 +1229,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
12291229
chain.push((expr.span, prev_ty));
12301230

12311231
let mut prev = None;
1232-
for (span, err_ty) in chain.into_iter().rev() {
1232+
let mut iter = chain.into_iter().rev().peekable();
1233+
while let Some((span, err_ty)) = iter.next() {
1234+
let is_last = iter.peek().is_none();
12331235
let err_ty = get_e_type(err_ty);
12341236
let err_ty = match (err_ty, prev) {
12351237
(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> {
12411243
continue;
12421244
}
12431245
};
1244-
if self
1246+
1247+
let implements_from = self
12451248
.infcx
12461249
.type_implements_trait(
12471250
self.tcx.get_diagnostic_item(sym::From).unwrap(),
12481251
[self_ty, err_ty],
12491252
obligation.param_env,
12501253
)
1251-
.must_apply_modulo_regions()
1252-
{
1253-
if !suggested {
1254-
let err_ty = self.tcx.short_string(err_ty, err.long_ty_path());
1255-
err.span_label(span, format!("this has type `Result<_, {err_ty}>`"));
1256-
}
1254+
.must_apply_modulo_regions();
1255+
1256+
let err_ty_str = self.tcx.short_string(err_ty, err.long_ty_path());
1257+
let label = if !implements_from && is_last {
1258+
format!(
1259+
"this can't be annotated with `?` because it has type `Result<_, {err_ty_str}>`"
1260+
)
12571261
} else {
1258-
let err_ty = self.tcx.short_string(err_ty, err.long_ty_path());
1259-
err.span_label(
1260-
span,
1261-
format!(
1262-
"this can't be annotated with `?` because it has type `Result<_, {err_ty}>`",
1263-
),
1264-
);
1262+
format!("this has type `Result<_, {err_ty_str}>`")
1263+
};
1264+
1265+
if !suggested || !implements_from {
1266+
err.span_label(span, label);
12651267
}
12661268
prev = Some(err_ty);
12671269
}

tests/ui/traits/question-mark-result-err-mismatch.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ fn foo() -> Result<String, String> { //~ NOTE expected `String` because of this
99
});
1010
let one = x
1111
.map(|s| ())
12-
.map_err(|e| { //~ NOTE this can't be annotated with `?` because it has type `Result<_, ()>`
12+
.map_err(|e| { //~ NOTE this has type `Result<_, ()>`
1313
e; //~ HELP remove this semicolon
1414
})
1515
.map(|()| "")?; //~ ERROR `?` couldn't convert the error to `String`

tests/ui/traits/question-mark-result-err-mismatch.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ LL | .map_err(|e| {
99
LL | | e;
1010
| | - help: remove this semicolon
1111
LL | | })
12-
| |__________- this can't be annotated with `?` because it has type `Result<_, ()>`
12+
| |__________- this has type `Result<_, ()>`
1313
LL | .map(|()| "")?;
1414
| ^ the trait `From<()>` is not implemented for `String`
1515
|
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn f() -> Result<(), i32> {
2+
Err("str").map_err(|e| e)?; //~ ERROR `?` couldn't convert the error to `i32`
3+
Err("str").map_err(|e| e.to_string())?; //~ ERROR `?` couldn't convert the error to `i32`
4+
Ok(())
5+
}
6+
7+
fn main() {}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
error[E0277]: `?` couldn't convert the error to `i32`
2+
--> $DIR/question-mark-span-144304.rs:2:30
3+
|
4+
LL | fn f() -> Result<(), i32> {
5+
| --------------- expected `i32` because of this
6+
LL | Err("str").map_err(|e| e)?;
7+
| ---------- ^ the trait `From<&str>` is not implemented for `i32`
8+
| |
9+
| this has type `Result<_, &str>`
10+
|
11+
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
12+
= help: the following other types implement trait `From<T>`:
13+
`i32` implements `From<bool>`
14+
`i32` implements `From<i16>`
15+
`i32` implements `From<i8>`
16+
`i32` implements `From<u16>`
17+
`i32` implements `From<u8>`
18+
19+
error[E0277]: `?` couldn't convert the error to `i32`
20+
--> $DIR/question-mark-span-144304.rs:3:42
21+
|
22+
LL | fn f() -> Result<(), i32> {
23+
| --------------- expected `i32` because of this
24+
LL | Err("str").map_err(|e| e)?;
25+
LL | Err("str").map_err(|e| e.to_string())?;
26+
| ---------- --------------------------^ the trait `From<String>` is not implemented for `i32`
27+
| | |
28+
| | this can't be annotated with `?` because it has type `Result<_, String>`
29+
| this has type `Result<_, &str>`
30+
|
31+
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
32+
= help: the following other types implement trait `From<T>`:
33+
`i32` implements `From<bool>`
34+
`i32` implements `From<i16>`
35+
`i32` implements `From<i8>`
36+
`i32` implements `From<u16>`
37+
`i32` implements `From<u8>`
38+
39+
error: aborting due to 2 previous errors
40+
41+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)