From ddb7003b7950a6df815d1f03ea6eca9f4cc2a408 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 10 Jul 2022 21:59:31 +0000 Subject: [PATCH 1/2] Add support for APIT and RPIT callables in label_fn_like --- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 138 +++++++++++++----- .../ui/argument-suggestions/exotic-calls.rs | 26 ++++ .../argument-suggestions/exotic-calls.stderr | 67 +++++++++ src/test/ui/issues/issue-16939.stderr | 8 +- .../overloaded-calls-bad.stderr | 16 -- 5 files changed, 195 insertions(+), 60 deletions(-) create mode 100644 src/test/ui/argument-suggestions/exotic-calls.rs create mode 100644 src/test/ui/argument-suggestions/exotic-calls.stderr diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index b1e391bf1c71f..3dd63d74c3fd7 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -25,7 +25,7 @@ use rustc_infer::infer::InferOk; use rustc_infer::infer::TypeTrace; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::{self, Span}; @@ -89,7 +89,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args_no_rcvr, false, tuple_arguments, - None, + method.ok().map(|method| method.def_id), ); return self.tcx.ty_error(); } @@ -458,6 +458,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { c_variadic, err_code, fn_def_id, + call_expr, ); } } @@ -474,6 +475,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { c_variadic: bool, err_code: &str, fn_def_id: Option, + call_expr: &hir::Expr<'tcx>, ) { // Don't print if it has error types or is just plain `_` fn has_error_or_infer<'tcx>(tys: impl IntoIterator>) -> bool { @@ -495,6 +497,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (self.resolve_vars_if_possible(ty), expr.span) }) .collect(); + let callee_expr = match &call_expr.peel_blocks().kind { + hir::ExprKind::Call(callee, _) => Some(*callee), + hir::ExprKind::MethodCall(_, callee, _) => { + if let Some((DefKind::AssocFn, def_id)) = + self.typeck_results.borrow().type_dependent_def(call_expr.hir_id) + && let Some(assoc) = tcx.opt_associated_item(def_id) + && assoc.fn_has_self_parameter + { + Some(&callee[0]) + } else { + None + } + } + _ => None, + }; + let callee_ty = callee_expr + .and_then(|callee_expr| self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr)); // A "softer" version of the `demand_compatible`, which checks types without persisting them, // and treats error types differently @@ -631,7 +650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); }; - label_fn_like(tcx, &mut err, fn_def_id); + self.label_fn_like(&mut err, fn_def_id, callee_ty); err.emit(); return; } @@ -721,7 +740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!("arguments to this {} are incorrect", call_name), ); // Call out where the function is defined - label_fn_like(tcx, &mut err, fn_def_id); + self.label_fn_like(&mut err, fn_def_id, callee_ty); err.emit(); return; } @@ -1003,7 +1022,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Call out where the function is defined - label_fn_like(tcx, &mut err, fn_def_id); + self.label_fn_like(&mut err, fn_def_id, callee_ty); // And add a suggestion block for all of the parameters let suggestion_text = match suggestion_text { @@ -1795,47 +1814,86 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } -} -fn label_fn_like<'tcx>( - tcx: TyCtxt<'tcx>, - err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>, - def_id: Option, -) { - let Some(def_id) = def_id else { - return; - }; - - if let Some(def_span) = tcx.def_ident_span(def_id) { - let mut spans: MultiSpan = def_span.into(); - - let params = tcx - .hir() - .get_if_local(def_id) - .and_then(|node| node.body_id()) - .into_iter() - .flat_map(|id| tcx.hir().body(id).params); - - for param in params { - spans.push_span_label(param.span, ""); + fn label_fn_like( + &self, + err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>, + def_id: Option, + callee_ty: Option>, + ) { + let Some(mut def_id) = def_id else { + return; + }; + + if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) + && let trait_def_id = assoc_item.trait_item_def_id.unwrap_or_else(|| self.tcx.parent(def_id)) + // Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce" + && ty::ClosureKind::from_def_id(self.tcx, trait_def_id).is_some() + && let Some(callee_ty) = callee_ty + { + let callee_ty = callee_ty.peel_refs(); + match *callee_ty.kind() { + ty::Param(param) => { + let param = + self.tcx.generics_of(self.body_id.owner).type_param(¶m, self.tcx); + if param.kind.is_synthetic() { + // if it's `impl Fn() -> ..` then just fall down to the def-id based logic + def_id = param.def_id; + } else { + // Otherwise, find the predicate that makes this generic callable, + // and point at that. + let instantiated = self + .tcx + .explicit_predicates_of(self.body_id.owner) + .instantiate_identity(self.tcx); + // FIXME(compiler-errors): This could be problematic if something has two + // fn-like predicates with different args, but callable types really never + // do that, so it's OK. + for (predicate, span) in + std::iter::zip(instantiated.predicates, instantiated.spans) + { + if let ty::PredicateKind::Trait(pred) = predicate.kind().skip_binder() + && pred.self_ty() == callee_ty + && ty::ClosureKind::from_def_id(self.tcx, pred.def_id()).is_some() + { + err.span_note(span, "callable defined here"); + return; + } + } + } + } + ty::Opaque(new_def_id, _) | ty::Closure(new_def_id, _) | ty::FnDef(new_def_id, _) => { + def_id = new_def_id; + } + _ => { + return; + } + } } - let def_kind = tcx.def_kind(def_id); - err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); - } else { - match tcx.hir().get_if_local(def_id) { - Some(hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }), - .. - })) => { - let spans: MultiSpan = (*fn_decl_span).into(); + if let Some(def_span) = self.tcx.def_ident_span(def_id) && !def_span.is_dummy() { + let mut spans: MultiSpan = def_span.into(); - // Note: We don't point to param spans here because they overlap - // with the closure span itself + let params = self + .tcx + .hir() + .get_if_local(def_id) + .and_then(|node| node.body_id()) + .into_iter() + .flat_map(|id| self.tcx.hir().body(id).params); - err.span_note(spans, "closure defined here"); + for param in params { + spans.push_span_label(param.span, ""); } - _ => {} + + let def_kind = self.tcx.def_kind(def_id); + err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); + } else if let def_kind @ (DefKind::Closure | DefKind::OpaqueTy) = self.tcx.def_kind(def_id) + { + err.span_note( + self.tcx.def_span(def_id), + &format!("{} defined here", def_kind.descr(def_id)), + ); } } } diff --git a/src/test/ui/argument-suggestions/exotic-calls.rs b/src/test/ui/argument-suggestions/exotic-calls.rs new file mode 100644 index 0000000000000..a18e967668def --- /dev/null +++ b/src/test/ui/argument-suggestions/exotic-calls.rs @@ -0,0 +1,26 @@ +fn foo(t: T) { + t(1i32); + //~^ ERROR this function takes 0 arguments but 1 argument was supplied +} + +fn bar(t: impl Fn()) { + t(1i32); + //~^ ERROR this function takes 0 arguments but 1 argument was supplied +} + +fn baz() -> impl Fn() { + || {} +} + +fn baz2() { + baz()(1i32) + //~^ ERROR this function takes 0 arguments but 1 argument was supplied +} + +fn qux() { + let x = || {}; + x(1i32); + //~^ ERROR this function takes 0 arguments but 1 argument was supplied +} + +fn main() {} diff --git a/src/test/ui/argument-suggestions/exotic-calls.stderr b/src/test/ui/argument-suggestions/exotic-calls.stderr new file mode 100644 index 0000000000000..ca93ecc4e381a --- /dev/null +++ b/src/test/ui/argument-suggestions/exotic-calls.stderr @@ -0,0 +1,67 @@ +error[E0057]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/exotic-calls.rs:2:5 + | +LL | t(1i32); + | ^ ---- argument of type `i32` unexpected + | +note: callable defined here + --> $DIR/exotic-calls.rs:1:11 + | +LL | fn foo(t: T) { + | ^^^^ +help: remove the extra argument + | +LL | t(); + | ~~~ + +error[E0057]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/exotic-calls.rs:7:5 + | +LL | t(1i32); + | ^ ---- argument of type `i32` unexpected + | +note: type parameter defined here + --> $DIR/exotic-calls.rs:6:11 + | +LL | fn bar(t: impl Fn()) { + | ^^^^^^^^^ +help: remove the extra argument + | +LL | t(); + | ~~~ + +error[E0057]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/exotic-calls.rs:16:5 + | +LL | baz()(1i32) + | ^^^^^ ---- argument of type `i32` unexpected + | +note: opaque type defined here + --> $DIR/exotic-calls.rs:11:13 + | +LL | fn baz() -> impl Fn() { + | ^^^^^^^^^ +help: remove the extra argument + | +LL | baz()() + | + +error[E0057]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/exotic-calls.rs:22:5 + | +LL | x(1i32); + | ^ ---- argument of type `i32` unexpected + | +note: closure defined here + --> $DIR/exotic-calls.rs:21:13 + | +LL | let x = || {}; + | ^^ +help: remove the extra argument + | +LL | x(); + | ~~~ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0057`. diff --git a/src/test/ui/issues/issue-16939.stderr b/src/test/ui/issues/issue-16939.stderr index 294524f0b6148..aaa3c49b3d83e 100644 --- a/src/test/ui/issues/issue-16939.stderr +++ b/src/test/ui/issues/issue-16939.stderr @@ -4,11 +4,11 @@ error[E0057]: this function takes 0 arguments but 1 argument was supplied LL | |t| f(t); | ^ - argument unexpected | -note: associated function defined here - --> $SRC_DIR/core/src/ops/function.rs:LL:COL +note: callable defined here + --> $DIR/issue-16939.rs:4:12 | -LL | extern "rust-call" fn call(&self, args: Args) -> Self::Output; - | ^^^^ +LL | fn _foo (f: F) { + | ^^^^ help: remove the extra argument | LL | |t| f(); diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr index cb93a7ad9008d..5ed15468fd64a 100644 --- a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr +++ b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr @@ -5,12 +5,6 @@ LL | let ans = s("what"); | - ^^^^^^ expected `isize`, found `&str` | | | arguments to this function are incorrect - | -note: associated function defined here - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - | -LL | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; - | ^^^^^^^^ error[E0057]: this function takes 1 argument but 0 arguments were supplied --> $DIR/overloaded-calls-bad.rs:29:15 @@ -18,11 +12,6 @@ error[E0057]: this function takes 1 argument but 0 arguments were supplied LL | let ans = s(); | ^-- an argument of type `isize` is missing | -note: associated function defined here - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - | -LL | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; - | ^^^^^^^^ help: provide the argument | LL | let ans = s(/* isize */); @@ -36,11 +25,6 @@ LL | let ans = s("burma", "shave"); | | | expected `isize`, found `&str` | -note: associated function defined here - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - | -LL | extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; - | ^^^^^^^^ help: remove the extra argument | LL | let ans = s(/* isize */); From d25abdc0c52cc08cdd290be325f1be04f3cea548 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 13 Jul 2022 05:39:01 +0000 Subject: [PATCH 2/2] Point out custom Fn-family trait impl --- compiler/rustc_middle/src/ty/closure.rs | 8 + .../rustc_typeck/src/check/fn_ctxt/checks.rs | 143 +++++++++++------- .../overloaded-calls-bad.stderr | 16 ++ 3 files changed, 114 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index f5ce43f3afb69..8ead05122740e 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -128,6 +128,14 @@ impl<'tcx> ClosureKind { None } } + + pub fn to_def_id(&self, tcx: TyCtxt<'_>) -> DefId { + match self { + ClosureKind::Fn => tcx.lang_items().fn_once_trait().unwrap(), + ClosureKind::FnMut => tcx.lang_items().fn_mut_trait().unwrap(), + ClosureKind::FnOnce => tcx.lang_items().fn_trait().unwrap(), + } + } } /// A composite describing a `Place` that is captured by a closure. diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 3dd63d74c3fd7..ec045d3e70c96 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -21,6 +21,7 @@ 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::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::InferOk; use rustc_infer::infer::TypeTrace; use rustc_middle::ty::adjustment::AllowTwoPhase; @@ -29,7 +30,9 @@ use rustc_middle::ty::{self, DefIdTree, IsSuggestable, Ty}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::{self, Span}; -use rustc_trait_selection::traits::{self, ObligationCauseCode, StatementAsExpression}; +use rustc_trait_selection::traits::{ + self, ObligationCauseCode, SelectionContext, StatementAsExpression, +}; use std::iter; use std::slice; @@ -393,41 +396,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } 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( - hir::Expr { - span, - kind: - hir::ExprKind::Path(hir::QPath::Resolved( - _, - hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. }, - )), - .. - }, - _, - ) => (call_span, *span, Some(of)), - hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None), - hir::ExprKind::MethodCall(path_segment, _, span) => { - let ident_span = path_segment.ident.span; - let ident_span = if let Some(args) = path_segment.args { - ident_span.with_hi(args.span_ext.hi()) - } else { - ident_span - }; - ( - *span, ident_span, None, // methods are never ctors - ) - } - k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k), - }; - let args_span = error_span.trim_start(full_call_span).unwrap_or(error_span); - let call_name = match ctor_of { - Some(CtorOf::Struct) => "struct", - Some(CtorOf::Variant) => "enum variant", - None => "function", - }; - let compatibility_diagonal = IndexVec::from_raw(compatibility_diagonal); let provided_args = IndexVec::from_iter(provided_args.iter().take(if c_variadic { minimum_input_count @@ -451,13 +419,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { compatibility_diagonal, formal_and_expected_inputs, provided_args, - full_call_span, - error_span, - args_span, - call_name, c_variadic, err_code, fn_def_id, + call_span, call_expr, ); } @@ -468,15 +433,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { compatibility_diagonal: IndexVec>, formal_and_expected_inputs: IndexVec, Ty<'tcx>)>, provided_args: IndexVec>, - full_call_span: Span, - error_span: Span, - args_span: Span, - call_name: &str, c_variadic: bool, err_code: &str, fn_def_id: Option, + call_span: Span, call_expr: &hir::Expr<'tcx>, ) { + // Next, let's construct the error + let (error_span, full_call_span, ctor_of) = match &call_expr.kind { + hir::ExprKind::Call( + hir::Expr { + span, + kind: + hir::ExprKind::Path(hir::QPath::Resolved( + _, + hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. }, + )), + .. + }, + _, + ) => (call_span, *span, Some(of)), + hir::ExprKind::Call(hir::Expr { span, .. }, _) => (call_span, *span, None), + hir::ExprKind::MethodCall(path_segment, _, span) => { + let ident_span = path_segment.ident.span; + let ident_span = if let Some(args) = path_segment.args { + ident_span.with_hi(args.span_ext.hi()) + } else { + ident_span + }; + ( + *span, ident_span, None, // methods are never ctors + ) + } + k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k), + }; + let args_span = error_span.trim_start(full_call_span).unwrap_or(error_span); + let call_name = match ctor_of { + Some(CtorOf::Struct) => "struct", + Some(CtorOf::Variant) => "enum variant", + None => "function", + }; + // Don't print if it has error types or is just plain `_` fn has_error_or_infer<'tcx>(tys: impl IntoIterator>) -> bool { tys.into_iter().any(|ty| ty.references_error() || ty.is_ty_var()) @@ -1818,17 +1815,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn label_fn_like( &self, err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>, - def_id: Option, + callable_def_id: Option, callee_ty: Option>, ) { - let Some(mut def_id) = def_id else { + let Some(mut def_id) = callable_def_id else { return; }; if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) - && let trait_def_id = assoc_item.trait_item_def_id.unwrap_or_else(|| self.tcx.parent(def_id)) + // Possibly points at either impl or trait item, so try to get it + // to point to trait item, then get the parent. + // This parent might be an impl in the case of an inherent function, + // but the next check will fail. + && let maybe_trait_item_def_id = assoc_item.trait_item_def_id.unwrap_or(def_id) + && let maybe_trait_def_id = self.tcx.parent(maybe_trait_item_def_id) // Just an easy way to check "trait_def_id == Fn/FnMut/FnOnce" - && ty::ClosureKind::from_def_id(self.tcx, trait_def_id).is_some() + && let Some(call_kind) = ty::ClosureKind::from_def_id(self.tcx, maybe_trait_def_id) && let Some(callee_ty) = callee_ty { let callee_ty = callee_ty.peel_refs(); @@ -1853,7 +1855,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { std::iter::zip(instantiated.predicates, instantiated.spans) { if let ty::PredicateKind::Trait(pred) = predicate.kind().skip_binder() - && pred.self_ty() == callee_ty + && pred.self_ty().peel_refs() == callee_ty && ty::ClosureKind::from_def_id(self.tcx, pred.def_id()).is_some() { err.span_note(span, "callable defined here"); @@ -1862,11 +1864,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - ty::Opaque(new_def_id, _) | ty::Closure(new_def_id, _) | ty::FnDef(new_def_id, _) => { + ty::Opaque(new_def_id, _) + | ty::Closure(new_def_id, _) + | ty::FnDef(new_def_id, _) => { def_id = new_def_id; } _ => { - return; + // Look for a user-provided impl of a `Fn` trait, and point to it. + let new_def_id = self.probe(|_| { + let trait_ref = ty::TraitRef::new( + call_kind.to_def_id(self.tcx), + self.tcx.mk_substs([ + ty::GenericArg::from(callee_ty), + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::MiscVariable, + span: rustc_span::DUMMY_SP, + }) + .into(), + ].into_iter()), + ); + let obligation = traits::Obligation::new( + traits::ObligationCause::dummy(), + self.param_env, + ty::Binder::dummy(ty::TraitPredicate { + trait_ref, + constness: ty::BoundConstness::NotConst, + polarity: ty::ImplPolarity::Positive, + }), + ); + match SelectionContext::new(&self).select(&obligation) { + Ok(Some(traits::ImplSource::UserDefined(impl_source))) => { + Some(impl_source.impl_def_id) + } + _ => None + } + }); + if let Some(new_def_id) = new_def_id { + def_id = new_def_id; + } else { + return; + } } } } @@ -1888,8 +1925,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let def_kind = self.tcx.def_kind(def_id); err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); - } else if let def_kind @ (DefKind::Closure | DefKind::OpaqueTy) = self.tcx.def_kind(def_id) - { + } else { + let def_kind = self.tcx.def_kind(def_id); err.span_note( self.tcx.def_span(def_id), &format!("{} defined here", def_kind.descr(def_id)), diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr index 5ed15468fd64a..475ea9dfaf1b4 100644 --- a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr +++ b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr @@ -5,6 +5,12 @@ LL | let ans = s("what"); | - ^^^^^^ expected `isize`, found `&str` | | | arguments to this function are incorrect + | +note: implementation defined here + --> $DIR/overloaded-calls-bad.rs:10:1 + | +LL | impl FnMut<(isize,)> for S { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0057]: this function takes 1 argument but 0 arguments were supplied --> $DIR/overloaded-calls-bad.rs:29:15 @@ -12,6 +18,11 @@ error[E0057]: this function takes 1 argument but 0 arguments were supplied LL | let ans = s(); | ^-- an argument of type `isize` is missing | +note: implementation defined here + --> $DIR/overloaded-calls-bad.rs:10:1 + | +LL | impl FnMut<(isize,)> for S { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: provide the argument | LL | let ans = s(/* isize */); @@ -25,6 +36,11 @@ LL | let ans = s("burma", "shave"); | | | expected `isize`, found `&str` | +note: implementation defined here + --> $DIR/overloaded-calls-bad.rs:10:1 + | +LL | impl FnMut<(isize,)> for S { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the extra argument | LL | let ans = s(/* isize */);