From d3a148fe07bf2bcab0d262463f0f892f555e0aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 25 Oct 2024 21:27:13 +0000 Subject: [PATCH 1/5] When encountering unexpected closure return type, point at return type/expression ``` error[E0271]: expected `{closure@fallback-closure-wrap.rs: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` ``` ``` error[E0271]: expected `{closure@dont-ice-for-type-mismatch-in-closure-in-async.rs: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 `{closure@f670.rs: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::::or_else` --> /home/gh-estebank/rust/library/core/src/result.rs:1406:39 | 1406 | pub fn or_else Result>(self, op: O) -> Result { | ^^^^^^^^^^^^ required by this bound in `Result::::or_else` ``` --- .../src/check/compare_impl_item.rs | 3 + compiler/rustc_hir_analysis/src/check/mod.rs | 1 + .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 1 + .../src/error_reporting/infer/mod.rs | 4 +- .../traits/fulfillment_errors.rs | 98 ++++++++++++++----- ...r-type-mismatch-in-closure-in-async.stderr | 17 ++-- .../trait-bounds/issue-62203-hrtb-ice.rs | 6 +- .../trait-bounds/issue-62203-hrtb-ice.stderr | 37 ++++--- .../fallback-closure-wrap.fallback.stderr | 13 ++- tests/ui/never_type/fallback-closure-wrap.rs | 2 +- 11 files changed, 116 insertions(+), 67 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 7332888c5f913..717d6f9dd737d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -642,6 +642,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( ); let hir = tcx.hir(); infcx.err_ctxt().note_type_err( + cause.span, &mut diag, &cause, hir.get_if_local(impl_m.def_id) @@ -1061,6 +1062,7 @@ fn report_trait_method_mismatch<'tcx>( cause.span = impl_err_span; infcx.err_ctxt().note_type_err( + cause.span, &mut diag, &cause, trait_err_span.map(|sp| (sp, Cow::from("type in trait"), false)), @@ -1853,6 +1855,7 @@ fn compare_const_predicate_entailment<'tcx>( }); infcx.err_ctxt().note_type_err( + cause.span, &mut diag, &cause, trait_c_span.map(|span| (span, Cow::from("type in trait"), false)), diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 814c784710a1f..3cf662a635afe 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -640,6 +640,7 @@ pub fn check_function_signature<'tcx>( let failure_code = cause.as_failure_code_diag(err, cause.span, vec![]); let mut diag = tcx.dcx().create_err(failure_code); err_ctxt.note_type_err( + cause.span, &mut diag, &cause, None, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 8e78fb3e2191f..e76ce420bedc8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1141,6 +1141,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty); if let Some(e) = error { self.err_ctxt().note_type_err( + trace.cause.span, &mut err, &trace.cause, None, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index e19819a22b4fc..c9a429846fd80 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2462,6 +2462,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } infcx.err_ctxt().note_type_err( + cause.span, &mut diag, &cause, None, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 9eacd377361a7..da9386c00ba8e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1386,6 +1386,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self, diag, secondary_span, prefer_label))] pub fn note_type_err( &self, + span: Span, diag: &mut Diag<'_>, cause: &ObligationCause<'tcx>, secondary_span: Option<(Span, Cow<'static, str>, bool)>, @@ -1393,8 +1394,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { terr: TypeError<'tcx>, prefer_label: bool, ) { - let span = cause.span; - // For some types of errors, expected-found does not make // sense, so just ignore the values we were given. if let TypeError::CyclicTy(_) = terr { @@ -2053,6 +2052,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); let mut diag = self.dcx().create_err(failure_code); self.note_type_err( + span, &mut diag, &trace.cause, None, 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 6d39cbce3b788..24615dfdc56c3 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 @@ -702,6 +702,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); self.note_type_err( + span, &mut diag, &obligation.cause, None, @@ -931,14 +932,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id); - let body_id = match self.tcx.hir_node(hir_id) { - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn { body: body_id, .. }, .. - }) => body_id, - _ => return false, - }; - let ControlFlow::Break(expr) = (FindMethodSubexprOfTry { search_span: span }) - .visit_body(self.tcx.hir().body(*body_id)) + let Some(body_id) = self.tcx.hir_node(hir_id).body_id() else { return false }; + let ControlFlow::Break(expr) = + (FindMethodSubexprOfTry { search_span: span }).visit_body(self.tcx.hir().body(body_id)) else { return false; }; @@ -1385,9 +1381,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => (None, error.err), }; - let msg = values + let (msg, span, closure_span) = values .and_then(|(predicate, normalized_term, expected_term)| { - self.maybe_detailed_projection_msg(predicate, normalized_term, expected_term) + self.maybe_detailed_projection_msg( + obligation.cause.span, + predicate, + normalized_term, + expected_term, + ) }) .unwrap_or_else(|| { let mut cx = FmtPrinter::new_with_limit( @@ -1395,12 +1396,35 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Namespace::TypeNS, rustc_session::Limit(10), ); - with_forced_trimmed_paths!(format!("type mismatch resolving `{}`", { - self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap(); - cx.into_buffer() - })) + ( + with_forced_trimmed_paths!(format!("type mismatch resolving `{}`", { + self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap(); + cx.into_buffer() + })), + obligation.cause.span, + None, + ) }); - let mut diag = struct_span_code_err!(self.dcx(), obligation.cause.span, E0271, "{msg}"); + let mut diag = struct_span_code_err!(self.dcx(), span, E0271, "{msg}"); + if let Some(span) = closure_span { + // Mark the closure decl so that it is seen even if we are pointing at the return + // type or expression. + // + // error[E0271]: expected `{closure@foo.rs:41:16}` to be a closure that returns + // `Unit3`, but it returns `Unit4` + // --> $DIR/foo.rs:43:17 + // | + // LL | let v = Unit2.m( + // | - required by a bound introduced by this call + // ... + // LL | f: |x| { + // | --- /* this span */ + // LL | drop(x); + // LL | Unit4 + // | ^^^^^ expected `Unit3`, found `Unit4` + // | + diag.span_label(span, ""); + } let secondary_span = (|| { let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = @@ -1460,6 +1484,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { })(); self.note_type_err( + span, &mut diag, &obligation.cause, secondary_span, @@ -1479,34 +1504,63 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn maybe_detailed_projection_msg( &self, + mut span: Span, projection_term: ty::AliasTerm<'tcx>, normalized_ty: ty::Term<'tcx>, expected_ty: ty::Term<'tcx>, - ) -> Option { + ) -> Option<(String, Span, Option)> { let trait_def_id = projection_term.trait_def_id(self.tcx); let self_ty = projection_term.self_ty(); with_forced_trimmed_paths! { if self.tcx.is_lang_item(projection_term.def_id, LangItem::FnOnceOutput) { let fn_kind = self_ty.prefix_string(self.tcx); + let (span, closure_span) = if let ty::Closure(def_id, _) = self_ty.kind() { + let def_span = self.tcx.def_span(def_id); + let node = self.tcx.hir_node_by_def_id(def_id.as_local().unwrap()); + if let Some(fn_decl) = node.fn_decl() { + span = match fn_decl.output { + hir::FnRetTy::Return(ty) => ty.span, + hir::FnRetTy::DefaultReturn(_) => { + let body = self.tcx.hir().body(node.body_id().unwrap()); + match body.value.kind { + hir::ExprKind::Block( + hir::Block { expr: Some(expr), .. }, + _, + ) => expr.span, + hir::ExprKind::Block( + hir::Block { + expr: None, stmts: [.., last], .. + }, + _, + ) => last.span, + _ => body.value.span, + } + } + }; + } + (span, Some(def_span)) + } else { + (span, None) + }; let item = match self_ty.kind() { ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(), _ => self_ty.to_string(), }; - Some(format!( + Some((format!( "expected `{item}` to be a {fn_kind} that returns `{expected_ty}`, but it \ returns `{normalized_ty}`", - )) + ), span, closure_span)) } else if self.tcx.is_lang_item(trait_def_id, LangItem::Future) { - Some(format!( + Some((format!( "expected `{self_ty}` to be a future that resolves to `{expected_ty}`, but it \ resolves to `{normalized_ty}`" - )) + ), span, None)) } else if Some(trait_def_id) == self.tcx.get_diagnostic_item(sym::Iterator) { - Some(format!( + Some((format!( "expected `{self_ty}` to be an iterator that yields `{expected_ty}`, but it \ yields `{normalized_ty}`" - )) + ), span, None)) } else { None } diff --git a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr index b60f6a0833867..6e8df91767de1 100644 --- a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr +++ b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr @@ -21,18 +21,13 @@ LL | true found type `bool` error[E0271]: expected `{closure@dont-ice-for-type-mismatch-in-closure-in-async.rs: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:10 + --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:6:16 | -LL | call(|| -> Option<()> { - | _____----_^ - | | | - | | required by a bound introduced by this call -LL | | -LL | | if true { -LL | | false -... | -LL | | }) - | |_____^ expected `bool`, found `Option<()>` +LL | call(|| -> Option<()> { + | ---- ------^^^^^^^^^^ + | | | + | | expected `bool`, found `Option<()>` + | required by a bound introduced by this call | = note: expected type `bool` found enum `Option<()>` diff --git a/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs index e70f6fc3430f6..f2b73d6926189 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs @@ -36,12 +36,10 @@ trait Ty<'a> { fn main() { let v = Unit2.m( - L { - //~^ ERROR to be a closure that returns `Unit3`, but it returns `Unit4` - //~| ERROR type mismatch + L { //~ ERROR type mismatch f: |x| { drop(x); - Unit4 + Unit4 //~ ERROR to be a closure that returns `Unit3`, but it returns `Unit4` }, }, ); diff --git a/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr index 74610b55dc373..411b99e2bbba1 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr @@ -1,16 +1,15 @@ -error[E0271]: type mismatch resolving ` as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V` +error[E0271]: type mismatch resolving ` as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V` --> $DIR/issue-62203-hrtb-ice.rs:39:9 | LL | let v = Unit2.m( | - required by a bound introduced by this call LL | / L { -LL | | -LL | | LL | | f: |x| { -... | +LL | | drop(x); +LL | | Unit4 LL | | }, LL | | }, - | |_________^ type mismatch resolving ` as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V` + | |_________^ type mismatch resolving ` as T0<'r, (&u8,)>>::O == <_ as Ty<'r>>::V` | note: expected this to be `<_ as Ty<'_>>::V` --> $DIR/issue-62203-hrtb-ice.rs:21:14 @@ -30,21 +29,19 @@ LL | where LL | F: for<'r> T0<'r, (>::V,), O = >::V>, | ^^^^^^^^^^^^^^^^^^^^ required by this bound in `T1::m` -error[E0271]: expected `{closure@issue-62203-hrtb-ice.rs:42:16}` to be a closure that returns `Unit3`, but it returns `Unit4` - --> $DIR/issue-62203-hrtb-ice.rs:39:9 - | -LL | let v = Unit2.m( - | - required by a bound introduced by this call -LL | / L { -LL | | -LL | | -LL | | f: |x| { -... | -LL | | }, -LL | | }, - | |_________^ expected `Unit3`, found `Unit4` - | -note: required for `L<{closure@$DIR/issue-62203-hrtb-ice.rs:42:16: 42:19}>` to implement `for<'r> T0<'r, (&'r u8,)>` +error[E0271]: expected `{closure@issue-62203-hrtb-ice.rs:40:16}` to be a closure that returns `Unit3`, but it returns `Unit4` + --> $DIR/issue-62203-hrtb-ice.rs:42:17 + | +LL | let v = Unit2.m( + | - required by a bound introduced by this call +LL | L { +LL | f: |x| { + | --- +LL | drop(x); +LL | Unit4 + | ^^^^^ expected `Unit3`, found `Unit4` + | +note: required for `L<{closure@$DIR/issue-62203-hrtb-ice.rs:40:16: 40:19}>` to implement `for<'r> T0<'r, (&'r u8,)>` --> $DIR/issue-62203-hrtb-ice.rs:17:16 | LL | impl<'a, A, T> T0<'a, A> for L diff --git a/tests/ui/never_type/fallback-closure-wrap.fallback.stderr b/tests/ui/never_type/fallback-closure-wrap.fallback.stderr index aa4a2760ffdc6..031c522b69e54 100644 --- a/tests/ui/never_type/fallback-closure-wrap.fallback.stderr +++ b/tests/ui/never_type/fallback-closure-wrap.fallback.stderr @@ -1,16 +1,15 @@ error[E0271]: expected `{closure@fallback-closure-wrap.rs:18:40}` to be a closure that returns `()`, but it returns `!` - --> $DIR/fallback-closure-wrap.rs:18:31 + --> $DIR/fallback-closure-wrap.rs:19:9 | -LL | let error = Closure::wrap(Box::new(move || { - | _______________________________^ -LL | | -LL | | panic!("Can't connect to server."); -LL | | }) as Box); - | |______^ expected `()`, found `!` +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` + = note: this error originates in the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/never_type/fallback-closure-wrap.rs b/tests/ui/never_type/fallback-closure-wrap.rs index 27020289c683c..e97505b6bc0c3 100644 --- a/tests/ui/never_type/fallback-closure-wrap.rs +++ b/tests/ui/never_type/fallback-closure-wrap.rs @@ -16,8 +16,8 @@ use std::marker::PhantomData; fn main() { let error = Closure::wrap(Box::new(move || { - //[fallback]~^ to be a closure that returns `()`, but it returns `!` panic!("Can't connect to server."); + //[fallback]~^ to be a closure that returns `()`, but it returns `!` }) as Box); } From 03e9a383906ca85e264f056f490c091fdef30a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 25 Oct 2024 23:23:15 +0000 Subject: [PATCH 2/5] On E0271 for a closure behind a binding, point at binding in call too ``` error[E0271]: expected `{closure@return-type-doesnt-match-bound.rs:18:13}` to be a closure that returns `Result<(), _>`, but it returns `!` --> tests/ui/closures/return-type-doesnt-match-bound.rs:18:20 | 18 | let c = |e| -> ! { //~ ERROR to be a closure that returns | -------^ | | | expected `Result<(), _>`, found `!` ... 22 | f().or_else(c); | ------- - | | | required by a bound introduced by this call | = note: expected enum `Result<(), _>` found type `!` note: required by a bound in `Result::::or_else` --> /home/gh-estebank/rust/library/core/src/result.rs:1406:39 | 1406 | pub fn or_else Result>(self, op: O) -> Result { | ^^^^^^^^^^^^ required by this bound in `Result::::or_else` ``` --- .../traits/fulfillment_errors.rs | 4 +++ .../return-type-doesnt-match-bound.rs | 25 +++++++++++++ .../return-type-doesnt-match-bound.stderr | 35 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 tests/ui/closures/return-type-doesnt-match-bound.rs create mode 100644 tests/ui/closures/return-type-doesnt-match-bound.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 24615dfdc56c3..78f6cd9e65635 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 @@ -1424,6 +1424,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // | ^^^^^ expected `Unit3`, found `Unit4` // | diag.span_label(span, ""); + if !span.overlaps(obligation.cause.span) { + // Point at the binding corresponding to the closure where it is used. + diag.span_label(obligation.cause.span, ""); + } } let secondary_span = (|| { diff --git a/tests/ui/closures/return-type-doesnt-match-bound.rs b/tests/ui/closures/return-type-doesnt-match-bound.rs new file mode 100644 index 0000000000000..f9098d0cb5cca --- /dev/null +++ b/tests/ui/closures/return-type-doesnt-match-bound.rs @@ -0,0 +1,25 @@ +use std::error::Error; +use std::process::exit; + +fn foo(f: F) -> () +where + F: FnOnce() -> Result<(), Box>, +{ + f().or_else(|e| -> ! { //~ ERROR to be a closure that returns + eprintln!("{:?}", e); + exit(1) + }); +} + +fn bar(f: F) -> () +where + F: FnOnce() -> Result<(), Box>, +{ + let c = |e| -> ! { //~ ERROR to be a closure that returns + eprintln!("{:?}", e); + exit(1) + }; + f().or_else(c); +} + +fn main() {} diff --git a/tests/ui/closures/return-type-doesnt-match-bound.stderr b/tests/ui/closures/return-type-doesnt-match-bound.stderr new file mode 100644 index 0000000000000..c6aad2054f54d --- /dev/null +++ b/tests/ui/closures/return-type-doesnt-match-bound.stderr @@ -0,0 +1,35 @@ +error[E0271]: expected `{closure@return-type-doesnt-match-bound.rs:8:17}` to be a closure that returns `Result<(), _>`, but it returns `!` + --> $DIR/return-type-doesnt-match-bound.rs:8:24 + | +LL | f().or_else(|e| -> ! { + | ------- -------^ + | | | + | | expected `Result<(), _>`, found `!` + | required by a bound introduced by this call + | + = note: expected enum `Result<(), _>` + found type `!` +note: required by a bound in `Result::::or_else` + --> $SRC_DIR/core/src/result.rs:LL:COL + +error[E0271]: expected `{closure@return-type-doesnt-match-bound.rs:18:13}` to be a closure that returns `Result<(), _>`, but it returns `!` + --> $DIR/return-type-doesnt-match-bound.rs:18:20 + | +LL | let c = |e| -> ! { + | -------^ + | | + | expected `Result<(), _>`, found `!` +... +LL | f().or_else(c); + | ------- - + | | + | required by a bound introduced by this call + | + = note: expected enum `Result<(), _>` + found type `!` +note: required by a bound in `Result::::or_else` + --> $SRC_DIR/core/src/result.rs:LL:COL + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. From 87d323c81e77545fc9a3878277430c1e0d58805f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 27 Oct 2024 19:03:13 +0000 Subject: [PATCH 3/5] Add closure labels --- .../src/error_reporting/traits/fulfillment_errors.rs | 4 ++-- ...-ice-for-type-mismatch-in-closure-in-async.stderr | 5 +++-- .../closures/return-type-doesnt-match-bound.stderr | 12 +++++++----- .../trait-bounds/issue-62203-hrtb-ice.stderr | 2 +- .../never_type/fallback-closure-wrap.fallback.stderr | 2 +- 5 files changed, 14 insertions(+), 11 deletions(-) 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 78f6cd9e65635..22e88b36af324 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 @@ -1423,10 +1423,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // LL | Unit4 // | ^^^^^ expected `Unit3`, found `Unit4` // | - diag.span_label(span, ""); + diag.span_label(span, "this closure"); if !span.overlaps(obligation.cause.span) { // Point at the binding corresponding to the closure where it is used. - diag.span_label(obligation.cause.span, ""); + diag.span_label(obligation.cause.span, "closure used here"); } } diff --git a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr index 6e8df91767de1..f478d55d10e35 100644 --- a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr +++ b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr @@ -25,8 +25,9 @@ error[E0271]: expected `{closure@dont-ice-for-type-mismatch-in-closure-in-async. | LL | call(|| -> Option<()> { | ---- ------^^^^^^^^^^ - | | | - | | expected `bool`, found `Option<()>` + | | | | + | | | expected `bool`, found `Option<()>` + | | this closure | required by a bound introduced by this call | = note: expected type `bool` diff --git a/tests/ui/closures/return-type-doesnt-match-bound.stderr b/tests/ui/closures/return-type-doesnt-match-bound.stderr index c6aad2054f54d..f796a5552ac0c 100644 --- a/tests/ui/closures/return-type-doesnt-match-bound.stderr +++ b/tests/ui/closures/return-type-doesnt-match-bound.stderr @@ -3,8 +3,9 @@ error[E0271]: expected `{closure@return-type-doesnt-match-bound.rs:8:17}` to be | LL | f().or_else(|e| -> ! { | ------- -------^ - | | | - | | expected `Result<(), _>`, found `!` + | | | | + | | | expected `Result<(), _>`, found `!` + | | this closure | required by a bound introduced by this call | = note: expected enum `Result<(), _>` @@ -17,11 +18,12 @@ error[E0271]: expected `{closure@return-type-doesnt-match-bound.rs:18:13}` to be | LL | let c = |e| -> ! { | -------^ - | | - | expected `Result<(), _>`, found `!` + | | | + | | expected `Result<(), _>`, found `!` + | this closure ... LL | f().or_else(c); - | ------- - + | ------- - closure used here | | | required by a bound introduced by this call | diff --git a/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr index 411b99e2bbba1..d0675d5020c80 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.stderr @@ -36,7 +36,7 @@ LL | let v = Unit2.m( | - required by a bound introduced by this call LL | L { LL | f: |x| { - | --- + | --- this closure LL | drop(x); LL | Unit4 | ^^^^^ expected `Unit3`, found `Unit4` diff --git a/tests/ui/never_type/fallback-closure-wrap.fallback.stderr b/tests/ui/never_type/fallback-closure-wrap.fallback.stderr index 031c522b69e54..a559a95a334ad 100644 --- a/tests/ui/never_type/fallback-closure-wrap.fallback.stderr +++ b/tests/ui/never_type/fallback-closure-wrap.fallback.stderr @@ -2,7 +2,7 @@ error[E0271]: expected `{closure@fallback-closure-wrap.rs:18:40}` to be a closur --> $DIR/fallback-closure-wrap.rs:19:9 | LL | let error = Closure::wrap(Box::new(move || { - | ------- + | ------- this closure LL | panic!("Can't connect to server."); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `!` | From d2a781a2ecbf02edf11deb5b3320d10ae5f34830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 27 Oct 2024 19:12:16 +0000 Subject: [PATCH 4/5] Remove `unwrap()`s --- .../src/error_reporting/traits/fulfillment_errors.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 22e88b36af324..3b313530a603e 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 @@ -1521,12 +1521,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let fn_kind = self_ty.prefix_string(self.tcx); let (span, closure_span) = if let ty::Closure(def_id, _) = self_ty.kind() { let def_span = self.tcx.def_span(def_id); - let node = self.tcx.hir_node_by_def_id(def_id.as_local().unwrap()); - if let Some(fn_decl) = node.fn_decl() { + if let Some(local_def_id) = def_id.as_local() + && let node = self.tcx.hir_node_by_def_id(local_def_id) + && let Some(fn_decl) = node.fn_decl() + && let Some(id) = node.body_id() + { span = match fn_decl.output { hir::FnRetTy::Return(ty) => ty.span, hir::FnRetTy::DefaultReturn(_) => { - let body = self.tcx.hir().body(node.body_id().unwrap()); + let body = self.tcx.hir().body(id); match body.value.kind { hir::ExprKind::Block( hir::Block { expr: Some(expr), .. }, From d11676711347a220339f3601c79f74076bdb43a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 27 Oct 2024 19:23:21 +0000 Subject: [PATCH 5/5] review comment: change `span` argument --- .../rustc_hir_analysis/src/check/compare_impl_item.rs | 6 +++--- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- .../src/error_reporting/infer/mod.rs | 9 +++++++-- .../src/error_reporting/traits/fulfillment_errors.rs | 4 ++-- 6 files changed, 15 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 717d6f9dd737d..5823d86776cd5 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -642,7 +642,6 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( ); let hir = tcx.hir(); infcx.err_ctxt().note_type_err( - cause.span, &mut diag, &cause, hir.get_if_local(impl_m.def_id) @@ -654,6 +653,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( }))), terr, false, + None, ); return Err(diag.emit()); } @@ -1062,7 +1062,6 @@ fn report_trait_method_mismatch<'tcx>( cause.span = impl_err_span; infcx.err_ctxt().note_type_err( - cause.span, &mut diag, &cause, trait_err_span.map(|sp| (sp, Cow::from("type in trait"), false)), @@ -1072,6 +1071,7 @@ fn report_trait_method_mismatch<'tcx>( }))), terr, false, + None, ); diag.emit() @@ -1855,7 +1855,6 @@ fn compare_const_predicate_entailment<'tcx>( }); infcx.err_ctxt().note_type_err( - cause.span, &mut diag, &cause, trait_c_span.map(|span| (span, Cow::from("type in trait"), false)), @@ -1865,6 +1864,7 @@ fn compare_const_predicate_entailment<'tcx>( }))), terr, false, + None, ); return Err(diag.emit()); }; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 3cf662a635afe..067edaa349a28 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -640,7 +640,6 @@ pub fn check_function_signature<'tcx>( let failure_code = cause.as_failure_code_diag(err, cause.span, vec![]); let mut diag = tcx.dcx().create_err(failure_code); err_ctxt.note_type_err( - cause.span, &mut diag, &cause, None, @@ -650,6 +649,7 @@ pub fn check_function_signature<'tcx>( }))), err, false, + None, ); return Err(diag.emit()); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index e76ce420bedc8..fb5fc109ce467 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1141,13 +1141,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty); if let Some(e) = error { self.err_ctxt().note_type_err( - trace.cause.span, &mut err, &trace.cause, None, Some(self.param_env.and(trace.values)), e, true, + None, ); } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c9a429846fd80..837da6e7724ca 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2462,7 +2462,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } infcx.err_ctxt().note_type_err( - cause.span, &mut diag, &cause, None, @@ -2472,6 +2471,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }))), terr, false, + None, ); diag.emit(); self.abort.set(true); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index da9386c00ba8e..01b26583c44ba 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -1386,14 +1386,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self, diag, secondary_span, prefer_label))] pub fn note_type_err( &self, - span: Span, diag: &mut Diag<'_>, cause: &ObligationCause<'tcx>, secondary_span: Option<(Span, Cow<'static, str>, bool)>, mut values: Option>>, terr: TypeError<'tcx>, prefer_label: bool, + override_span: Option, ) { + // We use `override_span` when we want the error to point at a `Span` other than + // `cause.span`. This is used in E0271, when a closure is passed in where the return type + // isn't what was expected. We want to point at the closure's return type (or expression), + // instead of the expression where the closure is passed as call argument. + let span = override_span.unwrap_or(cause.span); // For some types of errors, expected-found does not make // sense, so just ignore the values we were given. if let TypeError::CyclicTy(_) = terr { @@ -2052,13 +2057,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); let mut diag = self.dcx().create_err(failure_code); self.note_type_err( - span, &mut diag, &trace.cause, None, Some(param_env.and(trace.values)), terr, false, + None, ); diag } 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 3b313530a603e..6416c539f2616 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 @@ -702,13 +702,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); self.note_type_err( - span, &mut diag, &obligation.cause, None, None, TypeError::Sorts(ty::error::ExpectedFound::new(expected_ty, ct_ty)), false, + None, ); diag } @@ -1488,7 +1488,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { })(); self.note_type_err( - span, &mut diag, &obligation.cause, secondary_span, @@ -1500,6 +1499,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }), err, false, + Some(span), ); self.note_obligation_cause(&mut diag, obligation); diag.emit()