diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 45ea04f234288..58c01a34cad51 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -271,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } #[instrument(skip(self, expr), level = "debug")] - pub(super) fn check_expr_kind( + fn check_expr_kind( &self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 1794446e92aa5..a7c7089234aa9 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -483,6 +483,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.set_tainted_by_errors(); let tcx = self.tcx; + // Precompute the provided types and spans, since that's all we typically need for below + let provided_arg_tys: IndexVec, Span)> = provided_args + .iter() + .map(|expr| { + let ty = self + .typeck_results + .borrow() + .expr_ty_adjusted_opt(*expr) + .unwrap_or_else(|| tcx.ty_error()); + (self.resolve_vars_if_possible(ty), expr.span) + }) + .collect(); + // 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 @@ -499,31 +512,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 (arg_ty, arg_span) = provided_arg_tys[provided_idx]; + let expectation = Expectation::rvalue_hint(self, expected_input_ty); let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); - let can_coerce = self.can_coerce(checked_ty, coerced_ty); + let can_coerce = self.can_coerce(arg_ty, coerced_ty); if !can_coerce { return Compatibility::Incompatible(None); } // Using probe here, since we don't want this subtyping to affect inference. let subtyping_error = self.probe(|_| { - self.at(&self.misc(provided_arg.span), self.param_env) - .sup(formal_input_ty, coerced_ty) - .err() + self.at(&self.misc(arg_span), self.param_env).sup(formal_input_ty, coerced_ty).err() }); // 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(); + let references_error = (coerced_ty, arg_ty).references_error(); match (references_error, subtyping_error) { (false, None) => Compatibility::Compatible, (_, subtyping_error) => Compatibility::Incompatible(subtyping_error), @@ -542,19 +547,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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, Span)> = provided_args - .iter() - .map(|expr| { - let ty = self - .typeck_results - .borrow() - .expr_ty_adjusted_opt(*expr) - .unwrap_or_else(|| tcx.ty_error()); - (self.resolve_vars_if_possible(ty), expr.span) - }) - .collect(); - // First, check if we just need to wrap some arguments in a tuple. if let Some((mismatch_idx, terr)) = compatibility_diagonal.iter().enumerate().find_map(|(i, c)| { diff --git a/src/test/ui/issues/issue-3044.rs b/src/test/ui/issues/issue-3044.rs index 7363cae8370ab..7c626a01b1298 100644 --- a/src/test/ui/issues/issue-3044.rs +++ b/src/test/ui/issues/issue-3044.rs @@ -1,7 +1,6 @@ fn main() { let needlesArr: Vec = vec!['a', 'f']; needlesArr.iter().fold(|x, y| { + //~^ ERROR this function takes 2 arguments but 1 argument was supplied }); - //~^^ ERROR mismatched types - //~| ERROR this function takes 2 arguments but 1 argument was supplied } diff --git a/src/test/ui/issues/issue-3044.stderr b/src/test/ui/issues/issue-3044.stderr index 7230079dcffc1..a4c455ca1927e 100644 --- a/src/test/ui/issues/issue-3044.stderr +++ b/src/test/ui/issues/issue-3044.stderr @@ -1,21 +1,9 @@ -error[E0308]: mismatched types - --> $DIR/issue-3044.rs:3:35 - | -LL | needlesArr.iter().fold(|x, y| { - | ____________________________------_^ - | | | - | | the expected closure -LL | | }); - | |_____^ expected closure, found `()` - | - = note: expected closure `[closure@$DIR/issue-3044.rs:3:28: 3:34]` - found unit type `()` - error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/issue-3044.rs:3:23 | LL | needlesArr.iter().fold(|x, y| { | _______________________^^^^- +LL | | LL | | }); | |______- an argument is missing | @@ -27,10 +15,10 @@ LL | fn fold(mut self, init: B, mut f: F) -> B help: provide the argument | LL ~ needlesArr.iter().fold(|x, y| { +LL + LL ~ }, /* value */); | -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0061, E0308. -For more information about an error, try `rustc --explain E0061`. +For more information about this error, try `rustc --explain E0061`.