Rollup merge of #94438 - compiler-errors:check-method-inputs-once, r=davidtwco
Check method input expressions once If the user mistakenly forgets to wrap their method args in a tuple, then the compiler tries to check that types within the tuple match the expression args. This means we call `check_expr` once within this diagnostic code, so when we check the expr once again in `demand_compatible`, we attempt to apply expr adjustments twice, leading to ICEs. This PR attempts to fix this by skipping the expression type check in `demand_compatible` if we have detected an method arg mismatch at all. This does lead to a single UI test regressing slightly, due to a diagnostic disappearing, though I don't know if it is generally meaningful to even raise an type error after noting that the argument count is incorrect in a function call, since the user might be providing (in-context) meaningless expressions to the wrong method. I can adjust this to be a bit more targeted (to just skip checking exprs in `demand_compatible` in the tuple case) if this UI test regression is a problem. fixes #94334 cc #94291 Also drive-by fixup of `.node_type(expr.hir_id)` to `.expr_ty(expr)`, since that method exists.
This commit is contained in:
commit
2353e835c5
@ -470,7 +470,7 @@ fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, St
|
||||
return None;
|
||||
};
|
||||
|
||||
let self_ty = self.typeck_results.borrow().node_type(method_expr[0].hir_id);
|
||||
let self_ty = self.typeck_results.borrow().expr_ty(&method_expr[0]);
|
||||
let self_ty = format!("{:?}", self_ty);
|
||||
let name = method_path.ident.name;
|
||||
let is_as_ref_able = (self_ty.starts_with("&std::option::Option")
|
||||
|
@ -1517,7 +1517,7 @@ fn check_expr_struct_fields(
|
||||
}
|
||||
} else {
|
||||
self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {
|
||||
let base_ty = self.typeck_results.borrow().node_type(base_expr.hir_id);
|
||||
let base_ty = self.typeck_results.borrow().expr_ty(*base_expr);
|
||||
let same_adt = match (adt_ty.kind(), base_ty.kind()) {
|
||||
(ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt => true,
|
||||
_ => false,
|
||||
|
@ -313,15 +313,6 @@ pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>
|
||||
) => {
|
||||
// A reborrow has no effect before a dereference.
|
||||
}
|
||||
// Catch cases which have Deref(None)
|
||||
// having them slip to bug! causes ICE
|
||||
// see #94291 for more info
|
||||
(&[Adjustment { kind: Adjust::Deref(None), .. }], _) => {
|
||||
self.tcx.sess.delay_span_bug(
|
||||
DUMMY_SP,
|
||||
&format!("Can't compose Deref(None) expressions"),
|
||||
)
|
||||
}
|
||||
// FIXME: currently we never try to compose autoderefs
|
||||
// and ReifyFnPointer/UnsafeFnPointer, but we could.
|
||||
_ => bug!(
|
||||
|
@ -133,7 +133,8 @@ pub(in super::super) fn check_argument_types(
|
||||
let expected_arg_count = formal_input_tys.len();
|
||||
|
||||
// expected_count, arg_count, error_code, sugg_unit, sugg_tuple_wrap_args
|
||||
let mut error: Option<(usize, usize, &str, bool, Option<FnArgsAsTuple<'_>>)> = None;
|
||||
let mut arg_count_error: Option<(usize, usize, &str, bool, Option<FnArgsAsTuple<'_>>)> =
|
||||
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 {
|
||||
@ -143,7 +144,8 @@ pub(in super::super) fn check_argument_types(
|
||||
ty::Tuple(arg_types) => {
|
||||
// Argument length differs
|
||||
if arg_types.len() != provided_args.len() {
|
||||
error = Some((arg_types.len(), provided_args.len(), "E0057", false, None));
|
||||
arg_count_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() {
|
||||
@ -174,7 +176,8 @@ pub(in super::super) fn check_argument_types(
|
||||
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, None));
|
||||
arg_count_error =
|
||||
Some((expected_arg_count, supplied_arg_count, "E0060", false, None));
|
||||
(self.err_args(supplied_arg_count), vec![])
|
||||
}
|
||||
} else {
|
||||
@ -198,7 +201,7 @@ pub(in super::super) fn check_argument_types(
|
||||
|
||||
let sugg_tuple_wrap_args = self.suggested_tuple_wrap(expected_input_tys, provided_args);
|
||||
|
||||
error = Some((
|
||||
arg_count_error = Some((
|
||||
expected_arg_count,
|
||||
supplied_arg_count,
|
||||
"E0061",
|
||||
@ -231,6 +234,11 @@ pub(in super::super) fn check_argument_types(
|
||||
// This is more complicated than just checking type equality, as arguments could be coerced
|
||||
// This version writes those types back so further type checking uses the narrowed types
|
||||
let demand_compatible = |idx, final_arg_types: &mut Vec<Option<(Ty<'tcx>, Ty<'tcx>)>>| {
|
||||
// Do not check argument compatibility if the number of args do not match
|
||||
if arg_count_error.is_some() {
|
||||
return;
|
||||
}
|
||||
|
||||
let formal_input_ty: Ty<'tcx> = formal_input_tys[idx];
|
||||
let expected_input_ty: Ty<'tcx> = expected_input_tys[idx];
|
||||
let provided_arg = &provided_args[idx];
|
||||
@ -328,7 +336,8 @@ pub(in super::super) fn check_argument_types(
|
||||
}
|
||||
|
||||
// If there was an error in parameter count, emit that here
|
||||
if let Some((expected_count, arg_count, err_code, sugg_unit, sugg_tuple_wrap_args)) = error
|
||||
if let Some((expected_count, arg_count, err_code, sugg_unit, sugg_tuple_wrap_args)) =
|
||||
arg_count_error
|
||||
{
|
||||
let (span, start_span, args, ctor_of) = match &call_expr.kind {
|
||||
hir::ExprKind::Call(
|
||||
|
@ -30,5 +30,4 @@ fn main() {
|
||||
//~^ ERROR this function takes 1 argument but 0 arguments were supplied
|
||||
let ans = s("burma", "shave");
|
||||
//~^ ERROR this function takes 1 argument but 2 arguments were supplied
|
||||
//~| ERROR mismatched types
|
||||
}
|
||||
|
@ -18,12 +18,6 @@ note: associated function defined here
|
||||
LL | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
|
||||
| ^^^^^^^^
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/overloaded-calls-bad.rs:31:17
|
||||
|
|
||||
LL | let ans = s("burma", "shave");
|
||||
| ^^^^^^^ expected `isize`, found `&str`
|
||||
|
||||
error[E0057]: this function takes 1 argument but 2 arguments were supplied
|
||||
--> $DIR/overloaded-calls-bad.rs:31:15
|
||||
|
|
||||
@ -38,7 +32,7 @@ note: associated function defined here
|
||||
LL | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0057, E0308.
|
||||
For more information about an error, try `rustc --explain E0057`.
|
||||
|
17
src/test/ui/tuple/wrong_argument_ice-2.rs
Normal file
17
src/test/ui/tuple/wrong_argument_ice-2.rs
Normal file
@ -0,0 +1,17 @@
|
||||
fn test(t: (i32, i32)) {}
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn qux(&self) -> i32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
let x = Foo;
|
||||
test(x.qux(), x.qux());
|
||||
//~^ ERROR this function takes 1 argument but 2 arguments were supplied
|
||||
}
|
||||
|
||||
fn main() {}
|
19
src/test/ui/tuple/wrong_argument_ice-2.stderr
Normal file
19
src/test/ui/tuple/wrong_argument_ice-2.stderr
Normal file
@ -0,0 +1,19 @@
|
||||
error[E0061]: this function takes 1 argument but 2 arguments were supplied
|
||||
--> $DIR/wrong_argument_ice-2.rs:13:5
|
||||
|
|
||||
LL | test(x.qux(), x.qux());
|
||||
| ^^^^ ------- ------- supplied 2 arguments
|
||||
|
|
||||
note: function defined here
|
||||
--> $DIR/wrong_argument_ice-2.rs:1:4
|
||||
|
|
||||
LL | fn test(t: (i32, i32)) {}
|
||||
| ^^^^ -------------
|
||||
help: use parentheses to construct a tuple
|
||||
|
|
||||
LL | test((x.qux(), x.qux()));
|
||||
| + +
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0061`.
|
Loading…
Reference in New Issue
Block a user