diff options
| author | Dylan DPC <99973273+Dylan-DPC@users.noreply.github.com> | 2022-06-29 10:28:19 +0530 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-06-29 10:28:19 +0530 |
| commit | dee9aed07d3e4d54d1d4c56474a9630e4cd3496f (patch) | |
| tree | d77cf95af955c9c46e46372ca70050f88b528b3e | |
| parent | 45740acd3451a574f4b67329f70e610145cd99cd (diff) | |
| parent | f2277e03eeb112730e3f07fab0d6b91d195fe55c (diff) | |
| download | rust-dee9aed07d3e4d54d1d4c56474a9630e4cd3496f.tar.gz rust-dee9aed07d3e4d54d1d4c56474a9630e4cd3496f.zip | |
Rollup merge of #97542 - compiler-errors:arg-mismatch, r=jackh726
Use typed indices in argument mismatch algorithm I kinda went overboard with the renames, but in general, "arg" is renamed to "expected", and "input" is renamed to "provided", and we use new typed indices to make sure we're indexing into the right sized array. Other drive-by changes: 1. Factor this logic into a new function, so we don't need to `break 'label` to escape it. 1. Factored out dependence on `final_arg_types`, which is never populated for arguments greater than the number of expected args. Instead, we just grab the final coerced expression type from `in_progress_typeck_results`. 1. Adjust the criteria we use to print (provided) type names, before we didn't suggest anything that had infer vars, but now we suggest thing that have infer vars but aren't `_`. ~Also, sorry in advance, I kinda want to backport this but I know I have folded in a lot of unnecessary drive-by changes that might discourage that. I would be open to brainstorming how to get some of these changes on beta at least.~ edit: Minimized the ICE-fixing changes to #97557 cc `@jackh726` as author of #92364, and `@estebank` as reviewer of the PR. fixes #97484
19 files changed, 759 insertions, 682 deletions
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs index b7ba9d97878..7602f2550e8 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/arg_matrix.rs @@ -1,7 +1,26 @@ use std::cmp; +use rustc_index::vec::IndexVec; use rustc_middle::ty::error::TypeError; +rustc_index::newtype_index! { + pub(crate) struct ExpectedIdx { + DEBUG_FORMAT = "ExpectedIdx({})", + } +} + +rustc_index::newtype_index! { + pub(crate) struct ProvidedIdx { + DEBUG_FORMAT = "ProvidedIdx({})", + } +} + +impl ExpectedIdx { + pub fn to_provided_idx(self) -> ProvidedIdx { + ProvidedIdx::from_usize(self.as_usize()) + } +} + // An issue that might be found in the compatibility matrix #[derive(Debug)] enum Issue { @@ -27,24 +46,24 @@ pub(crate) enum Compatibility<'tcx> { #[derive(Debug)] pub(crate) enum Error<'tcx> { /// The provided argument is the invalid type for the expected input - Invalid(usize, usize, Compatibility<'tcx>), // provided, expected + Invalid(ProvidedIdx, ExpectedIdx, Compatibility<'tcx>), /// There is a missing input - Missing(usize), + Missing(ExpectedIdx), /// There's a superfluous argument - Extra(usize), + Extra(ProvidedIdx), /// Two arguments should be swapped - Swap(usize, usize, usize, usize), + Swap(ProvidedIdx, ProvidedIdx, ExpectedIdx, ExpectedIdx), /// Several arguments should be reordered - Permutation(Vec<(usize, usize)>), // dest_arg, dest_input + Permutation(Vec<(ExpectedIdx, ProvidedIdx)>), } pub(crate) struct ArgMatrix<'tcx> { /// Maps the indices in the `compatibility_matrix` rows to the indices of /// the *user provided* inputs - input_indexes: Vec<usize>, + provided_indices: Vec<ProvidedIdx>, /// Maps the indices in the `compatibility_matrix` columns to the indices /// of the *expected* args - arg_indexes: Vec<usize>, + expected_indices: Vec<ExpectedIdx>, /// The first dimension (rows) are the remaining user provided inputs to /// match and the second dimension (cols) are the remaining expected args /// to match @@ -52,62 +71,64 @@ pub(crate) struct ArgMatrix<'tcx> { } impl<'tcx> ArgMatrix<'tcx> { - pub(crate) fn new<F: FnMut(usize, usize) -> Compatibility<'tcx>>( - minimum_input_count: usize, - provided_arg_count: usize, + pub(crate) fn new<F: FnMut(ProvidedIdx, ExpectedIdx) -> Compatibility<'tcx>>( + provided_count: usize, + expected_input_count: usize, mut is_compatible: F, ) -> Self { - let compatibility_matrix = (0..provided_arg_count) - .map(|i| (0..minimum_input_count).map(|j| is_compatible(i, j)).collect()) + let compatibility_matrix = (0..provided_count) + .map(|i| { + (0..expected_input_count) + .map(|j| is_compatible(ProvidedIdx::from_usize(i), ExpectedIdx::from_usize(j))) + .collect() + }) .collect(); ArgMatrix { - input_indexes: (0..provided_arg_count).collect(), - arg_indexes: (0..minimum_input_count).collect(), + provided_indices: (0..provided_count).map(ProvidedIdx::from_usize).collect(), + expected_indices: (0..expected_input_count).map(ExpectedIdx::from_usize).collect(), compatibility_matrix, } } /// Remove a given input from consideration - fn eliminate_input(&mut self, idx: usize) { - self.input_indexes.remove(idx); + fn eliminate_provided(&mut self, idx: usize) { + self.provided_indices.remove(idx); self.compatibility_matrix.remove(idx); } /// Remove a given argument from consideration - fn eliminate_arg(&mut self, idx: usize) { - self.arg_indexes.remove(idx); + fn eliminate_expected(&mut self, idx: usize) { + self.expected_indices.remove(idx); for row in &mut self.compatibility_matrix { row.remove(idx); } } /// "satisfy" an input with a given arg, removing both from consideration - fn satisfy_input(&mut self, input_idx: usize, arg_idx: usize) { - self.eliminate_input(input_idx); - self.eliminate_arg(arg_idx); + fn satisfy_input(&mut self, provided_idx: usize, expected_idx: usize) { + self.eliminate_provided(provided_idx); + self.eliminate_expected(expected_idx); } // Returns a `Vec` of (user input, expected arg) of matched arguments. These // are inputs on the remaining diagonal that match. - fn eliminate_satisfied(&mut self) -> Vec<(usize, usize)> { - let mut i = cmp::min(self.input_indexes.len(), self.arg_indexes.len()); + fn eliminate_satisfied(&mut self) -> Vec<(ProvidedIdx, ExpectedIdx)> { + let num_args = cmp::min(self.provided_indices.len(), self.expected_indices.len()); let mut eliminated = vec![]; - while i > 0 { - let idx = i - 1; - if matches!(self.compatibility_matrix[idx][idx], Compatibility::Compatible) { - eliminated.push((self.input_indexes[idx], self.arg_indexes[idx])); - self.satisfy_input(idx, idx); + for i in (0..num_args).rev() { + if matches!(self.compatibility_matrix[i][i], Compatibility::Compatible) { + eliminated.push((self.provided_indices[i], self.expected_indices[i])); + self.satisfy_input(i, i); } - i -= 1; } - return eliminated; + eliminated } // Find some issue in the compatibility matrix fn find_issue(&self) -> Option<Issue> { let mat = &self.compatibility_matrix; - let ai = &self.arg_indexes; - let ii = &self.input_indexes; + let ai = &self.expected_indices; + let ii = &self.provided_indices; for i in 0..cmp::max(ai.len(), ii.len()) { // If we eliminate the last row, any left-over inputs are considered missing @@ -264,12 +285,15 @@ impl<'tcx> ArgMatrix<'tcx> { // // We'll want to know which arguments and inputs these rows and columns correspond to // even after we delete them. - pub(crate) fn find_errors(mut self) -> (Vec<Error<'tcx>>, Vec<Option<usize>>) { - let provided_arg_count = self.input_indexes.len(); + pub(crate) fn find_errors( + mut self, + ) -> (Vec<Error<'tcx>>, IndexVec<ExpectedIdx, Option<ProvidedIdx>>) { + let provided_arg_count = self.provided_indices.len(); let mut errors: Vec<Error<'tcx>> = vec![]; // For each expected argument, the matched *actual* input - let mut matched_inputs: Vec<Option<usize>> = vec![None; self.arg_indexes.len()]; + let mut matched_inputs: IndexVec<ExpectedIdx, Option<ProvidedIdx>> = + IndexVec::from_elem_n(None, self.expected_indices.len()); // Before we start looking for issues, eliminate any arguments that are already satisfied, // so that an argument which is already spoken for by the input it's in doesn't @@ -280,34 +304,34 @@ impl<'tcx> ArgMatrix<'tcx> { // Without this elimination, the first argument causes the second argument // to show up as both a missing input and extra argument, rather than // just an invalid type. - for (inp, arg) in self.eliminate_satisfied() { - matched_inputs[arg] = Some(inp); + for (provided, expected) in self.eliminate_satisfied() { + matched_inputs[expected] = Some(provided); } - while self.input_indexes.len() > 0 || self.arg_indexes.len() > 0 { + while !self.provided_indices.is_empty() || !self.expected_indices.is_empty() { match self.find_issue() { Some(Issue::Invalid(idx)) => { let compatibility = self.compatibility_matrix[idx][idx].clone(); - let input_idx = self.input_indexes[idx]; - let arg_idx = self.arg_indexes[idx]; + let input_idx = self.provided_indices[idx]; + let arg_idx = self.expected_indices[idx]; self.satisfy_input(idx, idx); errors.push(Error::Invalid(input_idx, arg_idx, compatibility)); } Some(Issue::Extra(idx)) => { - let input_idx = self.input_indexes[idx]; - self.eliminate_input(idx); + let input_idx = self.provided_indices[idx]; + self.eliminate_provided(idx); errors.push(Error::Extra(input_idx)); } Some(Issue::Missing(idx)) => { - let arg_idx = self.arg_indexes[idx]; - self.eliminate_arg(idx); + let arg_idx = self.expected_indices[idx]; + self.eliminate_expected(idx); errors.push(Error::Missing(arg_idx)); } Some(Issue::Swap(idx, other)) => { - let input_idx = self.input_indexes[idx]; - let other_input_idx = self.input_indexes[other]; - let arg_idx = self.arg_indexes[idx]; - let other_arg_idx = self.arg_indexes[other]; + let input_idx = self.provided_indices[idx]; + let other_input_idx = self.provided_indices[other]; + let arg_idx = self.expected_indices[idx]; + let other_arg_idx = self.expected_indices[other]; let (min, max) = (cmp::min(idx, other), cmp::max(idx, other)); self.satisfy_input(min, max); // Subtract 1 because we already removed the "min" row @@ -319,13 +343,14 @@ impl<'tcx> ArgMatrix<'tcx> { Some(Issue::Permutation(args)) => { let mut idxs: Vec<usize> = args.iter().filter_map(|&a| a).collect(); - let mut real_idxs = vec![None; provided_arg_count]; + let mut real_idxs: IndexVec<ProvidedIdx, Option<(ExpectedIdx, ProvidedIdx)>> = + IndexVec::from_elem_n(None, provided_arg_count); for (src, dst) in args.iter().enumerate().filter_map(|(src, dst)| dst.map(|dst| (src, dst))) { - let src_input_idx = self.input_indexes[src]; - let dst_input_idx = self.input_indexes[dst]; - let dest_arg_idx = self.arg_indexes[dst]; + let src_input_idx = self.provided_indices[src]; + let dst_input_idx = self.provided_indices[dst]; + let dest_arg_idx = self.expected_indices[dst]; real_idxs[src_input_idx] = Some((dest_arg_idx, dst_input_idx)); matched_inputs[dest_arg_idx] = Some(src_input_idx); } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 2326c4069e4..08df01c0c1a 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1,6 +1,8 @@ use crate::astconv::AstConv; use crate::check::coercion::CoerceMany; -use crate::check::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error}; +use crate::check::fn_ctxt::arg_matrix::{ + ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx, +}; use crate::check::gather_locals::Declaration; use crate::check::method::MethodCallee; use crate::check::Expectation::*; @@ -17,13 +19,14 @@ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ExprKind, Node, QPath}; +use rustc_index::vec::IndexVec; use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt}; use rustc_infer::infer::InferOk; use rustc_infer::infer::TypeTrace; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::{self, Span}; @@ -214,6 +217,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let provided_arg_count = provided_args.len(); // We'll also want to keep track of the fully coerced argument types, for an awkward hack near the end + // FIXME(compiler-errors): Get rid of this, actually. let mut final_arg_types: Vec<Option<(Ty<'_>, Ty<'_>)>> = vec![None; provided_arg_count]; // We introduce a helper function to demand that a given argument satisfy a given input @@ -287,54 +291,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - // A "softer" version of the helper above, which checks types without persisting them, - // and treats error types differently - // This will allow us to "probe" for other argument orders that would likely have been correct - let check_compatible = |input_idx, arg_idx| { - let formal_input_ty: Ty<'tcx> = formal_input_tys[arg_idx]; - let expected_input_ty: Ty<'tcx> = expected_input_tys[arg_idx]; - - // If either is an error type, we defy the usual convention and consider them to *not* be - // coercible. This prevents our error message heuristic from trying to pass errors into - // every argument. - if formal_input_ty.references_error() || expected_input_ty.references_error() { - return Compatibility::Incompatible(None); - } - - let provided_arg: &hir::Expr<'tcx> = &provided_args[input_idx]; - let expectation = Expectation::rvalue_hint(self, expected_input_ty); - // FIXME: check that this is safe; I don't believe this commits any of the obligations, but I can't be sure. - // - // I had another method of "soft" type checking before, - // but it was failing to find the type of some expressions (like "") - // so I prodded this method and made it pub(super) so I could call it, and it seems to work well. - let checked_ty = self.check_expr_kind(provided_arg, expectation); - - let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); - let can_coerce = self.can_coerce(checked_ty, coerced_ty); - - if !can_coerce { - return Compatibility::Incompatible(None); - } - - let subtyping_result = self - .at(&self.misc(provided_arg.span), self.param_env) - .sup(formal_input_ty, coerced_ty); - - // Same as above: if either the coerce type or the checked type is an error type, - // consider them *not* compatible. - let coercible = - !coerced_ty.references_error() && !checked_ty.references_error() && can_coerce; - - match (coercible, &subtyping_result) { - (true, Ok(_)) => Compatibility::Compatible, - _ => Compatibility::Incompatible(subtyping_result.err()), - } - }; - // To start, we only care "along the diagonal", where we expect every // provided arg to be in the right spot - let mut compatibility = vec![Compatibility::Incompatible(None); provided_args.len()]; + let mut compatibility_diagonal = + vec![Compatibility::Incompatible(None); provided_args.len()]; // Keep track of whether we *could possibly* be satisfied, i.e. whether we're on the happy path // if the wrong number of arguments were supplied, we CAN'T be satisfied, @@ -394,7 +354,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let compatible = demand_compatible(idx, &mut final_arg_types); let is_compatible = matches!(compatible, Compatibility::Compatible); - compatibility[idx] = compatible; + compatibility_diagonal[idx] = compatible; if !is_compatible { call_appears_satisfied = false; @@ -402,70 +362,54 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - // Logic here is a bit hairy - 'errors: { - // If something above didn't typecheck, we've fallen off the happy path - // and we should make some effort to provide better error messages - if call_appears_satisfied { - break 'errors; - } - - self.set_tainted_by_errors(); + if c_variadic && provided_arg_count < minimum_input_count { + err_code = "E0060"; + } - // The algorithm here is inspired by levenshtein distance and longest common subsequence. - // We'll try to detect 4 different types of mistakes: - // - An extra parameter has been provided that doesn't satisfy *any* of the other inputs - // - An input is missing, which isn't satisfied by *any* of the other arguments - // - Some number of arguments have been provided in the wrong order - // - A type is straight up invalid + for arg in provided_args.iter().skip(minimum_input_count) { + // Make sure we've checked this expr at least once. + let arg_ty = self.check_expr(&arg); - // First, let's find the errors - let mut compatibility: Vec<_> = compatibility.into_iter().map(Some).collect(); - let (mut errors, matched_inputs) = - ArgMatrix::new(minimum_input_count, provided_arg_count, |i, j| { - if i == j { compatibility[i].take().unwrap() } else { check_compatible(i, j) } - }) - .find_errors(); + // If the function is c-style variadic, we skipped a bunch of arguments + // so we need to check those, and write out the types + // Ideally this would be folded into the above, for uniform style + // but c-variadic is already a corner case + if c_variadic { + fn variadic_error<'tcx>( + sess: &'tcx Session, + span: Span, + ty: Ty<'tcx>, + cast_ty: &str, + ) { + use crate::structured_errors::MissingCastForVariadicArg; - // Okay, so here's where it gets complicated in regards to what errors - // we emit and how. - // There are 3 different "types" of errors we might encounter. - // 1) Missing/extra/swapped arguments - // 2) Valid but incorrect arguments - // 3) Invalid arguments - // - Currently I think this only comes up with `CyclicTy` - // - // We first need to go through, remove those from (3) and emit those - // as their own error, particularly since they're error code and - // message is special. From what I can tell, we *must* emit these - // here (vs somewhere prior to this function) since the arguments - // become invalid *because* of how they get used in the function. - // It is what it is. - - let found_errors = !errors.is_empty(); - - errors.drain_filter(|error| { - let Error::Invalid(input_idx, arg_idx, Compatibility::Incompatible(Some(e))) = error else { return false }; - let expected_ty = expected_input_tys[*arg_idx]; - let provided_ty = final_arg_types[*input_idx].map(|ty| ty.0).unwrap_or_else(|| tcx.ty_error()); - let cause = &self.misc(provided_args[*input_idx].span); - let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); - if !matches!(trace.cause.as_failure_code(e), FailureCode::Error0308(_)) { - self.report_and_explain_type_error(trace, e).emit(); - return true; + MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit(); } - false - }); - // We're done if we found errors, but we already emitted them. - // I don't think we *should* be able to enter this bit of code - // (`!call_appears_satisfied`) without *also* finding errors, but we - // don't want to accidentally not emit an error if there is some - // logic bug in the `ArgMatrix` code. - if found_errors && errors.is_empty() { - break 'errors; + // There are a few types which get autopromoted when passed via varargs + // in C but we just error out instead and require explicit casts. + let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); + match arg_ty.kind() { + ty::Float(ty::FloatTy::F32) => { + variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); + } + ty::Int(ty::IntTy::I8 | ty::IntTy::I16) | ty::Bool => { + variadic_error(tcx.sess, arg.span, arg_ty, "c_int"); + } + ty::Uint(ty::UintTy::U8 | ty::UintTy::U16) => { + variadic_error(tcx.sess, arg.span, arg_ty, "c_uint"); + } + ty::FnDef(..) => { + let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); + let ptr_ty = self.resolve_vars_if_possible(ptr_ty); + variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); + } + _ => {} + } } + } + if !call_appears_satisfied { // Next, let's construct the error let (error_span, full_call_span, ctor_of) = match &call_expr.kind { hir::ExprKind::Call( @@ -500,524 +444,633 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(CtorOf::Variant) => "enum variant", None => "function", }; - if c_variadic && provided_arg_count < minimum_input_count { - err_code = "E0060"; - } - // Next special case: The case where we expect a single tuple and - // wrapping all the args in parentheses (or adding a comma to - // already existing parentheses) will result in a tuple that - // satisfies the call. - // This isn't super ideal code, because we copy code from elsewhere - // and somewhat duplicate this. We also delegate to the general type - // mismatch suggestions for the single arg case. - let sugg_tuple_wrap_args = - self.suggested_tuple_wrap(&expected_input_tys, provided_args); - match sugg_tuple_wrap_args { - TupleMatchFound::None => {} - TupleMatchFound::Single => { - let expected_ty = expected_input_tys[0]; - let provided_ty = final_arg_types[0].map(|ty| ty.0).unwrap(); - let expected_ty = self.resolve_vars_if_possible(expected_ty); - let provided_ty = self.resolve_vars_if_possible(provided_ty); - let cause = &self.misc(provided_args[0].span); - let compatibility = demand_compatible(0, &mut final_arg_types); - let type_error = match compatibility { - Compatibility::Incompatible(Some(error)) => error, - _ => TypeError::Mismatch, - }; - let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); - let mut err = self.report_and_explain_type_error(trace, &type_error); - self.emit_coerce_suggestions( - &mut err, - &provided_args[0], - final_arg_types[0].map(|ty| ty.0).unwrap(), - final_arg_types[0].map(|ty| ty.1).unwrap(), - None, - None, - ); - err.span_label( - full_call_span, - format!("arguments to this {} are incorrect", call_name), - ); - // Call out where the function is defined - label_fn_like(tcx, &mut err, fn_def_id); - err.emit(); - break 'errors; - } - TupleMatchFound::Multiple(start, end) => { - let mut err = tcx.sess.struct_span_err_with_code( - full_call_span, - &format!( - "this {} takes {}{} but {} {} supplied", - call_name, - if c_variadic { "at least " } else { "" }, - potentially_plural_count(minimum_input_count, "argument"), - potentially_plural_count(provided_arg_count, "argument"), - if provided_arg_count == 1 { "was" } else { "were" } - ), - DiagnosticId::Error(err_code.to_owned()), - ); - // Call out where the function is defined - label_fn_like(tcx, &mut err, fn_def_id); - err.multipart_suggestion( - "use parentheses to construct a tuple", - vec![(start, '('.to_string()), (end, ')'.to_string())], - Applicability::MachineApplicable, - ); - err.emit(); - break 'errors; + let try_tuple_wrap_args = || { + // The case where we expect a single tuple and wrapping all the args + // in parentheses (or adding a comma to already existing parentheses) + // will result in a tuple that satisfies the call. + // This isn't super ideal code, because we copy code from elsewhere + // and somewhat duplicate this. We also delegate to the general type + // mismatch suggestions for the single arg case. + match self.suggested_tuple_wrap(&expected_input_tys, provided_args) { + TupleMatchFound::Single => { + let expected_ty = expected_input_tys[0]; + let provided_ty = final_arg_types[0].map(|ty| ty.0).unwrap(); + let expected_ty = self.resolve_vars_if_possible(expected_ty); + let provided_ty = self.resolve_vars_if_possible(provided_ty); + let cause = &self.misc(provided_args[0].span); + let compatibility = demand_compatible(0, &mut final_arg_types); + let type_error = match compatibility { + Compatibility::Incompatible(Some(error)) => error, + _ => TypeError::Mismatch, + }; + let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); + let mut err = self.report_and_explain_type_error(trace, &type_error); + self.emit_coerce_suggestions( + &mut err, + &provided_args[0], + final_arg_types[0].map(|ty| ty.0).unwrap(), + final_arg_types[0].map(|ty| ty.1).unwrap(), + None, + None, + ); + err.span_label( + full_call_span, + format!("arguments to this {} are incorrect", call_name), + ); + // Call out where the function is defined + label_fn_like(tcx, &mut err, fn_def_id); + err.emit(); + return true; + } + TupleMatchFound::Multiple(start, end) => { + let mut err = tcx.sess.struct_span_err_with_code( + full_call_span, + &format!( + "this {} takes {}{} but {} {} supplied", + call_name, + if c_variadic { "at least " } else { "" }, + potentially_plural_count(minimum_input_count, "argument"), + potentially_plural_count(provided_arg_count, "argument"), + if provided_arg_count == 1 { "was" } else { "were" } + ), + DiagnosticId::Error(err_code.to_owned()), + ); + // Call out where the function is defined + label_fn_like(tcx, &mut err, fn_def_id); + err.multipart_suggestion( + "use parentheses to construct a tuple", + vec![(start, '('.to_string()), (end, ')'.to_string())], + Applicability::MachineApplicable, + ); + err.emit(); + return true; + } + TupleMatchFound::None => {} } + false + }; + + let compatibility_diagonal = IndexVec::from_raw(compatibility_diagonal); + let provided_args = IndexVec::from_iter(provided_args.iter().take(if c_variadic { + minimum_input_count + } else { + provided_arg_count + })); + debug_assert_eq!( + formal_input_tys.len(), + expected_input_tys.len(), + "expected formal_input_tys to be the same size as expected_input_tys" + ); + let formal_and_expected_inputs = IndexVec::from_iter( + formal_input_tys + .iter() + .copied() + .zip(expected_input_tys.iter().copied()) + .map(|vars| self.resolve_vars_if_possible(vars)), + ); + + self.report_arg_errors( + compatibility_diagonal, + formal_and_expected_inputs, + provided_args, + full_call_span, + error_span, + args_span, + call_name, + c_variadic, + err_code, + fn_def_id, + try_tuple_wrap_args, + ); + } + } + + fn report_arg_errors( + &self, + compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>, + formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, + provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>, + full_call_span: Span, + error_span: Span, + args_span: Span, + call_name: &str, + c_variadic: bool, + err_code: &str, + fn_def_id: Option<DefId>, + try_tuple_wrap_args: impl FnOnce() -> bool, + ) { + // Don't print if it has error types or is just plain `_` + fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool { + tys.into_iter().any(|ty| ty.references_error() || ty.is_ty_var()) + } + + self.set_tainted_by_errors(); + let tcx = self.tcx; + + // A "softer" version of the `demand_compatible`, which checks types without persisting them, + // and treats error types differently + // This will allow us to "probe" for other argument orders that would likely have been correct + let check_compatible = |provided_idx: ProvidedIdx, expected_idx: ExpectedIdx| { + if provided_idx.as_usize() == expected_idx.as_usize() { + return compatibility_diagonal[provided_idx].clone(); + } + + let (formal_input_ty, expected_input_ty) = formal_and_expected_inputs[expected_idx]; + // If either is an error type, we defy the usual convention and consider them to *not* be + // coercible. This prevents our error message heuristic from trying to pass errors into + // every argument. + if (formal_input_ty, expected_input_ty).references_error() { + return Compatibility::Incompatible(None); + } + + let provided_arg: &hir::Expr<'tcx> = &provided_args[provided_idx]; + let expectation = Expectation::rvalue_hint(self, expected_input_ty); + // FIXME: check that this is safe; I don't believe this commits any of the obligations, but I can't be sure. + // + // I had another method of "soft" type checking before, + // but it was failing to find the type of some expressions (like "") + // so I prodded this method and made it pub(super) so I could call it, and it seems to work well. + let checked_ty = self.check_expr_kind(provided_arg, expectation); + + let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); + let can_coerce = self.can_coerce(checked_ty, coerced_ty); + if !can_coerce { + return Compatibility::Incompatible(None); + } + + let subtyping_result = self + .at(&self.misc(provided_arg.span), self.param_env) + .sup(formal_input_ty, coerced_ty); + + // Same as above: if either the coerce type or the checked type is an error type, + // consider them *not* compatible. + let references_error = (coerced_ty, checked_ty).references_error(); + match (references_error, &subtyping_result) { + (false, Ok(_)) => Compatibility::Compatible, + _ => Compatibility::Incompatible(subtyping_result.err()), } + }; + + // The algorithm here is inspired by levenshtein distance and longest common subsequence. + // We'll try to detect 4 different types of mistakes: + // - An extra parameter has been provided that doesn't satisfy *any* of the other inputs + // - An input is missing, which isn't satisfied by *any* of the other arguments + // - Some number of arguments have been provided in the wrong order + // - A type is straight up invalid + + // First, let's find the errors + let (mut errors, matched_inputs) = + ArgMatrix::new(provided_args.len(), formal_and_expected_inputs.len(), check_compatible) + .find_errors(); + + // Precompute the provided types and spans, since that's all we typically need for below + let provided_arg_tys: IndexVec<ProvidedIdx, (Ty<'tcx>, Span)> = provided_args + .iter() + .map(|expr| { + let ty = self + .in_progress_typeck_results + .as_ref() + .unwrap() + .borrow() + .expr_ty_adjusted_opt(*expr) + .unwrap_or_else(|| tcx.ty_error()); + (self.resolve_vars_if_possible(ty), expr.span) + }) + .collect(); + + // Okay, so here's where it gets complicated in regards to what errors + // we emit and how. + // There are 3 different "types" of errors we might encounter. + // 1) Missing/extra/swapped arguments + // 2) Valid but incorrect arguments + // 3) Invalid arguments + // - Currently I think this only comes up with `CyclicTy` + // + // We first need to go through, remove those from (3) and emit those + // as their own error, particularly since they're error code and + // message is special. From what I can tell, we *must* emit these + // here (vs somewhere prior to this function) since the arguments + // become invalid *because* of how they get used in the function. + // It is what it is. + + if errors.is_empty() { + if cfg!(debug_assertions) { + span_bug!(error_span, "expected errors from argument matrix"); + } else { + tcx.sess + .struct_span_err( + error_span, + "argument type mismatch was detected, \ + but rustc had trouble determining where", + ) + .note( + "we would appreciate a bug report: \ + https://github.com/rust-lang/rust-clippy/issues/new", + ) + .emit(); + } + return; + } + + errors.drain_filter(|error| { + let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(error)) = error else { return false }; + let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; + let (expected_ty, _) = formal_and_expected_inputs[*expected_idx]; + let cause = &self.misc(provided_span); + let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); + if let Some(e) = error { + if !matches!(trace.cause.as_failure_code(e), FailureCode::Error0308(_)) { + self.report_and_explain_type_error(trace, e).emit(); + return true; + } + } + false + }); + + // We're done if we found errors, but we already emitted them. + if errors.is_empty() { + return; + } + + // Okay, now that we've emitted the special errors separately, we + // are only left missing/extra/swapped and mismatched arguments, both + // can be collated pretty easily if needed. + + // Next special case: if there is only one "Incompatible" error, just emit that + if let [ + Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(err))), + ] = &errors[..] + { + let (formal_ty, expected_ty) = formal_and_expected_inputs[*expected_idx]; + let (provided_ty, provided_arg_span) = provided_arg_tys[*provided_idx]; + let cause = &self.misc(provided_arg_span); + let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); + let mut err = self.report_and_explain_type_error(trace, err); + self.emit_coerce_suggestions( + &mut err, + &provided_args[*provided_idx], + provided_ty, + Expectation::rvalue_hint(self, expected_ty) + .only_has_type(self) + .unwrap_or(formal_ty), + None, + None, + ); + err.span_label( + full_call_span, + format!("arguments to this {} are incorrect", call_name), + ); + // Call out where the function is defined + label_fn_like(tcx, &mut err, fn_def_id); + err.emit(); + return; + } + + // Second, let's try tuple wrapping the args. + // FIXME(compiler-errors): This is currently in its own closure because + // I didn't want to factor it out. + if try_tuple_wrap_args() { + return; + } + + let mut err = if formal_and_expected_inputs.len() == provided_args.len() { + struct_span_err!( + tcx.sess, + full_call_span, + E0308, + "arguments to this {} are incorrect", + call_name, + ) + } else { + tcx.sess.struct_span_err_with_code( + full_call_span, + &format!( + "this {} takes {}{} but {} {} supplied", + call_name, + if c_variadic { "at least " } else { "" }, + potentially_plural_count(formal_and_expected_inputs.len(), "argument"), + potentially_plural_count(provided_args.len(), "argument"), + if provided_args.len() == 1 { "was" } else { "were" } + ), + DiagnosticId::Error(err_code.to_owned()), + ) + }; + + // As we encounter issues, keep track of what we want to provide for the suggestion + let mut labels = vec![]; + // If there is a single error, we give a specific suggestion; otherwise, we change to + // "did you mean" with the suggested function call + enum SuggestionText { + None, + Provide(bool), + Remove(bool), + Swap, + Reorder, + DidYouMean, + } + let mut suggestion_text = SuggestionText::None; + + let mut errors = errors.into_iter().peekable(); + while let Some(error) = errors.next() { + match error { + Error::Invalid(provided_idx, expected_idx, compatibility) => { + let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx]; + let (provided_ty, provided_span) = provided_arg_tys[provided_idx]; + if let Compatibility::Incompatible(error) = &compatibility { + let cause = &self.misc(provided_span); + let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); + if let Some(e) = error { + self.note_type_err( + &mut err, + &trace.cause, + None, + Some(trace.values), + e, + false, + true, + ); + } + } - // Okay, now that we've emitted the special errors separately, we - // are only left missing/extra/swapped and mismatched arguments, both - // can be collated pretty easily if needed. - - // Next special case: if there is only one "Incompatible" error, just emit that - if errors.len() == 1 { - if let Some(Error::Invalid( - input_idx, - arg_idx, - Compatibility::Incompatible(Some(error)), - )) = errors.iter().next() - { - let expected_ty = expected_input_tys[*arg_idx]; - let provided_ty = final_arg_types[*input_idx] - .map(|ty| ty.0) - .unwrap_or_else(|| tcx.ty_error()); - let expected_ty = self.resolve_vars_if_possible(expected_ty); - let provided_ty = self.resolve_vars_if_possible(provided_ty); - let cause = &self.misc(provided_args[*input_idx].span); - let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); - let mut err = self.report_and_explain_type_error(trace, error); self.emit_coerce_suggestions( &mut err, - &provided_args[*input_idx], + &provided_args[provided_idx], provided_ty, - final_arg_types[*input_idx] - .map(|ty| ty.1) - .unwrap_or_else(|| tcx.ty_error()), + Expectation::rvalue_hint(self, expected_ty) + .only_has_type(self) + .unwrap_or(formal_ty), None, None, ); - err.span_label( - full_call_span, - format!("arguments to this {} are incorrect", call_name), - ); - // Call out where the function is defined - label_fn_like(tcx, &mut err, fn_def_id); - err.emit(); - break 'errors; } - } - - let mut err = if minimum_input_count == provided_arg_count { - struct_span_err!( - tcx.sess, - full_call_span, - E0308, - "arguments to this {} are incorrect", - call_name, - ) - } else { - tcx.sess.struct_span_err_with_code( - full_call_span, - &format!( - "this {} takes {}{} but {} {} supplied", - call_name, - if c_variadic { "at least " } else { "" }, - potentially_plural_count(minimum_input_count, "argument"), - potentially_plural_count(provided_arg_count, "argument"), - if provided_arg_count == 1 { "was" } else { "were" } - ), - DiagnosticId::Error(err_code.to_owned()), - ) - }; - - // As we encounter issues, keep track of what we want to provide for the suggestion - let mut labels = vec![]; - // If there is a single error, we give a specific suggestion; otherwise, we change to - // "did you mean" with the suggested function call - enum SuggestionText { - None, - Provide(bool), - Remove(bool), - Swap, - Reorder, - DidYouMean, - } - let mut suggestion_text = SuggestionText::None; - - let mut errors = errors.into_iter().peekable(); - while let Some(error) = errors.next() { - match error { - Error::Invalid(input_idx, arg_idx, compatibility) => { - let expected_ty = expected_input_tys[arg_idx]; - let provided_ty = final_arg_types[input_idx] - .map(|ty| ty.0) - .unwrap_or_else(|| tcx.ty_error()); - let expected_ty = self.resolve_vars_if_possible(expected_ty); - let provided_ty = self.resolve_vars_if_possible(provided_ty); - if let Compatibility::Incompatible(error) = &compatibility { - let cause = &self.misc(provided_args[input_idx].span); - let trace = TypeTrace::types(cause, true, expected_ty, provided_ty); - if let Some(e) = error { - self.note_type_err( - &mut err, - &trace.cause, - None, - Some(trace.values), - e, - false, - true, - ); - } + Error::Extra(arg_idx) => { + let (provided_ty, provided_span) = provided_arg_tys[arg_idx]; + let provided_ty_name = if !has_error_or_infer([provided_ty]) { + // FIXME: not suggestable, use something else + format!(" of type `{}`", provided_ty) + } else { + "".to_string() + }; + labels + .push((provided_span, format!("argument{} unexpected", provided_ty_name))); + suggestion_text = match suggestion_text { + SuggestionText::None => SuggestionText::Remove(false), + SuggestionText::Remove(_) => SuggestionText::Remove(true), + _ => SuggestionText::DidYouMean, + }; + } + Error::Missing(expected_idx) => { + // If there are multiple missing arguments adjacent to each other, + // then we can provide a single error. + + let mut missing_idxs = vec![expected_idx]; + while let Some(e) = errors.next_if(|e| { + matches!(e, Error::Missing(next_expected_idx) + if *next_expected_idx == *missing_idxs.last().unwrap() + 1) + }) { + match e { + Error::Missing(expected_idx) => missing_idxs.push(expected_idx), + _ => unreachable!(), } - - self.emit_coerce_suggestions( - &mut err, - &provided_args[input_idx], - provided_ty, - // FIXME(compiler-errors): expected_ty? - final_arg_types[input_idx] - .map(|ty| ty.1) - .unwrap_or_else(|| tcx.ty_error()), - None, - None, - ); } - Error::Extra(arg_idx) => { - let arg_type = if let Some((_, ty)) = final_arg_types[arg_idx] { - if ty.references_error() || ty.has_infer_types() { - "".into() + + // NOTE: Because we might be re-arranging arguments, might have extra + // arguments, etc. it's hard to *really* know where we should provide + // this error label, so as a heuristic, we point to the provided arg, or + // to the call if the missing inputs pass the provided args. + match &missing_idxs[..] { + &[expected_idx] => { + let (_, input_ty) = formal_and_expected_inputs[expected_idx]; + let span = if let Some((_, arg_span)) = + provided_arg_tys.get(expected_idx.to_provided_idx()) + { + *arg_span } else { - format!(" of type `{}`", ty) - } - } else { - "".into() - }; - labels.push(( - provided_args[arg_idx].span, - format!("argument{} unexpected", arg_type), - )); - suggestion_text = match suggestion_text { - SuggestionText::None => SuggestionText::Remove(false), - SuggestionText::Remove(_) => SuggestionText::Remove(true), - _ => SuggestionText::DidYouMean, - }; - } - Error::Missing(input_idx) => { - // If there are multiple missing arguments adjacent to each other, - // then we can provide a single error. - - let mut missing_idxs = vec![input_idx]; - while let Some(e) = errors.next_if(|e| matches!(e, Error::Missing(input_idx) if *input_idx == (missing_idxs.last().unwrap() + 1))) { - match e { - Error::Missing(input_idx) => missing_idxs.push(input_idx), - _ => unreachable!(), - } + args_span + }; + let rendered = if !has_error_or_infer([input_ty]) { + format!(" of type `{}`", input_ty) + } else { + "".to_string() + }; + labels.push((span, format!("an argument{} is missing", rendered))); + suggestion_text = match suggestion_text { + SuggestionText::None => SuggestionText::Provide(false), + SuggestionText::Provide(_) => SuggestionText::Provide(true), + _ => SuggestionText::DidYouMean, + }; } - - // NOTE: Because we might be re-arranging arguments, might have extra - // arguments, etc. it's hard to *really* know where we should provide - // this error label, so as a heuristic, we point to the provided arg, or - // to the call if the missing inputs pass the provided args. - match &missing_idxs[..] { - &[input_idx] => { - let expected_ty = expected_input_tys[input_idx]; - let input_ty = self.resolve_vars_if_possible(expected_ty); - let span = if input_idx < provided_arg_count { - let arg_span = provided_args[input_idx].span; - Span::new(arg_span.lo(), arg_span.hi(), arg_span.ctxt(), None) - } else { - args_span - }; - let arg_type = - if input_ty.references_error() || input_ty.has_infer_types() { - "".into() - } else { - format!(" of type `{}`", input_ty) - }; - labels.push((span, format!("an argument{} is missing", arg_type))); - suggestion_text = match suggestion_text { - SuggestionText::None => SuggestionText::Provide(false), - SuggestionText::Provide(_) => SuggestionText::Provide(true), - _ => SuggestionText::DidYouMean, - }; - } - &[first_idx, second_idx] => { - let first_input_ty = - self.resolve_vars_if_possible(expected_input_tys[first_idx]); - let second_input_ty = - self.resolve_vars_if_possible(expected_input_tys[second_idx]); - - let span = if second_idx < provided_arg_count { - let first_arg_span = provided_args[first_idx].span; - let second_arg_span = provided_args[second_idx].span; - Span::new( - first_arg_span.lo(), - second_arg_span.hi(), - first_arg_span.ctxt(), - None, - ) - } else { - args_span - }; - let any_unnameable = false - || first_input_ty.references_error() - || first_input_ty.has_infer_types() - || second_input_ty.references_error() - || second_input_ty.has_infer_types(); - let arg_type = if any_unnameable { - "".into() - } else { + &[first_idx, second_idx] => { + let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; + let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; + let span = if let (Some((_, first_span)), Some((_, second_span))) = ( + provided_arg_tys.get(first_idx.to_provided_idx()), + provided_arg_tys.get(second_idx.to_provided_idx()), + ) { + first_span.to(*second_span) + } else { + args_span + }; + let rendered = + if !has_error_or_infer([first_expected_ty, second_expected_ty]) { format!( " of type `{}` and `{}`", - first_input_ty, second_input_ty - ) - }; - labels - .push((span, format!("two arguments{} are missing", arg_type))); - suggestion_text = match suggestion_text { - SuggestionText::None | SuggestionText::Provide(_) => { - SuggestionText::Provide(true) - } - _ => SuggestionText::DidYouMean, - }; - } - &[first_idx, second_idx, third_idx] => { - let first_input_ty = - self.resolve_vars_if_possible(expected_input_tys[first_idx]); - let second_input_ty = - self.resolve_vars_if_possible(expected_input_tys[second_idx]); - let third_input_ty = - self.resolve_vars_if_possible(expected_input_tys[third_idx]); - let span = if third_idx < provided_arg_count { - let first_arg_span = provided_args[first_idx].span; - let third_arg_span = provided_args[third_idx].span; - Span::new( - first_arg_span.lo(), - third_arg_span.hi(), - first_arg_span.ctxt(), - None, - ) - } else { - args_span - }; - let any_unnameable = false - || first_input_ty.references_error() - || first_input_ty.has_infer_types() - || second_input_ty.references_error() - || second_input_ty.has_infer_types() - || third_input_ty.references_error() - || third_input_ty.has_infer_types(); - let arg_type = if any_unnameable { - "".into() - } else { - format!( - " of type `{}`, `{}`, and `{}`", - first_input_ty, second_input_ty, third_input_ty - ) - }; - labels.push(( - span, - format!("three arguments{} are missing", arg_type), - )); - suggestion_text = match suggestion_text { - SuggestionText::None | SuggestionText::Provide(_) => { - SuggestionText::Provide(true) - } - _ => SuggestionText::DidYouMean, - }; - } - missing_idxs => { - let first_idx = *missing_idxs.first().unwrap(); - let last_idx = *missing_idxs.last().unwrap(); - // NOTE: Because we might be re-arranging arguments, might have extra arguments, etc. - // It's hard to *really* know where we should provide this error label, so this is a - // decent heuristic - let span = if last_idx < provided_arg_count { - let first_arg_span = provided_args[first_idx].span; - let last_arg_span = provided_args[last_idx].span; - Span::new( - first_arg_span.lo(), - last_arg_span.hi(), - first_arg_span.ctxt(), - None, + first_expected_ty, second_expected_ty ) } else { - // Otherwise just label the whole function - args_span - }; - labels.push((span, format!("multiple arguments are missing"))); - suggestion_text = match suggestion_text { - SuggestionText::None | SuggestionText::Provide(_) => { - SuggestionText::Provide(true) - } - _ => SuggestionText::DidYouMean, + "".to_string() }; - } + labels.push((span, format!("two arguments{} are missing", rendered))); + suggestion_text = match suggestion_text { + SuggestionText::None | SuggestionText::Provide(_) => { + SuggestionText::Provide(true) + } + _ => SuggestionText::DidYouMean, + }; } - } - Error::Swap(input_idx, other_input_idx, arg_idx, other_arg_idx) => { - let first_span = provided_args[input_idx].span; - let second_span = provided_args[other_input_idx].span; - - let first_expected_ty = - self.resolve_vars_if_possible(expected_input_tys[arg_idx]); - let first_provided_ty = if let Some((ty, _)) = final_arg_types[input_idx] { - format!(", found `{}`", ty) - } else { - String::new() - }; - labels.push(( - first_span, - format!("expected `{}`{}", first_expected_ty, first_provided_ty), - )); - let other_expected_ty = - self.resolve_vars_if_possible(expected_input_tys[other_arg_idx]); - let other_provided_ty = - if let Some((ty, _)) = final_arg_types[other_input_idx] { - format!(", found `{}`", ty) + &[first_idx, second_idx, third_idx] => { + let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; + let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; + let (_, third_expected_ty) = formal_and_expected_inputs[third_idx]; + let span = if let (Some((_, first_span)), Some((_, third_span))) = ( + provided_arg_tys.get(first_idx.to_provided_idx()), + provided_arg_tys.get(third_idx.to_provided_idx()), + ) { + first_span.to(*third_span) } else { - String::new() + args_span }; - labels.push(( - second_span, - format!("expected `{}`{}", other_expected_ty, other_provided_ty), - )); - suggestion_text = match suggestion_text { - SuggestionText::None => SuggestionText::Swap, - _ => SuggestionText::DidYouMean, - }; - } - Error::Permutation(args) => { - for (dst_arg, dest_input) in args { - let expected_ty = - self.resolve_vars_if_possible(expected_input_tys[dst_arg]); - let provided_ty = if let Some((ty, _)) = final_arg_types[dest_input] { - format!(", found `{}`", ty) + let rendered = if !has_error_or_infer([ + first_expected_ty, + second_expected_ty, + third_expected_ty, + ]) { + format!( + " of type `{}`, `{}`, and `{}`", + first_expected_ty, second_expected_ty, third_expected_ty + ) } else { - String::new() + "".to_string() + }; + labels.push((span, format!("three arguments{} are missing", rendered))); + suggestion_text = match suggestion_text { + SuggestionText::None | SuggestionText::Provide(_) => { + SuggestionText::Provide(true) + } + _ => SuggestionText::DidYouMean, + }; + } + missing_idxs => { + let first_idx = *missing_idxs.first().unwrap(); + let last_idx = *missing_idxs.last().unwrap(); + // NOTE: Because we might be re-arranging arguments, might have extra arguments, etc. + // It's hard to *really* know where we should provide this error label, so this is a + // decent heuristic + let span = if let (Some((_, first_span)), Some((_, last_span))) = ( + provided_arg_tys.get(first_idx.to_provided_idx()), + provided_arg_tys.get(last_idx.to_provided_idx()), + ) { + first_span.to(*last_span) + } else { + args_span + }; + labels.push((span, format!("multiple arguments are missing"))); + suggestion_text = match suggestion_text { + SuggestionText::None | SuggestionText::Provide(_) => { + SuggestionText::Provide(true) + } + _ => SuggestionText::DidYouMean, }; - labels.push(( - provided_args[dest_input].span, - format!("expected `{}`{}", expected_ty, provided_ty), - )); } - - suggestion_text = match suggestion_text { - SuggestionText::None => SuggestionText::Reorder, - _ => SuggestionText::DidYouMean, - }; } } - } - - // If we have less than 5 things to say, it would be useful to call out exactly what's wrong - if labels.len() <= 5 { - for (span, label) in labels { - err.span_label(span, label); - } - } - - // Call out where the function is defined - label_fn_like(tcx, &mut err, fn_def_id); - - // And add a suggestion block for all of the parameters - let suggestion_text = match suggestion_text { - SuggestionText::None => None, - SuggestionText::Provide(plural) => { - Some(format!("provide the argument{}", if plural { "s" } else { "" })) - } - SuggestionText::Remove(plural) => { - Some(format!("remove the extra argument{}", if plural { "s" } else { "" })) - } - SuggestionText::Swap => Some("swap these arguments".to_string()), - SuggestionText::Reorder => Some("reorder these arguments".to_string()), - SuggestionText::DidYouMean => Some("did you mean".to_string()), - }; - if let Some(suggestion_text) = suggestion_text { - let source_map = self.sess().source_map(); - let mut suggestion = format!( - "{}(", - source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| String::new()) - ); - for (arg_index, input_idx) in matched_inputs.iter().enumerate() { - let suggestion_text = if let Some(input_idx) = input_idx { - let arg_span = provided_args[*input_idx].span.source_callsite(); - let arg_text = source_map.span_to_snippet(arg_span).unwrap(); - arg_text + Error::Swap( + first_provided_idx, + second_provided_idx, + first_expected_idx, + second_expected_idx, + ) => { + let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx]; + let (_, first_expected_ty) = formal_and_expected_inputs[first_expected_idx]; + let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) { + format!(", found `{}`", first_provided_ty) } else { - // Propose a placeholder of the correct type - let expected_ty = expected_input_tys[arg_index]; - let input_ty = self.resolve_vars_if_possible(expected_ty); - if input_ty.is_unit() { - "()".to_string() - } else if !input_ty.is_ty_var() { - format!("/* {} */", input_ty) + String::new() + }; + labels.push(( + first_span, + format!("expected `{}`{}", first_expected_ty, first_provided_ty_name), + )); + + let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx]; + let (_, second_expected_ty) = formal_and_expected_inputs[second_expected_idx]; + let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) { + format!(", found `{}`", second_provided_ty) + } else { + String::new() + }; + labels.push(( + second_span, + format!("expected `{}`{}", second_expected_ty, second_provided_ty_name), + )); + + suggestion_text = match suggestion_text { + SuggestionText::None => SuggestionText::Swap, + _ => SuggestionText::DidYouMean, + }; + } + Error::Permutation(args) => { + for (dst_arg, dest_input) in args { + let (_, expected_ty) = formal_and_expected_inputs[dst_arg]; + let (provided_ty, provided_span) = provided_arg_tys[dest_input]; + let provided_ty_name = if !has_error_or_infer([provided_ty]) { + format!(", found `{}`", provided_ty) } else { - "/* value */".to_string() + String::new() + }; + // FIXME(compiler-errors): Why do we get permutations with the same type? + if expected_ty != provided_ty { + labels.push(( + provided_span, + format!("expected `{}`{}", expected_ty, provided_ty_name), + )); } - }; - suggestion += &suggestion_text; - if arg_index < minimum_input_count - 1 { - suggestion += ", "; } + + suggestion_text = match suggestion_text { + SuggestionText::None => SuggestionText::Reorder, + _ => SuggestionText::DidYouMean, + }; } - suggestion += ")"; - err.span_suggestion_verbose( - error_span, - &suggestion_text, - suggestion, - Applicability::HasPlaceholders, - ); } - err.emit(); } - for arg in provided_args.iter().skip(minimum_input_count) { - let arg_ty = self.check_expr(&arg); + // If we have less than 5 things to say, it would be useful to call out exactly what's wrong + if labels.len() <= 5 { + for (span, label) in labels { + err.span_label(span, label); + } + } - // If the function is c-style variadic, we skipped a bunch of arguments - // so we need to check those, and write out the types - // Ideally this would be folded into the above, for uniform style - // but c-variadic is already a corner case - if c_variadic { - fn variadic_error<'tcx>( - sess: &'tcx Session, - span: Span, - ty: Ty<'tcx>, - cast_ty: &str, - ) { - use crate::structured_errors::MissingCastForVariadicArg; + // Call out where the function is defined + label_fn_like(tcx, &mut err, fn_def_id); - MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit(); + // And add a suggestion block for all of the parameters + let suggestion_text = match suggestion_text { + SuggestionText::None => None, + SuggestionText::Provide(plural) => { + Some(format!("provide the argument{}", if plural { "s" } else { "" })) + } + SuggestionText::Remove(plural) => { + Some(format!("remove the extra argument{}", if plural { "s" } else { "" })) + } + SuggestionText::Swap => Some("swap these arguments".to_string()), + SuggestionText::Reorder => Some("reorder these arguments".to_string()), + SuggestionText::DidYouMean => Some("did you mean".to_string()), + }; + if let Some(suggestion_text) = suggestion_text { + let source_map = self.sess().source_map(); + let mut suggestion = format!( + "{}(", + source_map.span_to_snippet(full_call_span).unwrap_or_else(|_| fn_def_id + .map_or("".to_string(), |fn_def_id| tcx.item_name(fn_def_id).to_string())) + ); + let mut needs_comma = false; + for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() { + if needs_comma { + suggestion += ", "; + } else { + needs_comma = true; } - - // There are a few types which get autopromoted when passed via varargs - // in C but we just error out instead and require explicit casts. - let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); - match arg_ty.kind() { - ty::Float(ty::FloatTy::F32) => { - variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); - } - ty::Int(ty::IntTy::I8 | ty::IntTy::I16) | ty::Bool => { - variadic_error(tcx.sess, arg.span, arg_ty, "c_int"); - } - ty::Uint(ty::UintTy::U8 | ty::UintTy::U16) => { - variadic_error(tcx.sess, arg.span, arg_ty, "c_uint"); - } - ty::FnDef(..) => { - let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); - let ptr_ty = self.resolve_vars_if_possible(ptr_ty); - variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); + let suggestion_text = + if let Some(provided_idx) = provided_idx + && let (_, provided_span) = provided_arg_tys[*provided_idx] + && let Ok(arg_text) = source_map.span_to_snippet(provided_span.source_callsite()) { + arg_text + } else { + // Propose a placeholder of the correct type + let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; + if expected_ty.is_unit() { + "()".to_string() + } else if expected_ty.is_suggestable(tcx) { + format!("/* {} */", expected_ty) + } else { + "/* value */".to_string() } - _ => {} - } + }; + suggestion += &suggestion_text; } + suggestion += ")"; + err.span_suggestion_verbose( + error_span, + &suggestion_text, + suggestion, + Applicability::HasPlaceholders, + ); } + + err.emit(); } fn suggested_tuple_wrap( diff --git a/src/test/ui/argument-suggestions/basic.stderr b/src/test/ui/argument-suggestions/basic.stderr index dd4812b5b25..c495ad6b842 100644 --- a/src/test/ui/argument-suggestions/basic.stderr +++ b/src/test/ui/argument-suggestions/basic.stderr @@ -16,7 +16,7 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied --> $DIR/basic.rs:21:5 | LL | extra(""); - | ^^^^^ -- argument unexpected + | ^^^^^ -- argument of type `&'static str` unexpected | note: function defined here --> $DIR/basic.rs:14:4 diff --git a/src/test/ui/argument-suggestions/extra_arguments.stderr b/src/test/ui/argument-suggestions/extra_arguments.stderr index 9b63f9bcbfa..32b1e15737a 100644 --- a/src/test/ui/argument-suggestions/extra_arguments.stderr +++ b/src/test/ui/argument-suggestions/extra_arguments.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied --> $DIR/extra_arguments.rs:7:3 | LL | empty(""); - | ^^^^^ -- argument unexpected + | ^^^^^ -- argument of type `&'static str` unexpected | note: function defined here --> $DIR/extra_arguments.rs:1:4 @@ -18,7 +18,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:9:3 | LL | one_arg(1, 1); - | ^^^^^^^ - argument unexpected + | ^^^^^^^ - argument of type `{integer}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -34,7 +34,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/extra_arguments.rs:10:3 | LL | one_arg(1, ""); - | ^^^^^^^ -- argument unexpected + | ^^^^^^^ -- argument of type `&'static str` unexpected | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -50,9 +50,9 @@ error[E0061]: this function takes 1 argument but 3 arguments were supplied --> $DIR/extra_arguments.rs:11:3 | LL | one_arg(1, "", 1.0); - | ^^^^^^^ -- --- argument unexpected + | ^^^^^^^ -- --- argument of type `{float}` unexpected | | - | argument unexpected + | argument of type `&'static str` unexpected | note: function defined here --> $DIR/extra_arguments.rs:2:4 @@ -68,7 +68,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:13:3 | LL | two_arg_same(1, 1, 1); - | ^^^^^^^^^^^^ - argument unexpected + | ^^^^^^^^^^^^ - argument of type `{integer}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -84,7 +84,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:14:3 | LL | two_arg_same(1, 1, 1.0); - | ^^^^^^^^^^^^ --- argument unexpected + | ^^^^^^^^^^^^ --- argument of type `{float}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -100,7 +100,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:16:3 | LL | two_arg_diff(1, 1, ""); - | ^^^^^^^^^^^^ - argument of type `&str` unexpected + | ^^^^^^^^^^^^ - argument of type `{integer}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -116,7 +116,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:17:3 | LL | two_arg_diff(1, "", ""); - | ^^^^^^^^^^^^ -- argument unexpected + | ^^^^^^^^^^^^ -- argument of type `&'static str` unexpected | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -132,9 +132,9 @@ error[E0061]: this function takes 2 arguments but 4 arguments were supplied --> $DIR/extra_arguments.rs:18:3 | LL | two_arg_diff(1, 1, "", ""); - | ^^^^^^^^^^^^ - -- argument unexpected + | ^^^^^^^^^^^^ - -- argument of type `&'static str` unexpected | | - | argument of type `&str` unexpected + | argument of type `{integer}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -150,9 +150,9 @@ error[E0061]: this function takes 2 arguments but 4 arguments were supplied --> $DIR/extra_arguments.rs:19:3 | LL | two_arg_diff(1, "", 1, ""); - | ^^^^^^^^^^^^ - -- argument unexpected + | ^^^^^^^^^^^^ - -- argument of type `&'static str` unexpected | | - | argument unexpected + | argument of type `{integer}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -168,7 +168,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:22:3 | LL | two_arg_same(1, 1, ""); - | ^^^^^^^^^^^^ -- argument unexpected + | ^^^^^^^^^^^^ -- argument of type `&'static str` unexpected | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -184,7 +184,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/extra_arguments.rs:23:3 | LL | two_arg_diff(1, 1, ""); - | ^^^^^^^^^^^^ - argument of type `&str` unexpected + | ^^^^^^^^^^^^ - argument of type `{integer}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:4:4 @@ -203,7 +203,7 @@ LL | two_arg_same( | ^^^^^^^^^^^^ ... LL | "" - | -- argument unexpected + | -- argument of type `&'static str` unexpected | note: function defined here --> $DIR/extra_arguments.rs:3:4 @@ -222,7 +222,7 @@ LL | two_arg_diff( | ^^^^^^^^^^^^ LL | 1, LL | 1, - | - argument of type `&str` unexpected + | - argument of type `{integer}` unexpected | note: function defined here --> $DIR/extra_arguments.rs:4:4 diff --git a/src/test/ui/argument-suggestions/issue-97484.stderr b/src/test/ui/argument-suggestions/issue-97484.stderr index 2af24d521f3..9589e919c0a 100644 --- a/src/test/ui/argument-suggestions/issue-97484.stderr +++ b/src/test/ui/argument-suggestions/issue-97484.stderr @@ -2,21 +2,20 @@ error[E0061]: this function takes 4 arguments but 7 arguments were supplied --> $DIR/issue-97484.rs:12:5 | LL | foo(&&A, B, C, D, E, F, G); - | ^^^ - - - argument unexpected + | ^^^ - - - argument of type `F` unexpected | | | - | | argument of type `&E` unexpected - | argument of type `D` unexpected + | | argument of type `C` unexpected + | argument of type `B` unexpected | note: function defined here --> $DIR/issue-97484.rs:9:4 | LL | fn foo(a: &A, d: D, e: &E, g: G) {} | ^^^ ----- ---- ----- ---- -help: consider removing the `` - | -LL - foo(&&A, B, C, D, E, F, G); -LL + foo(&&A, B, C, D, E, F, G); +help: consider borrowing here | +LL | foo(&&A, B, C, D, &E, F, G); + | ~~ help: remove the extra arguments | LL | foo(&&A, D, /* &E */, G); diff --git a/src/test/ui/argument-suggestions/mixed_cases.stderr b/src/test/ui/argument-suggestions/mixed_cases.stderr index 3fe4473a594..a52a30d7884 100644 --- a/src/test/ui/argument-suggestions/mixed_cases.stderr +++ b/src/test/ui/argument-suggestions/mixed_cases.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/mixed_cases.rs:10:3 | LL | two_args(1, "", X {}); - | ^^^^^^^^ -- ---- argument unexpected + | ^^^^^^^^ -- ---- argument of type `X` unexpected | | | expected `f32`, found `&str` | @@ -20,9 +20,9 @@ error[E0061]: this function takes 3 arguments but 4 arguments were supplied --> $DIR/mixed_cases.rs:11:3 | LL | three_args(1, "", X {}, ""); - | ^^^^^^^^^^ -- ---- -- argument unexpected + | ^^^^^^^^^^ -- ---- -- argument of type `&'static str` unexpected | | | - | | argument of type `&str` unexpected + | | argument of type `X` unexpected | an argument of type `f32` is missing | note: function defined here @@ -58,7 +58,7 @@ error[E0308]: arguments to this function are incorrect --> $DIR/mixed_cases.rs:17:3 | LL | three_args(1, "", X {}); - | ^^^^^^^^^^ -- ---- argument of type `&str` unexpected + | ^^^^^^^^^^ -- ---- argument of type `X` unexpected | | | an argument of type `f32` is missing | diff --git a/src/test/ui/error-codes/E0057.stderr b/src/test/ui/error-codes/E0057.stderr index 3697b5fcf15..2307f52c93b 100644 --- a/src/test/ui/error-codes/E0057.stderr +++ b/src/test/ui/error-codes/E0057.stderr @@ -18,7 +18,7 @@ error[E0057]: this function takes 1 argument but 2 arguments were supplied --> $DIR/E0057.rs:5:13 | LL | let c = f(2, 3); - | ^ - argument unexpected + | ^ - argument of type `{integer}` unexpected | note: closure defined here --> $DIR/E0057.rs:2:13 diff --git a/src/test/ui/issues/issue-26094.rs b/src/test/ui/issues/issue-26094.rs index 981c3abb4ba..df8c2f73910 100644 --- a/src/test/ui/issues/issue-26094.rs +++ b/src/test/ui/issues/issue-26094.rs @@ -1,6 +1,6 @@ macro_rules! some_macro { ($other: expr) => ({ - $other(None) //~ NOTE argument unexpected + $other(None) //~ NOTE argument of type `Option<_>` unexpected }) } diff --git a/src/test/ui/issues/issue-26094.stderr b/src/test/ui/issues/issue-26094.stderr index 1013518e1da..881a6e538ee 100644 --- a/src/test/ui/issues/issue-26094.stderr +++ b/src/test/ui/issues/issue-26094.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied --> $DIR/issue-26094.rs:10:17 | LL | $other(None) - | ---- argument unexpected + | ---- argument of type `Option<_>` unexpected ... LL | some_macro!(some_function); | ^^^^^^^^^^^^^ diff --git a/src/test/ui/issues/issue-4935.stderr b/src/test/ui/issues/issue-4935.stderr index b4cebe2a68b..aab19a699ac 100644 --- a/src/test/ui/issues/issue-4935.stderr +++ b/src/test/ui/issues/issue-4935.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/issue-4935.rs:5:13 | LL | fn main() { foo(5, 6) } - | ^^^ - argument unexpected + | ^^^ - argument of type `{integer}` unexpected | note: function defined here --> $DIR/issue-4935.rs:3:4 diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr index 77308a2c521..57662e1e265 100644 --- a/src/test/ui/methods/method-call-err-msg.stderr +++ b/src/test/ui/methods/method-call-err-msg.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied --> $DIR/method-call-err-msg.rs:13:7 | LL | x.zero(0) - | ^^^^ - argument unexpected + | ^^^^ - argument of type `{integer}` unexpected | note: associated function defined here --> $DIR/method-call-err-msg.rs:5:8 diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr index 4000b2ba312..cb93a7ad900 100644 --- a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr +++ b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr @@ -32,7 +32,7 @@ error[E0057]: this function takes 1 argument but 2 arguments were supplied --> $DIR/overloaded-calls-bad.rs:31:15 | LL | let ans = s("burma", "shave"); - | ^ ------- ------- argument unexpected + | ^ ------- ------- argument of type `&'static str` unexpected | | | expected `isize`, found `&str` | diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index 68da9f0dc88..e676d7372e8 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -54,7 +54,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:7:5 | LL | foo(Some(42), 2, ""); - | ^^^ -- argument unexpected + | ^^^ -- argument of type `&'static str` unexpected | note: function defined here --> $DIR/issue-34264.rs:1:4 @@ -84,7 +84,7 @@ error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:10:5 | LL | bar(1, 2, 3); - | ^^^ - argument unexpected + | ^^^ - argument of type `{integer}` unexpected | note: function defined here --> $DIR/issue-34264.rs:3:4 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 3d367eca707..805c75f464c 100644 --- a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr +++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr @@ -2,7 +2,7 @@ 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); - | ^^^^ - - argument unexpected + | ^^^^ - - argument of type `{integer}` unexpected | | | expected tuple, found integer | @@ -22,7 +22,7 @@ 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); - | ^^^^^^^^ - - argument unexpected + | ^^^^^^^^ - - argument of type `{integer}` unexpected | | | expected tuple, found integer | diff --git a/src/test/ui/tuple/wrong_argument_ice-3.stderr b/src/test/ui/tuple/wrong_argument_ice-3.stderr index 667b15776ef..2733fb3149b 100644 --- a/src/test/ui/tuple/wrong_argument_ice-3.stderr +++ b/src/test/ui/tuple/wrong_argument_ice-3.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/wrong_argument_ice-3.rs:9:16 | LL | groups.push(new_group, vec![process]); - | ^^^^ --------- ------------- argument unexpected + | ^^^^ --------- ------------- argument of type `Vec<&Process>` unexpected | | | expected tuple, found struct `Vec` | diff --git a/src/test/ui/tuple/wrong_argument_ice-4.stderr b/src/test/ui/tuple/wrong_argument_ice-4.stderr index f8dfc4cd043..3645d11842f 100644 --- a/src/test/ui/tuple/wrong_argument_ice-4.stderr +++ b/src/test/ui/tuple/wrong_argument_ice-4.stderr @@ -6,7 +6,7 @@ LL | (|| {})(|| { LL | | LL | | let b = 1; LL | | }); - | |_____- argument unexpected + | |_____- argument of type `[closure@$DIR/wrong_argument_ice-4.rs:2:13: 5:6]` unexpected | note: closure defined here --> $DIR/wrong_argument_ice-4.rs:2:6 diff --git a/src/test/ui/type/type-ascription-instead-of-initializer.stderr b/src/test/ui/type/type-ascription-instead-of-initializer.stderr index 18ed4986f89..fcac6c495c4 100644 --- a/src/test/ui/type/type-ascription-instead-of-initializer.stderr +++ b/src/test/ui/type/type-ascription-instead-of-initializer.stderr @@ -11,7 +11,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/type-ascription-instead-of-initializer.rs:2:12 | LL | let x: Vec::with_capacity(10, 20); - | ^^^^^^^^^^^^^^^^^^ -- argument unexpected + | ^^^^^^^^^^^^^^^^^^ -- argument of type `{integer}` unexpected | note: associated function defined here --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL diff --git a/src/test/ui/typeck/remove-extra-argument.stderr b/src/test/ui/typeck/remove-extra-argument.stderr index 815297765c1..703032a8322 100644 --- a/src/test/ui/typeck/remove-extra-argument.stderr +++ b/src/test/ui/typeck/remove-extra-argument.stderr @@ -2,7 +2,7 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/remove-extra-argument.rs:6:5 | LL | l(vec![], vec![]) - | ^ ------ argument unexpected + | ^ ------ argument of type `Vec<_>` unexpected | note: function defined here --> $DIR/remove-extra-argument.rs:3:4 diff --git a/src/test/ui/typeck/struct-enum-wrong-args.stderr b/src/test/ui/typeck/struct-enum-wrong-args.stderr index 2ea822df275..f72082d5301 100644 --- a/src/test/ui/typeck/struct-enum-wrong-args.stderr +++ b/src/test/ui/typeck/struct-enum-wrong-args.stderr @@ -2,7 +2,7 @@ error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:6:13 | LL | let _ = Some(3, 2); - | ^^^^ - argument unexpected + | ^^^^ - argument of type `{integer}` unexpected | note: tuple variant defined here --> $SRC_DIR/core/src/option.rs:LL:COL @@ -18,9 +18,9 @@ error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:7:13 | LL | let _ = Ok(3, 6, 2); - | ^^ - - argument unexpected + | ^^ - - argument of type `{integer}` unexpected | | - | argument unexpected + | argument of type `{integer}` unexpected | note: tuple variant defined here --> $SRC_DIR/core/src/result.rs:LL:COL @@ -68,7 +68,7 @@ error[E0061]: this struct takes 1 argument but 2 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:10:13 | LL | let _ = Wrapper(5, 2); - | ^^^^^^^ - argument unexpected + | ^^^^^^^ - argument of type `{integer}` unexpected | note: tuple struct defined here --> $DIR/struct-enum-wrong-args.rs:2:8 @@ -116,7 +116,7 @@ error[E0061]: this struct takes 2 arguments but 3 arguments were supplied --> $DIR/struct-enum-wrong-args.rs:13:13 | LL | let _ = DoubleWrapper(5, 2, 7); - | ^^^^^^^^^^^^^ - argument unexpected + | ^^^^^^^^^^^^^ - argument of type `{integer}` unexpected | note: tuple struct defined here --> $DIR/struct-enum-wrong-args.rs:3:8 |
