diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2024-10-25 21:27:13 +0000 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2025-01-30 18:38:37 +0000 |
| commit | d3a148fe07bf2bcab0d262463f0f892f555e0aa6 (patch) | |
| tree | 2e9ffaf29f755bd3dd7402c4eef3179be9235f86 /compiler | |
| parent | a6434ef9c0246fa39eecb34e22807da2a68f3904 (diff) | |
| download | rust-d3a148fe07bf2bcab0d262463f0f892f555e0aa6.tar.gz rust-d3a148fe07bf2bcab0d262463f0f892f555e0aa6.zip | |
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<dyn FnMut()>`
```
```
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::<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`
```
Diffstat (limited to 'compiler')
6 files changed, 84 insertions, 24 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 7332888c5f9..717d6f9dd73 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 814c784710a..3cf662a635a 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 8e78fb3e219..e76ce420bed 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 e19819a22b4..c9a429846fd 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 9eacd377361..da9386c00ba 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 6d39cbce3b7..24615dfdc56 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<String> { + ) -> Option<(String, Span, Option<Span>)> { 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 } |
