From 94c300a4522f3386546ba77a21865bb78fe9bba8 Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sun, 7 Nov 2021 22:41:35 +0000 Subject: [PATCH 1/5] Suggest tuple-parentheses when passing N arguments to an N-tuple argument --- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 73 +++++++++++++++++-- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index c39199f84b527..5f3507846ba9b 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -28,6 +28,11 @@ use crate::structured_errors::StructuredDiagnostic; use std::iter; use std::slice; +enum FnArgsAsTuple<'hir> { + Single(&'hir hir::Expr<'hir>), + Multi { first: &'hir hir::Expr<'hir>, last: &'hir hir::Expr<'hir> }, +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(in super::super) fn check_casts(&self) { let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); @@ -127,8 +132,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expected_arg_count = formal_input_tys.len(); - // expected_count, arg_count, error_code, sugg_unit - let mut error: Option<(usize, usize, &str, bool)> = None; + // expected_count, arg_count, error_code, sugg_unit, sugg_tuple_wrap_args + let mut error: Option<(usize, usize, &str, bool, Option>)> = None; // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments { @@ -138,7 +143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Tuple(arg_types) => { // Argument length differs if arg_types.len() != provided_args.len() { - error = Some((arg_types.len(), provided_args.len(), "E0057", false)); + error = Some((arg_types.len(), provided_args.len(), "E0057", false, None)); } let expected_input_tys = match expected_input_tys.get(0) { Some(&ty) => match ty.kind() { @@ -169,7 +174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if supplied_arg_count >= expected_arg_count { (formal_input_tys.to_vec(), expected_input_tys) } else { - error = Some((expected_arg_count, supplied_arg_count, "E0060", false)); + error = Some((expected_arg_count, supplied_arg_count, "E0060", false, None)); (self.err_args(supplied_arg_count), vec![]) } } else { @@ -181,7 +186,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { false }; - error = Some((expected_arg_count, supplied_arg_count, "E0061", sugg_unit)); + + // 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 + // 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 + } + }); + + error = Some(( + expected_arg_count, + supplied_arg_count, + "E0061", + sugg_unit, + sugg_tuple_wrap_args, + )); (self.err_args(supplied_arg_count), vec![]) }; @@ -305,7 +346,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // If there was an error in parameter count, emit that here - if let Some((expected_count, arg_count, err_code, sugg_unit)) = error { + if let Some((expected_count, arg_count, err_code, sugg_unit, sugg_tuple_wrap_args)) = error + { let (span, start_span, args, ctor_of) = match &call_expr.kind { hir::ExprKind::Call( hir::Expr { @@ -408,6 +450,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { String::from("()"), Applicability::MachineApplicable, ); + } else if let Some(tuple_fn_arg) = sugg_tuple_wrap_args { + use FnArgsAsTuple::*; + + let spans = match tuple_fn_arg { + Multi { first, last } => vec![ + (first.span.shrink_to_lo(), '('.to_string()), + (last.span.shrink_to_hi(), ')'.to_string()), + ], + Single(single) => vec![ + (single.span.shrink_to_lo(), '('.to_string()), + (single.span.shrink_to_hi(), ",)".to_string()), + ], + }; + + err.multipart_suggestion( + "use parentheses to construct a tuple", + spans, + Applicability::MachineApplicable, + ); } else { err.span_label( span, From 80059f99424c64d10f073ab5c502856d46b1c26d Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Tue, 9 Nov 2021 23:20:26 +0000 Subject: [PATCH 2/5] Test tuple suggestions, including tuple-as-function-argument --- .../suggestions/args-instead-of-tuple.fixed | 18 +++++++ .../ui/suggestions/args-instead-of-tuple.rs | 18 +++++++ .../suggestions/args-instead-of-tuple.stderr | 52 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 src/test/ui/suggestions/args-instead-of-tuple.fixed create mode 100644 src/test/ui/suggestions/args-instead-of-tuple.rs create mode 100644 src/test/ui/suggestions/args-instead-of-tuple.stderr diff --git a/src/test/ui/suggestions/args-instead-of-tuple.fixed b/src/test/ui/suggestions/args-instead-of-tuple.fixed new file mode 100644 index 0000000000000..adb832b8a7b74 --- /dev/null +++ b/src/test/ui/suggestions/args-instead-of-tuple.fixed @@ -0,0 +1,18 @@ +// Test suggesting tuples where bare arguments may have been passed +// See issue #86481 for details. + +// run-rustfix + +fn main() { + let _: Result<(i32, i8), ()> = Ok((1, 2)); + //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied + let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi")); + //~^ ERROR this enum variant takes 1 argument but 3 arguments were supplied + let _: Option<()> = Some(()); + //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied + + f((1, 2)); //~ ERROR this function takes 1 argument +} + +fn f(_: (i32, i32)) { +} diff --git a/src/test/ui/suggestions/args-instead-of-tuple.rs b/src/test/ui/suggestions/args-instead-of-tuple.rs new file mode 100644 index 0000000000000..8dbc58daeb1f5 --- /dev/null +++ b/src/test/ui/suggestions/args-instead-of-tuple.rs @@ -0,0 +1,18 @@ +// Test suggesting tuples where bare arguments may have been passed +// See issue #86481 for details. + +// run-rustfix + +fn main() { + let _: Result<(i32, i8), ()> = Ok(1, 2); + //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied + let _: Option<(i32, i8, &'static str)> = Some(1, 2, "hi"); + //~^ ERROR this enum variant takes 1 argument but 3 arguments were supplied + let _: Option<()> = Some(); + //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied + + f(1, 2); //~ ERROR this function takes 1 argument +} + +fn f(_: (i32, i32)) { +} diff --git a/src/test/ui/suggestions/args-instead-of-tuple.stderr b/src/test/ui/suggestions/args-instead-of-tuple.stderr new file mode 100644 index 0000000000000..95bbbdb274964 --- /dev/null +++ b/src/test/ui/suggestions/args-instead-of-tuple.stderr @@ -0,0 +1,52 @@ +error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:7:36 + | +LL | let _: Result<(i32, i8), ()> = Ok(1, 2); + | ^^ - - supplied 2 arguments + | +help: use parentheses to construct a tuple + | +LL | let _: Result<(i32, i8), ()> = Ok((1, 2)); + | + + + +error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:9:46 + | +LL | let _: Option<(i32, i8, &'static str)> = Some(1, 2, "hi"); + | ^^^^ - - ---- supplied 3 arguments + | +help: use parentheses to construct a tuple + | +LL | let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi")); + | + + + +error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:11:25 + | +LL | let _: Option<()> = Some(); + | ^^^^-- supplied 0 arguments + | +help: expected the unit value `()`; create it with empty parentheses + | +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 + | +note: function defined here + --> $DIR/args-instead-of-tuple.rs:17:4 + | +LL | fn f(_: (i32, i32)) { + | ^ ------------- +help: use parentheses to construct a tuple + | +LL | f((1, 2)); + | + + + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0061`. From 54d2d30662c2832554bb127f017f7a311bb62b4e Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sun, 5 Dec 2021 21:41:33 +0000 Subject: [PATCH 3/5] Compare tuple element & arg types before suggesting a tuple --- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 53 +++++++++++-------- .../args-instead-of-tuple-errors.rs | 13 +++++ .../args-instead-of-tuple-errors.stderr | 25 +++++++++ .../suggestions/args-instead-of-tuple.fixed | 4 +- .../ui/suggestions/args-instead-of-tuple.rs | 4 +- .../suggestions/args-instead-of-tuple.stderr | 12 ++--- 6 files changed, 79 insertions(+), 32 deletions(-) create mode 100644 src/test/ui/suggestions/args-instead-of-tuple-errors.rs create mode 100644 src/test/ui/suggestions/args-instead-of-tuple-errors.stderr diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 5f3507846ba9b..a94e6b480d643 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -18,7 +18,7 @@ use rustc_hir::def_id::DefId; 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn suggested_tuple_wrap( + &self, + expected_input_tys: &[Ty<'tcx>], + provided_args: &'tcx [hir::Expr<'tcx>], + ) -> Option> { + 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, diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.rs b/src/test/ui/suggestions/args-instead-of-tuple-errors.rs new file mode 100644 index 0000000000000..c4e9c68e219e6 --- /dev/null +++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.rs @@ -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)) { +} diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr new file mode 100644 index 0000000000000..c53c8bbdcc9df --- /dev/null +++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr @@ -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`. diff --git a/src/test/ui/suggestions/args-instead-of-tuple.fixed b/src/test/ui/suggestions/args-instead-of-tuple.fixed index adb832b8a7b74..095be95f18586 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple.fixed +++ b/src/test/ui/suggestions/args-instead-of-tuple.fixed @@ -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)) { } diff --git a/src/test/ui/suggestions/args-instead-of-tuple.rs b/src/test/ui/suggestions/args-instead-of-tuple.rs index 8dbc58daeb1f5..3466a46df848e 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple.rs +++ b/src/test/ui/suggestions/args-instead-of-tuple.rs @@ -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)) { } diff --git a/src/test/ui/suggestions/args-instead-of-tuple.stderr b/src/test/ui/suggestions/args-instead-of-tuple.stderr index 95bbbdb274964..1bf7e7a8d171b 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple.stderr +++ b/src/test/ui/suggestions/args-instead-of-tuple.stderr @@ -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 From a129a85144efb67bfd8f380a758ed6be41d3e29b Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sun, 16 Jan 2022 21:47:44 +0000 Subject: [PATCH 4/5] Handle generics with ParamEnv --- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 4 +-- .../suggestions/args-instead-of-tuple.fixed | 9 +++++ .../ui/suggestions/args-instead-of-tuple.rs | 9 +++++ .../suggestions/args-instead-of-tuple.stderr | 36 +++++++++++++++++-- 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index a94e6b480d643..af0c9e5e5090e 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -18,7 +18,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::{ExprKind, Node, QPath}; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, ParamEnv, Ty}; +use rustc_middle::ty::{self, Ty}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::{self, MultiSpan, Span}; @@ -514,7 +514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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()); + .all(|(expected, supplied)| self.can_eq(self.param_env, expected, supplied).is_ok()); if all_match { match provided_args { diff --git a/src/test/ui/suggestions/args-instead-of-tuple.fixed b/src/test/ui/suggestions/args-instead-of-tuple.fixed index 095be95f18586..c9b8a41d469b9 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple.fixed +++ b/src/test/ui/suggestions/args-instead-of-tuple.fixed @@ -12,7 +12,16 @@ fn main() { //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied two_ints((1, 2)); //~ ERROR this function takes 1 argument + + with_generic((3, 4)); //~ ERROR this function takes 1 argument } fn two_ints(_: (i32, i32)) { } + +fn with_generic((a, b): (i32, T)) { + if false { + // test generics/bound handling + with_generic((a, b)); //~ ERROR this function takes 1 argument + } +} diff --git a/src/test/ui/suggestions/args-instead-of-tuple.rs b/src/test/ui/suggestions/args-instead-of-tuple.rs index 3466a46df848e..d4cc3024dd0d2 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple.rs +++ b/src/test/ui/suggestions/args-instead-of-tuple.rs @@ -12,7 +12,16 @@ fn main() { //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied two_ints(1, 2); //~ ERROR this function takes 1 argument + + with_generic(3, 4); //~ ERROR this function takes 1 argument } fn two_ints(_: (i32, i32)) { } + +fn with_generic((a, b): (i32, T)) { + if false { + // test generics/bound handling + with_generic(a, b); //~ ERROR this function takes 1 argument + } +} diff --git a/src/test/ui/suggestions/args-instead-of-tuple.stderr b/src/test/ui/suggestions/args-instead-of-tuple.stderr index 1bf7e7a8d171b..172db7ee3df38 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple.stderr +++ b/src/test/ui/suggestions/args-instead-of-tuple.stderr @@ -38,7 +38,7 @@ LL | two_ints(1, 2); | ^^^^^^^^ - - supplied 2 arguments | note: function defined here - --> $DIR/args-instead-of-tuple.rs:17:4 + --> $DIR/args-instead-of-tuple.rs:19:4 | LL | fn two_ints(_: (i32, i32)) { | ^^^^^^^^ ------------- @@ -47,6 +47,38 @@ help: use parentheses to construct a tuple LL | two_ints((1, 2)); | + + -error: aborting due to 4 previous errors +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:16:5 + | +LL | with_generic(3, 4); + | ^^^^^^^^^^^^ - - supplied 2 arguments + | +note: function defined here + --> $DIR/args-instead-of-tuple.rs:22:4 + | +LL | fn with_generic((a, b): (i32, T)) { + | ^^^^^^^^^^^^ ---------------- +help: use parentheses to construct a tuple + | +LL | with_generic((3, 4)); + | + + + +error[E0061]: this function takes 1 argument but 2 arguments were supplied + --> $DIR/args-instead-of-tuple.rs:25:9 + | +LL | with_generic(a, b); + | ^^^^^^^^^^^^ - - supplied 2 arguments + | +note: function defined here + --> $DIR/args-instead-of-tuple.rs:22:4 + | +LL | fn with_generic((a, b): (i32, T)) { + | ^^^^^^^^^^^^ ---------------- +help: use parentheses to construct a tuple + | +LL | with_generic((a, b)); + | + + + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0061`. From a8bac9879a36d01c1fc325ed85d6a992deab88fa Mon Sep 17 00:00:00 2001 From: Rob Pilling Date: Sun, 16 Jan 2022 22:47:33 +0000 Subject: [PATCH 5/5] Remove 1-tuple unreachable case --- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 30 +++++++------------ .../args-instead-of-tuple-errors.rs | 3 ++ .../args-instead-of-tuple-errors.stderr | 12 ++++++-- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index af0c9e5e5090e..d7022c27d3984 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -28,9 +28,9 @@ use crate::structured_errors::StructuredDiagnostic; use std::iter; use std::slice; -enum FnArgsAsTuple<'hir> { - Single(&'hir hir::Expr<'hir>), - Multi { first: &'hir hir::Expr<'hir>, last: &'hir hir::Expr<'hir> }, +struct FnArgsAsTuple<'hir> { + first: &'hir hir::Expr<'hir>, + last: &'hir hir::Expr<'hir>, } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -432,23 +432,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { String::from("()"), Applicability::MachineApplicable, ); - } else if let Some(tuple_fn_arg) = sugg_tuple_wrap_args { - use FnArgsAsTuple::*; - - let spans = match tuple_fn_arg { - Multi { first, last } => vec![ + } else if let Some(FnArgsAsTuple { first, last }) = sugg_tuple_wrap_args { + err.multipart_suggestion( + "use parentheses to construct a tuple", + vec![ (first.span.shrink_to_lo(), '('.to_string()), (last.span.shrink_to_hi(), ')'.to_string()), ], - Single(single) => vec![ - (single.span.shrink_to_lo(), '('.to_string()), - (single.span.shrink_to_hi(), ",)".to_string()), - ], - }; - - err.multipart_suggestion( - "use parentheses to construct a tuple", - spans, Applicability::MachineApplicable, ); } else { @@ -519,8 +509,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if all_match { match provided_args { [] => None, - [single] => Some(FnArgsAsTuple::Single(single)), - [first, .., last] => Some(FnArgsAsTuple::Multi { first, last }), + [_] => unreachable!( + "shouldn't reach here - need count mismatch between 1-tuple and 1-argument" + ), + [first, .., last] => Some(FnArgsAsTuple { first, last }), } } else { None diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.rs b/src/test/ui/suggestions/args-instead-of-tuple-errors.rs index c4e9c68e219e6..2c3ee5fcb8039 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple-errors.rs +++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.rs @@ -7,6 +7,9 @@ fn main() { //~^ 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 + + let _: Option<(i8,)> = Some(); + //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied } fn int_bool(_: (i32, bool)) { diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr index c53c8bbdcc9df..a2ad602dbd47a 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr +++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr @@ -15,11 +15,19 @@ LL | int_bool(1, 2); | expected 1 argument | note: function defined here - --> $DIR/args-instead-of-tuple-errors.rs:12:4 + --> $DIR/args-instead-of-tuple-errors.rs:15:4 | LL | fn int_bool(_: (i32, bool)) { | ^^^^^^^^ -------------- -error: aborting due to 2 previous errors +error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied + --> $DIR/args-instead-of-tuple-errors.rs:11:28 + | +LL | let _: Option<(i8,)> = Some(); + | ^^^^-- supplied 0 arguments + | | + | expected 1 argument + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0061`.