diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 6c128d0aa1a65..665dc8b6a2f2a 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 59607afec8f8d..1cd8949b8c4b7 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 72337892734e6..b492251c01691 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 c913483a8747c..9f669b9a5214b 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 `::Output` +help: the type constructed contains `::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 680aff1726f9f..de4e067fead4c 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 44a39efdf2542..bc097bf6eb451 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 5f59d0f541c99..7f05832bcd728 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 7924d3db06f36..a11867c03a689 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

` +help: the return type of this call is `Class

` 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 0000000000000..ba5b9f54246e2 --- /dev/null +++ b/tests/ui/type/wrong-call-return-type-due-to-generic-arg.rs @@ -0,0 +1,28 @@ +fn function(x: T, y: bool) -> T { + x +} + +struct S {} +impl S { + fn method(&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 0000000000000..4d012cb156bb5 --- /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(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(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(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(&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(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 f488463ae3ce9..8f5ff51fbe100 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 00d23389720b9..09f3aee2d9ec5 100644 --- a/tests/ui/typeck/issue-84768.stderr +++ b/tests/ui/typeck/issue-84768.stderr @@ -14,6 +14,13 @@ LL | ::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 | ::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 a2fe627868aeb..e85144a31ca96 100644 --- a/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/tests/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -21,6 +21,13 @@ LL | >::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 | >::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 | >::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 | >::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`