mirror of
https://github.com/rust-lang/rust
synced 2024-10-01 22:34:35 +00:00
Compare tuple element & arg types before suggesting a tuple
This commit is contained in:
parent
80059f9942
commit
54d2d30662
|
@ -18,7 +18,7 @@
|
|||
use rustc_hir::{ExprKind, Node, QPath};
|
||||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||
use rustc_middle::ty::fold::TypeFoldable;
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_middle::ty::{self, ParamEnv, Ty};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::{self, MultiSpan, Span};
|
||||
|
@ -188,33 +188,15 @@ pub(in super::super) fn check_argument_types(
|
|||
};
|
||||
|
||||
// are we passing elements of a tuple without the tuple parentheses?
|
||||
let chosen_arg_tys = if expected_input_tys.is_empty() {
|
||||
// In most cases we can use expected_arg_tys, but some callers won't have the type
|
||||
let expected_input_tys = if expected_input_tys.is_empty() {
|
||||
// In most cases we can use expected_input_tys, but some callers won't have the type
|
||||
// information, in which case we fall back to the types from the input expressions.
|
||||
formal_input_tys
|
||||
} else {
|
||||
&*expected_input_tys
|
||||
};
|
||||
|
||||
let sugg_tuple_wrap_args = chosen_arg_tys
|
||||
.get(0)
|
||||
.cloned()
|
||||
.map(|arg_ty| self.resolve_vars_if_possible(arg_ty))
|
||||
.and_then(|arg_ty| match arg_ty.kind() {
|
||||
ty::Tuple(tup_elems) => Some(tup_elems),
|
||||
_ => None,
|
||||
})
|
||||
.and_then(|tup_elems| {
|
||||
if tup_elems.len() == supplied_arg_count && chosen_arg_tys.len() == 1 {
|
||||
match provided_args {
|
||||
[] => None,
|
||||
[single] => Some(FnArgsAsTuple::Single(single)),
|
||||
[first, .., last] => Some(FnArgsAsTuple::Multi { first, last }),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let sugg_tuple_wrap_args = self.suggested_tuple_wrap(expected_input_tys, provided_args);
|
||||
|
||||
error = Some((
|
||||
expected_arg_count,
|
||||
|
@ -518,6 +500,33 @@ fn variadic_error<'tcx>(sess: &Session, span: Span, ty: Ty<'tcx>, cast_ty: &str)
|
|||
}
|
||||
}
|
||||
|
||||
fn suggested_tuple_wrap(
|
||||
&self,
|
||||
expected_input_tys: &[Ty<'tcx>],
|
||||
provided_args: &'tcx [hir::Expr<'tcx>],
|
||||
) -> Option<FnArgsAsTuple<'_>> {
|
||||
let [expected_arg_type] = &expected_input_tys[..] else { return None };
|
||||
|
||||
let ty::Tuple(expected_elems) = self.resolve_vars_if_possible(*expected_arg_type).kind()
|
||||
else { return None };
|
||||
|
||||
let expected_types: Vec<_> = expected_elems.iter().map(|k| k.expect_ty()).collect();
|
||||
let supplied_types: Vec<_> = provided_args.iter().map(|arg| self.check_expr(arg)).collect();
|
||||
|
||||
let all_match = iter::zip(expected_types, supplied_types)
|
||||
.all(|(expected, supplied)| self.can_eq(ParamEnv::empty(), expected, supplied).is_ok());
|
||||
|
||||
if all_match {
|
||||
match provided_args {
|
||||
[] => None,
|
||||
[single] => Some(FnArgsAsTuple::Single(single)),
|
||||
[first, .., last] => Some(FnArgsAsTuple::Multi { first, last }),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// AST fragment checking
|
||||
pub(in super::super) fn check_lit(
|
||||
&self,
|
||||
|
|
13
src/test/ui/suggestions/args-instead-of-tuple-errors.rs
Normal file
13
src/test/ui/suggestions/args-instead-of-tuple-errors.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Ensure we don't suggest tuple-wrapping when we'd end up with a type error
|
||||
|
||||
fn main() {
|
||||
// we shouldn't suggest to fix these - `2` isn't a `bool`
|
||||
|
||||
let _: Option<(i32, bool)> = Some(1, 2);
|
||||
//~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied
|
||||
int_bool(1, 2);
|
||||
//~^ ERROR this function takes 1 argument but 2 arguments were supplied
|
||||
}
|
||||
|
||||
fn int_bool(_: (i32, bool)) {
|
||||
}
|
25
src/test/ui/suggestions/args-instead-of-tuple-errors.stderr
Normal file
25
src/test/ui/suggestions/args-instead-of-tuple-errors.stderr
Normal file
|
@ -0,0 +1,25 @@
|
|||
error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied
|
||||
--> $DIR/args-instead-of-tuple-errors.rs:6:34
|
||||
|
|
||||
LL | let _: Option<(i32, bool)> = Some(1, 2);
|
||||
| ^^^^ - - supplied 2 arguments
|
||||
| |
|
||||
| expected 1 argument
|
||||
|
||||
error[E0061]: this function takes 1 argument but 2 arguments were supplied
|
||||
--> $DIR/args-instead-of-tuple-errors.rs:8:5
|
||||
|
|
||||
LL | int_bool(1, 2);
|
||||
| ^^^^^^^^ - - supplied 2 arguments
|
||||
| |
|
||||
| expected 1 argument
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/args-instead-of-tuple-errors.rs:12:4
|
||||
|
|
||||
LL | fn int_bool(_: (i32, bool)) {
|
||||
| ^^^^^^^^ --------------
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0061`.
|
|
@ -11,8 +11,8 @@ fn main() {
|
|||
let _: Option<()> = Some(());
|
||||
//~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
|
||||
|
||||
f((1, 2)); //~ ERROR this function takes 1 argument
|
||||
two_ints((1, 2)); //~ ERROR this function takes 1 argument
|
||||
}
|
||||
|
||||
fn f(_: (i32, i32)) {
|
||||
fn two_ints(_: (i32, i32)) {
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ fn main() {
|
|||
let _: Option<()> = Some();
|
||||
//~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
|
||||
|
||||
f(1, 2); //~ ERROR this function takes 1 argument
|
||||
two_ints(1, 2); //~ ERROR this function takes 1 argument
|
||||
}
|
||||
|
||||
fn f(_: (i32, i32)) {
|
||||
fn two_ints(_: (i32, i32)) {
|
||||
}
|
||||
|
|
|
@ -34,18 +34,18 @@ LL | let _: Option<()> = Some(());
|
|||
error[E0061]: this function takes 1 argument but 2 arguments were supplied
|
||||
--> $DIR/args-instead-of-tuple.rs:14:5
|
||||
|
|
||||
LL | f(1, 2);
|
||||
| ^ - - supplied 2 arguments
|
||||
LL | two_ints(1, 2);
|
||||
| ^^^^^^^^ - - supplied 2 arguments
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/args-instead-of-tuple.rs:17:4
|
||||
|
|
||||
LL | fn f(_: (i32, i32)) {
|
||||
| ^ -------------
|
||||
LL | fn two_ints(_: (i32, i32)) {
|
||||
| ^^^^^^^^ -------------
|
||||
help: use parentheses to construct a tuple
|
||||
|
|
||||
LL | f((1, 2));
|
||||
| + +
|
||||
LL | two_ints((1, 2));
|
||||
| + +
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
Loading…
Reference in a new issue