Skip to content

Commit 108b5f4

Browse files
authored
Rollup merge of #106752 - sulami:master, r=estebank
Emit a hint for bad call return types due to generic arguments When the return type of a function call depends on the type of an argument, e.g. ``` fn foo<T>(x: T) -> T { x } ``` and the expected type is set due to either an explicitly typed binding, or because the call to the function is in a tail position without semicolon, the current error implies that the argument in the call has the wrong type. This new hint highlights that the expected type doesn't match the returned type, which matches the argument type, and that that's why we're flagging the argument type. Fixes #43608.
2 parents 3fa9be9 + a3cf382 commit 108b5f4

13 files changed

+338
-0
lines changed

Diff for: compiler/rustc_hir_typeck/src/demand.rs

+74
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
8585
self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
8686
self.check_for_range_as_method_call(err, expr, expr_ty, expected);
8787
self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected);
88+
self.check_wrong_return_type_due_to_generic_arg(err, expr, expr_ty);
8889
}
8990

9091
/// Requires that the two types unify, and prints an error message if
@@ -1941,4 +1942,77 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19411942
err.span_label(block.span, "this block is missing a tail expression");
19421943
}
19431944
}
1945+
1946+
fn check_wrong_return_type_due_to_generic_arg(
1947+
&self,
1948+
err: &mut Diagnostic,
1949+
expr: &hir::Expr<'_>,
1950+
checked_ty: Ty<'tcx>,
1951+
) {
1952+
let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else { return; };
1953+
enum CallableKind {
1954+
Function,
1955+
Method,
1956+
Constructor,
1957+
}
1958+
let mut maybe_emit_help = |def_id: hir::def_id::DefId,
1959+
callable: rustc_span::symbol::Ident,
1960+
args: &[hir::Expr<'_>],
1961+
kind: CallableKind| {
1962+
let arg_idx = args.iter().position(|a| a.hir_id == expr.hir_id).unwrap();
1963+
let fn_ty = self.tcx.bound_type_of(def_id).0;
1964+
if !fn_ty.is_fn() {
1965+
return;
1966+
}
1967+
let fn_sig = fn_ty.fn_sig(self.tcx).skip_binder();
1968+
let Some(&arg) = fn_sig.inputs().get(arg_idx + if matches!(kind, CallableKind::Method) { 1 } else { 0 }) else { return; };
1969+
if matches!(arg.kind(), ty::Param(_))
1970+
&& fn_sig.output().contains(arg)
1971+
&& self.node_ty(args[arg_idx].hir_id) == checked_ty
1972+
{
1973+
let mut multi_span: MultiSpan = parent_expr.span.into();
1974+
multi_span.push_span_label(
1975+
args[arg_idx].span,
1976+
format!(
1977+
"this argument influences the {} of `{}`",
1978+
if matches!(kind, CallableKind::Constructor) {
1979+
"type"
1980+
} else {
1981+
"return type"
1982+
},
1983+
callable
1984+
),
1985+
);
1986+
err.span_help(
1987+
multi_span,
1988+
format!(
1989+
"the {} `{}` due to the type of the argument passed",
1990+
match kind {
1991+
CallableKind::Function => "return type of this call is",
1992+
CallableKind::Method => "return type of this call is",
1993+
CallableKind::Constructor => "type constructed contains",
1994+
},
1995+
checked_ty
1996+
),
1997+
);
1998+
}
1999+
};
2000+
match parent_expr.kind {
2001+
hir::ExprKind::Call(fun, args) => {
2002+
let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = fun.kind else { return; };
2003+
let hir::def::Res::Def(kind, def_id) = path.res else { return; };
2004+
let callable_kind = if matches!(kind, hir::def::DefKind::Ctor(_, _)) {
2005+
CallableKind::Constructor
2006+
} else {
2007+
CallableKind::Function
2008+
};
2009+
maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind);
2010+
}
2011+
hir::ExprKind::MethodCall(method, _receiver, args, _span) => {
2012+
let Some(def_id) = self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id) else { return; };
2013+
maybe_emit_help(def_id, method.ident, args, CallableKind::Method)
2014+
}
2015+
_ => return,
2016+
}
2017+
}
19442018
}

Diff for: tests/ui/closures/issue-84128.stderr

+7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ LL | Foo(())
66
| |
77
| arguments to this struct are incorrect
88
|
9+
help: the type constructed contains `()` due to the type of the argument passed
10+
--> $DIR/issue-84128.rs:13:9
11+
|
12+
LL | Foo(())
13+
| ^^^^--^
14+
| |
15+
| this argument influences the type of `Foo`
916
note: tuple struct defined here
1017
--> $DIR/issue-84128.rs:5:8
1118
|

Diff for: tests/ui/closures/issue-87461.stderr

+21
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ LL | Ok(())
66
| |
77
| arguments to this enum variant are incorrect
88
|
9+
help: the type constructed contains `()` due to the type of the argument passed
10+
--> $DIR/issue-87461.rs:10:5
11+
|
12+
LL | Ok(())
13+
| ^^^--^
14+
| |
15+
| this argument influences the type of `Ok`
916
note: tuple variant defined here
1017
--> $SRC_DIR/core/src/result.rs:LL:COL
1118

@@ -17,6 +24,13 @@ LL | Ok(())
1724
| |
1825
| arguments to this enum variant are incorrect
1926
|
27+
help: the type constructed contains `()` due to the type of the argument passed
28+
--> $DIR/issue-87461.rs:17:5
29+
|
30+
LL | Ok(())
31+
| ^^^--^
32+
| |
33+
| this argument influences the type of `Ok`
2034
note: tuple variant defined here
2135
--> $SRC_DIR/core/src/result.rs:LL:COL
2236

@@ -28,6 +42,13 @@ LL | Ok(())
2842
| |
2943
| arguments to this enum variant are incorrect
3044
|
45+
help: the type constructed contains `()` due to the type of the argument passed
46+
--> $DIR/issue-87461.rs:26:9
47+
|
48+
LL | Ok(())
49+
| ^^^--^
50+
| |
51+
| this argument influences the type of `Ok`
3152
note: tuple variant defined here
3253
--> $SRC_DIR/core/src/result.rs:LL:COL
3354

Diff for: tests/ui/generic-associated-types/missing-bounds.stderr

+7
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ LL | A(self.0 + rhs.0)
2323
|
2424
= note: expected type parameter `B`
2525
found associated type `<B as Add>::Output`
26+
help: the type constructed contains `<B as Add>::Output` due to the type of the argument passed
27+
--> $DIR/missing-bounds.rs:11:9
28+
|
29+
LL | A(self.0 + rhs.0)
30+
| ^^--------------^
31+
| |
32+
| this argument influences the type of `A`
2633
note: tuple struct defined here
2734
--> $DIR/missing-bounds.rs:5:8
2835
|

Diff for: tests/ui/mismatched_types/issue-35030.stderr

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ LL | Some(true)
1111
|
1212
= note: expected type parameter `bool` (type parameter `bool`)
1313
found type `bool` (`bool`)
14+
help: the type constructed contains `bool` due to the type of the argument passed
15+
--> $DIR/issue-35030.rs:9:9
16+
|
17+
LL | Some(true)
18+
| ^^^^^----^
19+
| |
20+
| this argument influences the type of `Some`
1421
note: tuple variant defined here
1522
--> $SRC_DIR/core/src/option.rs:LL:COL
1623

Diff for: tests/ui/suggestions/args-instead-of-tuple-errors.stderr

+21
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ LL | let _: Option<(i32, bool)> = Some(1, 2);
1111
| ^
1212
= note: expected tuple `(i32, bool)`
1313
found type `{integer}`
14+
help: the type constructed contains `{integer}` due to the type of the argument passed
15+
--> $DIR/args-instead-of-tuple-errors.rs:6:34
16+
|
17+
LL | let _: Option<(i32, bool)> = Some(1, 2);
18+
| ^^^^^-^^^^
19+
| |
20+
| this argument influences the type of `Some`
1421
note: tuple variant defined here
1522
--> $SRC_DIR/core/src/option.rs:LL:COL
1623
help: remove the extra argument
@@ -64,6 +71,13 @@ LL | let _: Option<(i32,)> = Some(5_usize);
6471
|
6572
= note: expected tuple `(i32,)`
6673
found type `usize`
74+
help: the type constructed contains `usize` due to the type of the argument passed
75+
--> $DIR/args-instead-of-tuple-errors.rs:14:29
76+
|
77+
LL | let _: Option<(i32,)> = Some(5_usize);
78+
| ^^^^^-------^
79+
| |
80+
| this argument influences the type of `Some`
6781
note: tuple variant defined here
6882
--> $SRC_DIR/core/src/option.rs:LL:COL
6983

@@ -77,6 +91,13 @@ LL | let _: Option<(i32,)> = Some((5_usize));
7791
|
7892
= note: expected tuple `(i32,)`
7993
found type `usize`
94+
help: the type constructed contains `usize` due to the type of the argument passed
95+
--> $DIR/args-instead-of-tuple-errors.rs:17:29
96+
|
97+
LL | let _: Option<(i32,)> = Some((5_usize));
98+
| ^^^^^---------^
99+
| |
100+
| this argument influences the type of `Some`
80101
note: tuple variant defined here
81102
--> $SRC_DIR/core/src/option.rs:LL:COL
82103

Diff for: tests/ui/suggestions/sugg-else-for-closure.stderr

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ LL | let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap());
88
|
99
= note: expected reference `&str`
1010
found closure `[closure@$DIR/sugg-else-for-closure.rs:6:26: 6:28]`
11+
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
12+
--> $DIR/sugg-else-for-closure.rs:6:14
13+
|
14+
LL | let _s = y.unwrap_or(|| x.split('.').nth(1).unwrap());
15+
| ^^^^^^^^^^^^-------------------------------^
16+
| |
17+
| this argument influences the return type of `unwrap_or`
1118
note: associated function defined here
1219
--> $SRC_DIR/core/src/option.rs:LL:COL
1320
help: try calling `unwrap_or_else` instead

Diff for: tests/ui/traits/issue-52893.stderr

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ LL | builder.push(output);
1111
|
1212
= note: expected type parameter `F`
1313
found struct `Class<P>`
14+
help: the return type of this call is `Class<P>` due to the type of the argument passed
15+
--> $DIR/issue-52893.rs:53:9
16+
|
17+
LL | builder.push(output);
18+
| ^^^^^^^^^^^^^------^
19+
| |
20+
| this argument influences the return type of `push`
1421
note: associated function defined here
1522
--> $DIR/issue-52893.rs:11:8
1623
|
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
fn function<T>(x: T, y: bool) -> T {
2+
x
3+
}
4+
5+
struct S {}
6+
impl S {
7+
fn method<T>(&self, x: T) -> T {
8+
x
9+
}
10+
}
11+
12+
fn wrong_arg_type(x: u32) -> u32 {
13+
x
14+
}
15+
16+
fn main() {
17+
// Should not trigger.
18+
let x = wrong_arg_type(0u16); //~ ERROR mismatched types
19+
let x: u16 = function(0, 0u8); //~ ERROR mismatched types
20+
21+
// Should trigger exactly once for the first argument.
22+
let x: u16 = function(0u32, 0u8); //~ ERROR arguments to this function are incorrect
23+
24+
// Should trigger.
25+
let x: u16 = function(0u32, true); //~ ERROR mismatched types
26+
let x: u16 = (S {}).method(0u32); //~ ERROR mismatched types
27+
function(0u32, 8u8) //~ ERROR arguments to this function are incorrect
28+
}

0 commit comments

Comments
 (0)