From ca2139d3262232d6b15471783f503ffe125531f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 16 Mar 2026 22:38:16 +0000 Subject: [PATCH] Point at return type when it is the source of the type expectation When calling an fn that returns a return type as a returned expression, point at the return type to explain that it affects the expected type. ``` error[E0308]: mismatched types --> f56.rs:5:15 | 3 | fn main() { | - the call expression's return type is influenced by this return type 4 | let a = 0; 5 | ptr::read(&a) | --------- ^^ expected `*const ()`, found `&{integer}` | | | arguments to this function are incorrect | = note: expected raw pointer `*const ()` found reference `&{integer}` note: function defined here --> library/core/src/ptr/mod.rs:1681:21 | 1681 | pub const unsafe fn read(src: *const T) -> T { | ^^^^ ``` --- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 41 ++++++++++++++++++- .../expectation-from-return-type.rs | 21 ++++++++++ .../expectation-from-return-type.stderr | 35 ++++++++++++++++ ...ransforming-option-ref-issue-127545.stderr | 6 +++ ...call-return-type-due-to-generic-arg.stderr | 3 ++ 5 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 tests/ui/mismatched_types/expectation-from-return-type.rs create mode 100644 tests/ui/mismatched_types/expectation-from-return-type.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 9faa75e18480d..f53259e91eec1 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -11,7 +11,7 @@ use rustc_hir::attrs::DivergingBlockBehavior; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath, is_range_literal}; +use rustc_hir::{Expr, ExprKind, FnRetTy, HirId, LangItem, Node, QPath, is_range_literal}; use rustc_hir_analysis::check::potentially_plural_count; use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants}; use rustc_index::IndexVec; @@ -1587,6 +1587,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id))); + if let DefKind::Fn | DefKind::AssocFn = self.tcx.def_kind(def_id) + && let ty::Param(_) = + self.tcx.fn_sig(def_id).instantiate_identity().skip_binder().output().kind() + && let parent = self.tcx.hir_get_parent_item(call_expr.hir_id).def_id + && let Some((output, body_id)) = match self.tcx.hir_node_by_def_id(parent) { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Fn { sig, body, .. }, + .. + }) + | hir::Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body)), + .. + }) + | hir::Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(sig, body), + .. + }) => Some((sig.decl.output, body)), + _ => None, + } + && let expr = self.tcx.hir_body(*body_id).value + && (expr.peel_blocks().span == call_expr.span + || matches!( + self.tcx.parent_hir_node(call_expr.hir_id), + hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. }) + )) + { + err.span_label( + output.span(), + match output { + FnRetTy::DefaultReturn(_) => format!( + "this implicit `()` return type influences the call expression's return type" + ), + FnRetTy::Return(_) => { + "this return type influences the call expression's return type" + .to_string() + } + }, + ); + } } else if let Some(hir::Node::Expr(e)) = self.tcx.hir_get_if_local(def_id) && let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind { diff --git a/tests/ui/mismatched_types/expectation-from-return-type.rs b/tests/ui/mismatched_types/expectation-from-return-type.rs new file mode 100644 index 0000000000000..ffe3d929984df --- /dev/null +++ b/tests/ui/mismatched_types/expectation-from-return-type.rs @@ -0,0 +1,21 @@ +use std::ptr; + +fn main() { //~ NOTE: this implicit `()` return type influences the call expression's return type + let a = 0; + ptr::read(&a) + //~^ ERROR: mismatched types + //~| NOTE: expected `*const ()`, found `&{integer}` + //~| NOTE: arguments to this function are incorrect + //~| NOTE: expected raw pointer + //~| NOTE: function defined here +} + +fn foo() { //~ NOTE: this implicit `()` return type influences the call expression's return type + let a = 0; + return ptr::read(&a); + //~^ ERROR: mismatched types + //~| NOTE: expected `*const ()`, found `&{integer}` + //~| NOTE: arguments to this function are incorrect + //~| NOTE: expected raw pointer + //~| NOTE: function defined here +} diff --git a/tests/ui/mismatched_types/expectation-from-return-type.stderr b/tests/ui/mismatched_types/expectation-from-return-type.stderr new file mode 100644 index 0000000000000..3bd7a21f987fc --- /dev/null +++ b/tests/ui/mismatched_types/expectation-from-return-type.stderr @@ -0,0 +1,35 @@ +error[E0308]: mismatched types + --> $DIR/expectation-from-return-type.rs:5:15 + | +LL | fn main() { + | - this implicit `()` return type influences the call expression's return type +LL | let a = 0; +LL | ptr::read(&a) + | --------- ^^ expected `*const ()`, found `&{integer}` + | | + | arguments to this function are incorrect + | + = note: expected raw pointer `*const ()` + found reference `&{integer}` +note: function defined here + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + +error[E0308]: mismatched types + --> $DIR/expectation-from-return-type.rs:15:22 + | +LL | fn foo() { + | - this implicit `()` return type influences the call expression's return type +LL | let a = 0; +LL | return ptr::read(&a); + | --------- ^^ expected `*const ()`, found `&{integer}` + | | + | arguments to this function are incorrect + | + = note: expected raw pointer `*const ()` + found reference `&{integer}` +note: function defined here + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr index 9a18798db2139..6243a9a729a2f 100644 --- a/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr +++ b/tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr @@ -16,6 +16,8 @@ LL | arg.map(|v| &**v) error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:9:19 | +LL | pub fn bar(arg: Option<&Vec>) -> &[i32] { + | ------ this return type influences the call expression's return type LL | arg.unwrap_or(&[]) | --------- ^^^ expected `&Vec`, found `&[_; 0]` | | @@ -41,6 +43,8 @@ LL + arg.map_or(&[], |v| v) error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:13:19 | +LL | pub fn barzz<'a>(arg: Option<&'a Vec>, v: &'a [i32]) -> &'a [i32] { + | --------- this return type influences the call expression's return type LL | arg.unwrap_or(v) | --------- ^ expected `&Vec`, found `&[i32]` | | @@ -66,6 +70,8 @@ LL + arg.map_or(v, |v| v) error[E0308]: mismatched types --> $DIR/transforming-option-ref-issue-127545.rs:17:19 | +LL | pub fn convert_result(arg: Result<&Vec, ()>) -> &[i32] { + | ------ this return type influences the call expression's return type LL | arg.unwrap_or(&[]) | --------- ^^^ expected `&Vec`, found `&[_; 0]` | | diff --git a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr index 53920bc9e02ec..fd07d5b09aeb0 100644 --- a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr +++ b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr @@ -112,6 +112,9 @@ LL + let x: u16 = (S {}).method(0u16); error[E0308]: arguments to this function are incorrect --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5 | +LL | fn main() { + | - this implicit `()` return type influences the call expression's return type +... LL | function(0u32, 8u8) | ^^^^^^^^ ---- --- expected `bool`, found `u8` | |