about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs74
-rw-r--r--tests/ui/closures/issue-84128.stderr7
-rw-r--r--tests/ui/closures/issue-87461.stderr21
-rw-r--r--tests/ui/generic-associated-types/missing-bounds.stderr7
-rw-r--r--tests/ui/mismatched_types/issue-35030.stderr7
-rw-r--r--tests/ui/suggestions/args-instead-of-tuple-errors.stderr21
-rw-r--r--tests/ui/suggestions/sugg-else-for-closure.stderr7
-rw-r--r--tests/ui/traits/issue-52893.stderr7
-rw-r--r--tests/ui/type/wrong-call-return-type-due-to-generic-arg.rs28
-rw-r--r--tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr131
-rw-r--r--tests/ui/typeck/issue-46112.stderr7
-rw-r--r--tests/ui/typeck/issue-84768.stderr7
-rw-r--r--tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr14
13 files changed, 338 insertions, 0 deletions
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 6c128d0aa1a..665dc8b6a2f 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -85,6 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
         self.check_for_range_as_method_call(err, expr, expr_ty, expected);
         self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected);
+        self.check_wrong_return_type_due_to_generic_arg(err, expr, expr_ty);
     }
 
     /// Requires that the two types unify, and prints an error message if
@@ -1941,4 +1942,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             err.span_label(block.span, "this block is missing a tail expression");
         }
     }
+
+    fn check_wrong_return_type_due_to_generic_arg(
+        &self,
+        err: &mut Diagnostic,
+        expr: &hir::Expr<'_>,
+        checked_ty: Ty<'tcx>,
+    ) {
+        let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { return; };
+        enum CallableKind {
+            Function,
+            Method,
+            Constructor,
+        }
+        let mut maybe_emit_help = |def_id: hir::def_id::DefId,
+                                   callable: rustc_span::symbol::Ident,
+                                   args: &[hir::Expr<'_>],
+                                   kind: CallableKind| {
+            let arg_idx = args.iter().position(|a| a.hir_id == expr.hir_id).unwrap();
+            let fn_ty = self.tcx.bound_type_of(def_id).0;
+            if !fn_ty.is_fn() {
+                return;
+            }
+            let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder();
+            let Some(&arg) = fn_sig.inputs().get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 }) else { return; };
+            if matches!(arg.kind(), ty::Param(_))
+                && fn_sig.output().contains(arg)
+                && self.node_ty(args[arg_idx].hir_id) == checked_ty
+            {
+                let mut multi_span: MultiSpan = parent_expr.span.into();
+                multi_span.push_span_label(
+                    args[arg_idx].span,
+                    format!(
+                        "this argument influences the {} of `{}`",
+                        if matches!(kind, CallableKind::Constructor) {
+                            "type"
+                        } else {
+                            "return type"
+                        },
+                        callable
+                    ),
+                );
+                err.span_help(
+                    multi_span,
+                    format!(
+                        "the {} `{}` due to the type of the argument passed",
+                        match kind {
+                            CallableKind::Function => "return type of this call is",
+                            CallableKind::Method => "return type of this call is",
+                            CallableKind::Constructor => "type constructed contains",
+                        },
+                        checked_ty
+                    ),
+                );
+            }
+        };
+        match parent_expr.kind {
+            hir::ExprKind::Call(fun, args) => {
+                let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else { return; };
+                let hir::def::Res::Def(kind, def_id) = path.res else { return; };
+                let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) {
+                    CallableKind::Constructor
+                } else {
+                    CallableKind::Function
+                };
+                maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind);
+            }
+            hir::ExprKind::MethodCall(method, _receiver, args, _span) => {
+                let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id) else { return; };
+                maybe_emit_help(def_id, method.ident, args, CallableKind::Method)
+            }
+            _ => return,
+        }
+    }
 }
diff --git a/tests/ui/closures/issue-84128.stderr b/tests/ui/closures/issue-84128.stderr
index 59607afec8f..1cd8949b8c4 100644
--- a/tests/ui/closures/issue-84128.stderr
+++ b/tests/ui/closures/issue-84128.stderr
@@ -6,6 +6,13 @@ LL |         Foo(())
    |         |
    |         arguments to this struct are incorrect
    |
+help: the type constructed contains `()` due to the type of the argument passed
+  --> $DIR/issue-84128.rs:13:9
+   |
+LL |         Foo(())
+   |         ^^^^--^
+   |             |
+   |             this argument influences the type of `Foo`
 note: tuple struct defined here
   --> $DIR/issue-84128.rs:5:8
    |
diff --git a/tests/ui/closures/issue-87461.stderr b/tests/ui/closures/issue-87461.stderr
index 72337892734..b492251c016 100644
--- a/tests/ui/closures/issue-87461.stderr
+++ b/tests/ui/closures/issue-87461.stderr
@@ -6,6 +6,13 @@ LL |     Ok(())
    |     |
    |     arguments to this enum variant are incorrect
    |
+help: the type constructed contains `()` due to the type of the argument passed
+  --> $DIR/issue-87461.rs:10:5
+   |
+LL |     Ok(())
+   |     ^^^--^
+   |        |
+   |        this argument influences the type of `Ok`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
 
@@ -17,6 +24,13 @@ LL |     Ok(())
    |     |
    |     arguments to this enum variant are incorrect
    |
+help: the type constructed contains `()` due to the type of the argument passed
+  --> $DIR/issue-87461.rs:17:5
+   |
+LL |     Ok(())
+   |     ^^^--^
+   |        |
+   |        this argument influences the type of `Ok`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
 
@@ -28,6 +42,13 @@ LL |         Ok(())
    |         |
    |         arguments to this enum variant are incorrect
    |
+help: the type constructed contains `()` due to the type of the argument passed
+  --> $DIR/issue-87461.rs:26:9
+   |
+LL |         Ok(())
+   |         ^^^--^
+   |            |
+   |            this argument influences the type of `Ok`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
 
diff --git a/tests/ui/generic-associated-types/missing-bounds.stderr b/tests/ui/generic-associated-types/missing-bounds.stderr
index c913483a874..9f669b9a521 100644
--- a/tests/ui/generic-associated-types/missing-bounds.stderr
+++ b/tests/ui/generic-associated-types/missing-bounds.stderr
@@ -23,6 +23,13 @@ LL |         A(self.0 + rhs.0)
    |
    = note: expected type parameter `B`
              found associated type `<B as Add>::Output`
+help: the type constructed contains `<B as Add>::Output` due to the type of the argument passed
+  --> $DIR/missing-bounds.rs:11:9
+   |
+LL |         A(self.0 + rhs.0)
+   |         ^^--------------^
+   |           |
+   |           this argument influences the type of `A`
 note: tuple struct defined here
   --> $DIR/missing-bounds.rs:5:8
    |
diff --git a/tests/ui/mismatched_types/issue-35030.stderr b/tests/ui/mismatched_types/issue-35030.stderr
index 680aff1726f..de4e067fead 100644
--- a/tests/ui/mismatched_types/issue-35030.stderr
+++ b/tests/ui/mismatched_types/issue-35030.stderr
@@ -11,6 +11,13 @@ LL |         Some(true)
    |
    = note: expected type parameter `bool` (type parameter `bool`)
                         found type `bool` (`bool`)
+help: the type constructed contains `bool` due to the type of the argument passed
+  --> $DIR/issue-35030.rs:9:9
+   |
+LL |         Some(true)
+   |         ^^^^^----^
+   |              |
+   |              this argument influences the type of `Some`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
 
diff --git a/tests/ui/suggestions/args-instead-of-tuple-errors.stderr b/tests/ui/suggestions/args-instead-of-tuple-errors.stderr
index 44a39efdf25..bc097bf6eb4 100644
--- a/tests/ui/suggestions/args-instead-of-tuple-errors.stderr
+++ b/tests/ui/suggestions/args-instead-of-tuple-errors.stderr
@@ -11,6 +11,13 @@ LL |     let _: Option<(i32, bool)> = Some(1, 2);
    |                                       ^
    = note: expected tuple `(i32, bool)`
                found type `{integer}`
+help: the type constructed contains `{integer}` due to the type of the argument passed
+  --> $DIR/args-instead-of-tuple-errors.rs:6:34
+   |
+LL |     let _: Option<(i32, bool)> = Some(1, 2);
+   |                                  ^^^^^-^^^^
+   |                                       |
+   |                                       this argument influences the type of `Some`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
 help: remove the extra argument
@@ -64,6 +71,13 @@ LL |     let _: Option<(i32,)> = Some(5_usize);
    |
    = note: expected tuple `(i32,)`
                found type `usize`
+help: the type constructed contains `usize` due to the type of the argument passed
+  --> $DIR/args-instead-of-tuple-errors.rs:14:29
+   |
+LL |     let _: Option<(i32,)> = Some(5_usize);
+   |                             ^^^^^-------^
+   |                                  |
+   |                                  this argument influences the type of `Some`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
 
@@ -77,6 +91,13 @@ LL |     let _: Option<(i32,)> = Some((5_usize));
    |
    = note: expected tuple `(i32,)`
                found type `usize`
+help: the type constructed contains `usize` due to the type of the argument passed
+  --> $DIR/args-instead-of-tuple-errors.rs:17:29
+   |
+LL |     let _: Option<(i32,)> = Some((5_usize));
+   |                             ^^^^^---------^
+   |                                  |
+   |                                  this argument influences the type of `Some`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
 
diff --git a/tests/ui/suggestions/sugg-else-for-closure.stderr b/tests/ui/suggestions/sugg-else-for-closure.stderr
index 5f59d0f541c..7f05832bcd7 100644
--- a/tests/ui/suggestions/sugg-else-for-closure.stderr
+++ b/tests/ui/suggestions/sugg-else-for-closure.stderr
@@ -8,6 +8,13 @@ LL |     let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap());
    |
    = note: expected reference `&str`
                 found closure `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]`
+help: the return type of this call is `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]` due to the type of the argument passed
+  --> $DIR/sugg-else-for-closure.rs:6:14
+   |
+LL |     let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap());
+   |              ^^^^^^^^^^^^-------------------------------^
+   |                          |
+   |                          this argument influences the return type of `unwrap_or`
 note: associated function defined here
   --> $SRC_DIR/core/src/option.rs:LL:COL
 help: try calling `unwrap_or_else` instead
diff --git a/tests/ui/traits/issue-52893.stderr b/tests/ui/traits/issue-52893.stderr
index 7924d3db06f..a11867c03a6 100644
--- a/tests/ui/traits/issue-52893.stderr
+++ b/tests/ui/traits/issue-52893.stderr
@@ -11,6 +11,13 @@ LL |         builder.push(output);
    |
    = note: expected type parameter `F`
                       found struct `Class<P>`
+help: the return type of this call is `Class<P>` due to the type of the argument passed
+  --> $DIR/issue-52893.rs:53:9
+   |
+LL |         builder.push(output);
+   |         ^^^^^^^^^^^^^------^
+   |                      |
+   |                      this argument influences the return type of `push`
 note: associated function defined here
   --> $DIR/issue-52893.rs:11:8
    |
diff --git a/tests/ui/type/wrong-call-return-type-due-to-generic-arg.rs b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.rs
new file mode 100644
index 00000000000..ba5b9f54246
--- /dev/null
+++ b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.rs
@@ -0,0 +1,28 @@
+fn function<T>(x: T, y: bool) -> T {
+    x
+}
+
+struct S {}
+impl S {
+    fn method<T>(&self, x: T) -> T {
+        x
+    }
+}
+
+fn wrong_arg_type(x: u32) -> u32 {
+    x
+}
+
+fn main() {
+    // Should not trigger.
+    let x = wrong_arg_type(0u16); //~ ERROR mismatched types
+    let x: u16 = function(0, 0u8); //~ ERROR mismatched types
+
+    // Should trigger exactly once for the first argument.
+    let x: u16 = function(0u32, 0u8); //~ ERROR arguments to this function are incorrect
+
+    // Should trigger.
+    let x: u16 = function(0u32, true); //~ ERROR mismatched types
+    let x: u16 = (S {}).method(0u32); //~ ERROR mismatched types
+    function(0u32, 8u8) //~ ERROR arguments to this function are incorrect
+}
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
new file mode 100644
index 00000000000..4d012cb156b
--- /dev/null
+++ b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.stderr
@@ -0,0 +1,131 @@
+error[E0308]: mismatched types
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:18:28
+   |
+LL |     let x = wrong_arg_type(0u16);
+   |             -------------- ^^^^ expected `u32`, found `u16`
+   |             |
+   |             arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:12:4
+   |
+LL | fn wrong_arg_type(x: u32) -> u32 {
+   |    ^^^^^^^^^^^^^^ ------
+help: change the type of the numeric literal from `u16` to `u32`
+   |
+LL |     let x = wrong_arg_type(0u32);
+   |                             ~~~
+
+error[E0308]: mismatched types
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:19:30
+   |
+LL |     let x: u16 = function(0, 0u8);
+   |                  --------    ^^^ expected `bool`, found `u8`
+   |                  |
+   |                  arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+   |
+LL | fn function<T>(x: T, y: bool) -> T {
+   |    ^^^^^^^^          -------
+
+error[E0308]: arguments to this function are incorrect
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:22:18
+   |
+LL |     let x: u16 = function(0u32, 0u8);
+   |                  ^^^^^^^^ ----  --- expected `bool`, found `u8`
+   |                           |
+   |                           expected `u16`, found `u32`
+   |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:22:18
+   |
+LL |     let x: u16 = function(0u32, 0u8);
+   |                  ^^^^^^^^^----^^^^^^
+   |                           |
+   |                           this argument influences the return type of `function`
+note: function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+   |
+LL | fn function<T>(x: T, y: bool) -> T {
+   |    ^^^^^^^^    ----  -------
+help: change the type of the numeric literal from `u32` to `u16`
+   |
+LL |     let x: u16 = function(0u16, 0u8);
+   |                            ~~~
+
+error[E0308]: mismatched types
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:25:27
+   |
+LL |     let x: u16 = function(0u32, true);
+   |                  -------- ^^^^ expected `u16`, found `u32`
+   |                  |
+   |                  arguments to this function are incorrect
+   |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:25:18
+   |
+LL |     let x: u16 = function(0u32, true);
+   |                  ^^^^^^^^^----^^^^^^^
+   |                           |
+   |                           this argument influences the return type of `function`
+note: function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+   |
+LL | fn function<T>(x: T, y: bool) -> T {
+   |    ^^^^^^^^    ----
+help: change the type of the numeric literal from `u32` to `u16`
+   |
+LL |     let x: u16 = function(0u16, true);
+   |                            ~~~
+
+error[E0308]: mismatched types
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:26:32
+   |
+LL |     let x: u16 = (S {}).method(0u32);
+   |                         ------ ^^^^ expected `u16`, found `u32`
+   |                         |
+   |                         arguments to this method are incorrect
+   |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:26:18
+   |
+LL |     let x: u16 = (S {}).method(0u32);
+   |                  ^^^^^^^^^^^^^^----^
+   |                                |
+   |                                this argument influences the return type of `method`
+note: associated function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:7:8
+   |
+LL |     fn method<T>(&self, x: T) -> T {
+   |        ^^^^^^           ----
+help: change the type of the numeric literal from `u32` to `u16`
+   |
+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 |     function(0u32, 8u8)
+   |     ^^^^^^^^ ----  --- expected `bool`, found `u8`
+   |              |
+   |              expected `()`, found `u32`
+   |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:27:5
+   |
+LL |     function(0u32, 8u8)
+   |     ^^^^^^^^^----^^^^^^
+   |              |
+   |              this argument influences the return type of `function`
+note: function defined here
+  --> $DIR/wrong-call-return-type-due-to-generic-arg.rs:1:4
+   |
+LL | fn function<T>(x: T, y: bool) -> T {
+   |    ^^^^^^^^    ----  -------
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/issue-46112.stderr b/tests/ui/typeck/issue-46112.stderr
index f488463ae3c..8f5ff51fbe1 100644
--- a/tests/ui/typeck/issue-46112.stderr
+++ b/tests/ui/typeck/issue-46112.stderr
@@ -8,6 +8,13 @@ LL | fn main() { test(Ok(())); }
    |
    = note:   expected enum `Option<()>`
            found unit type `()`
+help: the type constructed contains `()` due to the type of the argument passed
+  --> $DIR/issue-46112.rs:9:18
+   |
+LL | fn main() { test(Ok(())); }
+   |                  ^^^--^
+   |                     |
+   |                     this argument influences the type of `Ok`
 note: tuple variant defined here
   --> $SRC_DIR/core/src/result.rs:LL:COL
 help: try wrapping the expression in `Some`
diff --git a/tests/ui/typeck/issue-84768.stderr b/tests/ui/typeck/issue-84768.stderr
index 00d23389720..09f3aee2d9e 100644
--- a/tests/ui/typeck/issue-84768.stderr
+++ b/tests/ui/typeck/issue-84768.stderr
@@ -14,6 +14,13 @@ LL |     <F as FnOnce(&mut u8)>::call_once(f, 1)
    |
    = note: expected tuple `(&mut u8,)`
                found type `{integer}`
+help: the return type of this call is `{integer}` due to the type of the argument passed
+  --> $DIR/issue-84768.rs:7:5
+   |
+LL |     <F as FnOnce(&mut u8)>::call_once(f, 1)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^
+   |                                          |
+   |                                          this argument influences the return type of `FnOnce`
 note: associated function defined here
   --> $SRC_DIR/core/src/ops/function.rs:LL:COL
 
diff --git a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr
index a2fe627868a..e85144a31ca 100644
--- a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr
+++ b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr
@@ -21,6 +21,13 @@ LL |     <i32 as Add<i32>>::add(1u32, 2);
    |     |
    |     arguments to this function are incorrect
    |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/ufcs-qpath-self-mismatch.rs:7:5
+   |
+LL |     <i32 as Add<i32>>::add(1u32, 2);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^----^^^^
+   |                            |
+   |                            this argument influences the return type of `Add`
 note: associated function defined here
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 help: change the type of the numeric literal from `u32` to `i32`
@@ -36,6 +43,13 @@ LL |     <i32 as Add<i32>>::add(1, 2u32);
    |     |
    |     arguments to this function are incorrect
    |
+help: the return type of this call is `u32` due to the type of the argument passed
+  --> $DIR/ufcs-qpath-self-mismatch.rs:9:5
+   |
+LL |     <i32 as Add<i32>>::add(1, 2u32);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^----^
+   |                               |
+   |                               this argument influences the return type of `Add`
 note: associated function defined here
   --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
 help: change the type of the numeric literal from `u32` to `i32`