Repository: rust-lang/rust
Pull request: 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<T>(src: *const T) -> T {
     |                     ^^^^
```

Fix rust-lang/rust#43608.
<!-- homu-ignore:start -->
<!--
If this PR is related to an unstable feature or an otherwise tracked effort,
please link to the relevant tracking issue here. If you don't know of a related
tracking issue or there are none, feel free to ignore this.

This PR will get automatically assigned to a reviewer. In case you would like
a specific user to review your work, you can assign it to them by using

    r? <reviewer name>
-->
<!-- homu-ignore:end -->


Changed files:
filename: compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
patch: @@ -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
         {

filename: tests/ui/mismatched_types/expectation-from-return-type.rs
patch: @@ -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
+}

filename: tests/ui/mismatched_types/expectation-from-return-type.stderr
patch: @@ -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`.

filename: tests/ui/mismatched_types/transforming-option-ref-issue-127545.stderr
patch: @@ -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>>) -> &[i32] {
+   |                                       ------ this return type influences the call expression's return type
 LL |     arg.unwrap_or(&[])
    |         --------- ^^^ expected `&Vec<i32>`, 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<i32>>, v: &'a [i32]) -> &'a [i32] {
+   |                                                              --------- this return type influences the call expression's return type
 LL |     arg.unwrap_or(v)
    |         --------- ^ expected `&Vec<i32>`, 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>, ()>) -> &[i32] {
+   |                                                      ------ this return type influences the call expression's return type
 LL |     arg.unwrap_or(&[])
    |         --------- ^^^ expected `&Vec<i32>`, found `&[_; 0]`
    |         |

filename: tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr
patch: @@ -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`
    |              |