Skip to content

Commit d3a148f

Browse files
committed
When encountering unexpected closure return type, point at return type/expression
``` error[E0271]: expected `{[email protected]:18:40}` to be a closure that returns `()`, but it returns `!` --> $DIR/fallback-closure-wrap.rs:19:9 | LL | let error = Closure::wrap(Box::new(move || { | ------- LL | panic!("Can't connect to server."); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `!` | = note: expected unit type `()` found type `!` = note: required for the cast from `Box<{closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47}>` to `Box<dyn FnMut()>` ``` ``` error[E0271]: expected `{[email protected]:6:10}` to be a closure that returns `bool`, but it returns `Option<()>` --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:6:16 | LL | call(|| -> Option<()> { | ---- ------^^^^^^^^^^ | | | | | expected `bool`, found `Option<()>` | required by a bound introduced by this call | = note: expected type `bool` found enum `Option<()>` note: required by a bound in `call` --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:3:25 | LL | fn call(_: impl Fn() -> bool) {} | ^^^^ required by this bound in `call` ``` ``` error[E0271]: expected `{[email protected]:28:13}` to be a closure that returns `Result<(), _>`, but it returns `!` --> f670.rs:28:20 | 28 | let c = |e| -> ! { | -------^ | | | expected `Result<(), _>`, found `!` ... 32 | f().or_else(c); | ------- required by a bound introduced by this call -Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs:1433:28 | = note: expected enum `Result<(), _>` found type `!` note: required by a bound in `Result::<T, E>::or_else` --> /home/gh-estebank/rust/library/core/src/result.rs:1406:39 | 1406 | pub fn or_else<F, O: FnOnce(E) -> Result<T, F>>(self, op: O) -> Result<T, F> { | ^^^^^^^^^^^^ required by this bound in `Result::<T, E>::or_else` ```
1 parent a6434ef commit d3a148f

File tree

11 files changed

+116
-67
lines changed

11 files changed

+116
-67
lines changed

Diff for: compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

+3
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
642642
);
643643
let hir = tcx.hir();
644644
infcx.err_ctxt().note_type_err(
645+
cause.span,
645646
&mut diag,
646647
&cause,
647648
hir.get_if_local(impl_m.def_id)
@@ -1061,6 +1062,7 @@ fn report_trait_method_mismatch<'tcx>(
10611062

10621063
cause.span = impl_err_span;
10631064
infcx.err_ctxt().note_type_err(
1065+
cause.span,
10641066
&mut diag,
10651067
&cause,
10661068
trait_err_span.map(|sp| (sp, Cow::from("type in trait"), false)),
@@ -1853,6 +1855,7 @@ fn compare_const_predicate_entailment<'tcx>(
18531855
});
18541856

18551857
infcx.err_ctxt().note_type_err(
1858+
cause.span,
18561859
&mut diag,
18571860
&cause,
18581861
trait_c_span.map(|span| (span, Cow::from("type in trait"), false)),

Diff for: compiler/rustc_hir_analysis/src/check/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,7 @@ pub fn check_function_signature<'tcx>(
640640
let failure_code = cause.as_failure_code_diag(err, cause.span, vec![]);
641641
let mut diag = tcx.dcx().create_err(failure_code);
642642
err_ctxt.note_type_err(
643+
cause.span,
643644
&mut diag,
644645
&cause,
645646
None,

Diff for: compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1141,6 +1141,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
11411141
let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty);
11421142
if let Some(e) = error {
11431143
self.err_ctxt().note_type_err(
1144+
trace.cause.span,
11441145
&mut err,
11451146
&trace.cause,
11461147
None,

Diff for: compiler/rustc_passes/src/check_attr.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2462,6 +2462,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
24622462
}
24632463

24642464
infcx.err_ctxt().note_type_err(
2465+
cause.span,
24652466
&mut diag,
24662467
&cause,
24672468
None,

Diff for: compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1386,15 +1386,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
13861386
#[instrument(level = "debug", skip(self, diag, secondary_span, prefer_label))]
13871387
pub fn note_type_err(
13881388
&self,
1389+
span: Span,
13891390
diag: &mut Diag<'_>,
13901391
cause: &ObligationCause<'tcx>,
13911392
secondary_span: Option<(Span, Cow<'static, str>, bool)>,
13921393
mut values: Option<ty::ParamEnvAnd<'tcx, ValuePairs<'tcx>>>,
13931394
terr: TypeError<'tcx>,
13941395
prefer_label: bool,
13951396
) {
1396-
let span = cause.span;
1397-
13981397
// For some types of errors, expected-found does not make
13991398
// sense, so just ignore the values we were given.
14001399
if let TypeError::CyclicTy(_) = terr {
@@ -2053,6 +2052,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
20532052
);
20542053
let mut diag = self.dcx().create_err(failure_code);
20552054
self.note_type_err(
2055+
span,
20562056
&mut diag,
20572057
&trace.cause,
20582058
None,

Diff for: compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

+76-22
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
702702
);
703703

704704
self.note_type_err(
705+
span,
705706
&mut diag,
706707
&obligation.cause,
707708
None,
@@ -931,14 +932,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
931932
}
932933
}
933934
let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id);
934-
let body_id = match self.tcx.hir_node(hir_id) {
935-
hir::Node::Item(hir::Item {
936-
kind: hir::ItemKind::Fn { body: body_id, .. }, ..
937-
}) => body_id,
938-
_ => return false,
939-
};
940-
let ControlFlow::Break(expr) = (FindMethodSubexprOfTry { search_span: span })
941-
.visit_body(self.tcx.hir().body(*body_id))
935+
let Some(body_id) = self.tcx.hir_node(hir_id).body_id() else { return false };
936+
let ControlFlow::Break(expr) =
937+
(FindMethodSubexprOfTry { search_span: span }).visit_body(self.tcx.hir().body(body_id))
942938
else {
943939
return false;
944940
};
@@ -1385,22 +1381,50 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
13851381
_ => (None, error.err),
13861382
};
13871383

1388-
let msg = values
1384+
let (msg, span, closure_span) = values
13891385
.and_then(|(predicate, normalized_term, expected_term)| {
1390-
self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term)
1386+
self.maybe_detailed_projection_msg(
1387+
obligation.cause.span,
1388+
predicate,
1389+
normalized_term,
1390+
expected_term,
1391+
)
13911392
})
13921393
.unwrap_or_else(|| {
13931394
let mut cx = FmtPrinter::new_with_limit(
13941395
self.tcx,
13951396
Namespace::TypeNS,
13961397
rustc_session::Limit(10),
13971398
);
1398-
with_forced_trimmed_paths!(format!("type mismatch resolving `{}`", {
1399-
self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap();
1400-
cx.into_buffer()
1401-
}))
1399+
(
1400+
with_forced_trimmed_paths!(format!("type mismatch resolving `{}`", {
1401+
self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap();
1402+
cx.into_buffer()
1403+
})),
1404+
obligation.cause.span,
1405+
None,
1406+
)
14021407
});
1403-
let mut diag = struct_span_code_err!(self.dcx(), obligation.cause.span, E0271, "{msg}");
1408+
let mut diag = struct_span_code_err!(self.dcx(), span, E0271, "{msg}");
1409+
if let Some(span) = closure_span {
1410+
// Mark the closure decl so that it is seen even if we are pointing at the return
1411+
// type or expression.
1412+
//
1413+
// error[E0271]: expected `{[email protected]:41:16}` to be a closure that returns
1414+
// `Unit3`, but it returns `Unit4`
1415+
// --> $DIR/foo.rs:43:17
1416+
// |
1417+
// LL | let v = Unit2.m(
1418+
// | - required by a bound introduced by this call
1419+
// ...
1420+
// LL | f: |x| {
1421+
// | --- /* this span */
1422+
// LL | drop(x);
1423+
// LL | Unit4
1424+
// | ^^^^^ expected `Unit3`, found `Unit4`
1425+
// |
1426+
diag.span_label(span, "");
1427+
}
14041428

14051429
let secondary_span = (|| {
14061430
let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) =
@@ -1460,6 +1484,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
14601484
})();
14611485

14621486
self.note_type_err(
1487+
span,
14631488
&mut diag,
14641489
&obligation.cause,
14651490
secondary_span,
@@ -1479,34 +1504,63 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
14791504

14801505
fn maybe_detailed_projection_msg(
14811506
&self,
1507+
mut span: Span,
14821508
projection_term: ty::AliasTerm<'tcx>,
14831509
normalized_ty: ty::Term<'tcx>,
14841510
expected_ty: ty::Term<'tcx>,
1485-
) -> Option<String> {
1511+
) -> Option<(String, Span, Option<Span>)> {
14861512
let trait_def_id = projection_term.trait_def_id(self.tcx);
14871513
let self_ty = projection_term.self_ty();
14881514

14891515
with_forced_trimmed_paths! {
14901516
if self.tcx.is_lang_item(projection_term.def_id, LangItem::FnOnceOutput) {
14911517
let fn_kind = self_ty.prefix_string(self.tcx);
1518+
let (span, closure_span) = if let ty::Closure(def_id, _) = self_ty.kind() {
1519+
let def_span = self.tcx.def_span(def_id);
1520+
let node = self.tcx.hir_node_by_def_id(def_id.as_local().unwrap());
1521+
if let Some(fn_decl) = node.fn_decl() {
1522+
span = match fn_decl.output {
1523+
hir::FnRetTy::Return(ty) => ty.span,
1524+
hir::FnRetTy::DefaultReturn(_) => {
1525+
let body = self.tcx.hir().body(node.body_id().unwrap());
1526+
match body.value.kind {
1527+
hir::ExprKind::Block(
1528+
hir::Block { expr: Some(expr), .. },
1529+
_,
1530+
) => expr.span,
1531+
hir::ExprKind::Block(
1532+
hir::Block {
1533+
expr: None, stmts: [.., last], ..
1534+
},
1535+
_,
1536+
) => last.span,
1537+
_ => body.value.span,
1538+
}
1539+
}
1540+
};
1541+
}
1542+
(span, Some(def_span))
1543+
} else {
1544+
(span, None)
1545+
};
14921546
let item = match self_ty.kind() {
14931547
ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(),
14941548
_ => self_ty.to_string(),
14951549
};
1496-
Some(format!(
1550+
Some((format!(
14971551
"expected `{item}` to be a {fn_kind} that returns `{expected_ty}`, but it \
14981552
returns `{normalized_ty}`",
1499-
))
1553+
), span, closure_span))
15001554
} else if self.tcx.is_lang_item(trait_def_id, LangItem::Future) {
1501-
Some(format!(
1555+
Some((format!(
15021556
"expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \
15031557
resolves to `{normalized_ty}`"
1504-
))
1558+
), span, None))
15051559
} else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) {
1506-
Some(format!(
1560+
Some((format!(
15071561
"expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \
15081562
yields `{normalized_ty}`"
1509-
))
1563+
), span, None))
15101564
} else {
15111565
None
15121566
}

Diff for: tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr

+6-11
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,13 @@ LL | true
2121
found type `bool`
2222

2323
error[E0271]: expected `{[email protected]:6:10}` to be a closure that returns `bool`, but it returns `Option<()>`
24-
--> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:6:10
24+
--> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:6:16
2525
|
26-
LL | call(|| -> Option<()> {
27-
| _____----_^
28-
| | |
29-
| | required by a bound introduced by this call
30-
LL | |
31-
LL | | if true {
32-
LL | | false
33-
... |
34-
LL | | })
35-
| |_____^ expected `bool`, found `Option<()>`
26+
LL | call(|| -> Option<()> {
27+
| ---- ------^^^^^^^^^^
28+
| | |
29+
| | expected `bool`, found `Option<()>`
30+
| required by a bound introduced by this call
3631
|
3732
= note: expected type `bool`
3833
found enum `Option<()>`

Diff for: tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,10 @@ trait Ty<'a> {
3636

3737
fn main() {
3838
let v = Unit2.m(
39-
L {
40-
//~^ ERROR to be a closure that returns `Unit3`, but it returns `Unit4`
41-
//~| ERROR type mismatch
39+
L { //~ ERROR type mismatch
4240
f: |x| {
4341
drop(x);
44-
Unit4
42+
Unit4 //~ ERROR to be a closure that returns `Unit3`, but it returns `Unit4`
4543
},
4644
},
4745
);

Diff for: tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr

+17-20
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
error[E0271]: type mismatch resolving `<L<{[email protected]:42:16}> as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V`
1+
error[E0271]: type mismatch resolving `<L<{[email protected]:40:16}> as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V`
22
--> $DIR/issue-62203-hrtb-ice.rs:39:9
33
|
44
LL | let v = Unit2.m(
55
| - required by a bound introduced by this call
66
LL | / L {
7-
LL | |
8-
LL | |
97
LL | | f: |x| {
10-
... |
8+
LL | | drop(x);
9+
LL | | Unit4
1110
LL | | },
1211
LL | | },
13-
| |_________^ type mismatch resolving `<L<{[email protected]:42:16}> as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V`
12+
| |_________^ type mismatch resolving `<L<{[email protected]:40:16}> as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V`
1413
|
1514
note: expected this to be `<_ as Ty<'_>>::V`
1615
--> $DIR/issue-62203-hrtb-ice.rs:21:14
@@ -30,21 +29,19 @@ LL | where
3029
LL | F: for<'r> T0<'r, (<Self as Ty<'r>>::V,), O = <B as Ty<'r>>::V>,
3130
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m`
3231

33-
error[E0271]: expected `{[email protected]:42:16}` to be a closure that returns `Unit3`, but it returns `Unit4`
34-
--> $DIR/issue-62203-hrtb-ice.rs:39:9
35-
|
36-
LL | let v = Unit2.m(
37-
| - required by a bound introduced by this call
38-
LL | / L {
39-
LL | |
40-
LL | |
41-
LL | | f: |x| {
42-
... |
43-
LL | | },
44-
LL | | },
45-
| |_________^ expected `Unit3`, found `Unit4`
46-
|
47-
note: required for `L<{closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19}>` to implement `for<'r> T0<'r, (&'r u8,)>`
32+
error[E0271]: expected `{[email protected]:40:16}` to be a closure that returns `Unit3`, but it returns `Unit4`
33+
--> $DIR/issue-62203-hrtb-ice.rs:42:17
34+
|
35+
LL | let v = Unit2.m(
36+
| - required by a bound introduced by this call
37+
LL | L {
38+
LL | f: |x| {
39+
| ---
40+
LL | drop(x);
41+
LL | Unit4
42+
| ^^^^^ expected `Unit3`, found `Unit4`
43+
|
44+
note: required for `L<{closure@$DIR/issue-62203-hrtb-ice.rs:40:16: 40:19}>` to implement `for<'r> T0<'r, (&'r u8,)>`
4845
--> $DIR/issue-62203-hrtb-ice.rs:17:16
4946
|
5047
LL | impl<'a, A, T> T0<'a, A> for L<T>

Diff for: tests/ui/never_type/fallback-closure-wrap.fallback.stderr

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
error[E0271]: expected `{[email protected]:18:40}` to be a closure that returns `()`, but it returns `!`
2-
--> $DIR/fallback-closure-wrap.rs:18:31
2+
--> $DIR/fallback-closure-wrap.rs:19:9
33
|
4-
LL | let error = Closure::wrap(Box::new(move || {
5-
| _______________________________^
6-
LL | |
7-
LL | | panic!("Can't connect to server.");
8-
LL | | }) as Box<dyn FnMut()>);
9-
| |______^ expected `()`, found `!`
4+
LL | let error = Closure::wrap(Box::new(move || {
5+
| -------
6+
LL | panic!("Can't connect to server.");
7+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `!`
108
|
119
= note: expected unit type `()`
1210
found type `!`
1311
= note: required for the cast from `Box<{closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47}>` to `Box<dyn FnMut()>`
12+
= note: this error originates in the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
1413

1514
error: aborting due to 1 previous error
1615

Diff for: tests/ui/never_type/fallback-closure-wrap.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use std::marker::PhantomData;
1616

1717
fn main() {
1818
let error = Closure::wrap(Box::new(move || {
19-
//[fallback]~^ to be a closure that returns `()`, but it returns `!`
2019
panic!("Can't connect to server.");
20+
//[fallback]~^ to be a closure that returns `()`, but it returns `!`
2121
}) as Box<dyn FnMut()>);
2222
}
2323

0 commit comments

Comments
 (0)