about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2022-07-01 22:16:05 +0000
committerMichael Goulet <michael@errs.io>2022-07-09 20:50:23 +0000
commit6858fbc1012c2313dc538ba9fca6fa42c1deb198 (patch)
treedbd87b9ecb1a2541929e28723f07f8f95ba509fa
parent86b8dd5389cd9d545418a60902222a4ba859365f (diff)
downloadrust-6858fbc1012c2313dc538ba9fca6fa42c1deb198.tar.gz
rust-6858fbc1012c2313dc538ba9fca6fa42c1deb198.zip
Do not call `check_expr` in `check_compatible`, since it has side-effects and we've already checked all args
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs44
-rw-r--r--src/test/ui/issues/issue-3044.rs3
-rw-r--r--src/test/ui/issues/issue-3044.stderr20
4 files changed, 24 insertions, 45 deletions
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 45ea04f2342..58c01a34cad 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 1794446e92a..a7c7089234a 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<ProvidedIdx, (Ty<'tcx>, 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<ProvidedIdx, (Ty<'tcx>, 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 7363cae8370..7c626a01b12 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<char> = 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 7230079dcff..a4c455ca192 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<B, F>(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`.