Skip to content

Commit

Permalink
Auto merge of #98785 - compiler-errors:no-check-expr-in-check-compati…
Browse files Browse the repository at this point in the history
…ble, r=estebank

Do not call `check_expr` in `check_compatible`, since it has side-effects

Fixes a weird suggestion in #98784

found later:
Fixes #98894
Fixes #98897
  • Loading branch information
bors committed Jul 10, 2022
2 parents 29554c0 + 6858fbc commit c6ff90b
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 45 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down
44 changes: 18 additions & 26 deletions compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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),
Expand All @@ -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)| {
Expand Down
3 changes: 1 addition & 2 deletions src/test/ui/issues/issue-3044.rs
Original file line number Diff line number Diff line change
@@ -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
}
20 changes: 4 additions & 16 deletions src/test/ui/issues/issue-3044.stderr
Original file line number Diff line number Diff line change
@@ -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
|
Expand All @@ -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`.

0 comments on commit c6ff90b

Please sign in to comment.