Skip to content

Commit

Permalink
Rollup merge of rust-lang#106752 - sulami:master, r=estebank
Browse files Browse the repository at this point in the history
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 rust-lang#43608.
  • Loading branch information
matthiaskrgr committed Jan 14, 2023
2 parents 3fbfd5f + a3cf382 commit d57dcfd
Show file tree
Hide file tree
Showing 13 changed files with 338 additions and 0 deletions.
74 changes: 74 additions & 0 deletions compiler/rustc_hir_typeck/src/demand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
}
}
}
7 changes: 7 additions & 0 deletions tests/ui/closures/issue-84128.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand Down
21 changes: 21 additions & 0 deletions tests/ui/closures/issue-87461.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

Expand All @@ -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

Expand Down
7 changes: 7 additions & 0 deletions tests/ui/generic-associated-types/missing-bounds.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand Down
7 changes: 7 additions & 0 deletions tests/ui/mismatched_types/issue-35030.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
21 changes: 21 additions & 0 deletions tests/ui/suggestions/args-instead-of-tuple-errors.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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

Expand Down
7 changes: 7 additions & 0 deletions tests/ui/suggestions/sugg-else-for-closure.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions tests/ui/traits/issue-52893.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand Down
28 changes: 28 additions & 0 deletions tests/ui/type/wrong-call-return-type-due-to-generic-arg.rs
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit d57dcfd

Please sign in to comment.