diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 52099102dc2..7ec3d453660 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -13,7 +13,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; -use rustc_hir::{ExprKind, Node, QPath}; +use rustc_hir::{Expr, ExprKind, Node, QPath}; use rustc_infer::infer::{ type_variable::{TypeVariableOrigin, TypeVariableOriginKind}, RegionVariableOrigin, @@ -397,6 +397,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { custom_span_label = true; } if static_candidates.len() == 1 { + let mut has_unsuggestable_args = false; let ty_str = if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) { @@ -412,6 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .into_iter() .map(|arg| { if !arg.is_suggestable(tcx, true) { + has_unsuggestable_args = true; match arg.unpack() { GenericArgKind::Lifetime(_) => self .next_region_var(RegionVariableOrigin::MiscVariable( @@ -450,12 +452,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { self.ty_to_value_string(actual.peel_refs()) }; - if let SelfSource::MethodCall(expr) = source { + if let SelfSource::MethodCall(_) = source { + let first_arg = if let Some(CandidateSource::Impl(impl_did)) = static_sources.get(0) && + let Some(assoc) = self.associated_value(*impl_did, item_name) { + let sig = self.tcx.fn_sig(assoc.def_id); + if let Some(first) = sig.inputs().skip_binder().get(0) { + if first.peel_refs() == rcvr_ty.peel_refs() { + None + } else { + Some(if first.is_region_ptr() { + if first.is_mutable_ptr() { "&mut " } else { "&" } + } else { + "" + }) + } + } else { + None + } + } else { + None + }; + let mut applicability = Applicability::MachineApplicable; + let args = if let Some((receiver, args)) = args { + // The first arg is the same kind as the receiver + let it = if first_arg.is_some() { + Box::new(std::iter::once(receiver).chain(args.iter())) + as Box>> + } else { + // There is no `Self` kind to infer the arguments from + if has_unsuggestable_args { + applicability = Applicability::HasPlaceholders; + } + Box::new(args.iter()) as _ + }; + format!( + "({}{})", + first_arg.unwrap_or(""), + it.map(|arg| tcx + .sess + .source_map() + .span_to_snippet(arg.span) + .unwrap_or_else(|_| { + applicability = Applicability::HasPlaceholders; + "_".to_owned() + })) + .collect::>() + .join(", "), + ) + } else { + applicability = Applicability::HasPlaceholders; + "(...)".to_owned() + }; err.span_suggestion( - expr.span.to(span), + sugg_span, "use associated function syntax instead", - format!("{}::{}", ty_str, item_name), - Applicability::MachineApplicable, + format!("{}::{}{}", ty_str, item_name, args), + applicability, ); } else { err.help(&format!("try with `{}::{}`", ty_str, item_name,)); diff --git a/src/test/ui/issues/issue-3707.stderr b/src/test/ui/issues/issue-3707.stderr index 6ca2deee377..07c8101cbc6 100644 --- a/src/test/ui/issues/issue-3707.stderr +++ b/src/test/ui/issues/issue-3707.stderr @@ -2,10 +2,10 @@ error[E0599]: no method named `boom` found for reference `&Obj` in the current s --> $DIR/issue-3707.rs:10:14 | LL | self.boom(); - | -----^^^^ + | -----^^^^-- | | | | | this is an associated function, not a method - | help: use associated function syntax instead: `Obj::boom` + | help: use associated function syntax instead: `Obj::boom()` | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `Obj` diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr index 996d5773118..7c9f0b6c212 100644 --- a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr +++ b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr @@ -2,10 +2,10 @@ error[E0599]: no method named `hello` found for struct `RefMut<'_, HasAssocMetho --> $DIR/suggest-assoc-fn-call-with-turbofish-through-deref.rs:11:11 | LL | state.hello(); - | ------^^^^^ + | ------^^^^^-- | | | | | this is an associated function, not a method - | help: use associated function syntax instead: `HasAssocMethod::hello` + | help: use associated function syntax instead: `HasAssocMethod::hello()` | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `HasAssocMethod` diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.fixed b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.fixed new file mode 100644 index 00000000000..0398c510fea --- /dev/null +++ b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.fixed @@ -0,0 +1,29 @@ +// run-rustfix + +struct GenericAssocMethod(T); + +impl GenericAssocMethod { + fn default_hello() {} + fn self_ty_hello(_: Self) {} + fn self_ty_ref_hello(_: &Self) {} +} + +fn main() { + // Test for inferred types + let x = GenericAssocMethod(33); + // This particular case is unfixable without more information by the user, + // but `cargo fix --broken-code` reports a bug if + // x.default_hello(); + GenericAssocMethod::<_>::self_ty_ref_hello(&x); + //~^ ERROR no method named `self_ty_ref_hello` found + GenericAssocMethod::<_>::self_ty_hello(x); + //~^ ERROR no method named `self_ty_hello` found + // Test for known types + let y = GenericAssocMethod(33i32); + GenericAssocMethod::::default_hello(); + //~^ ERROR no method named `default_hello` found + GenericAssocMethod::::self_ty_ref_hello(&y); + //~^ ERROR no method named `self_ty_ref_hello` found + GenericAssocMethod::::self_ty_hello(y); + //~^ ERROR no method named `self_ty_hello` found +} diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.rs b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.rs index 213d1c72f9a..8bafc83bdd0 100644 --- a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.rs +++ b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.rs @@ -1,16 +1,19 @@ +// run-rustfix + struct GenericAssocMethod(T); impl GenericAssocMethod { fn default_hello() {} - fn self_ty_hello(_: T) {} - fn self_ty_ref_hello(_: &T) {} + fn self_ty_hello(_: Self) {} + fn self_ty_ref_hello(_: &Self) {} } fn main() { // Test for inferred types let x = GenericAssocMethod(33); - x.default_hello(); - //~^ ERROR no method named `default_hello` found + // This particular case is unfixable without more information by the user, + // but `cargo fix --broken-code` reports a bug if + // x.default_hello(); x.self_ty_ref_hello(); //~^ ERROR no method named `self_ty_ref_hello` found x.self_ty_hello(); diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr index c6d9122228a..e2f2d46b9e8 100644 --- a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr +++ b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish.stderr @@ -1,117 +1,98 @@ -error[E0599]: no method named `default_hello` found for struct `GenericAssocMethod<{integer}>` in the current scope - --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:12:7 - | -LL | struct GenericAssocMethod(T); - | ---------------------------- method `default_hello` not found for this struct -... -LL | x.default_hello(); - | --^^^^^^^^^^^^^ - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::<_>::default_hello` - | - = note: found the following associated functions; to be used as methods, functions must have a `self` parameter -note: the candidate is defined in an impl for the type `GenericAssocMethod` - --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:4:5 - | -LL | fn default_hello() {} - | ^^^^^^^^^^^^^^^^^^ - error[E0599]: no method named `self_ty_ref_hello` found for struct `GenericAssocMethod<{integer}>` in the current scope - --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:14:7 + --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:17:7 | LL | struct GenericAssocMethod(T); | ---------------------------- method `self_ty_ref_hello` not found for this struct ... LL | x.self_ty_ref_hello(); - | --^^^^^^^^^^^^^^^^^ + | --^^^^^^^^^^^^^^^^^-- | | | | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_ref_hello` + | help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_ref_hello(&x)` | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` - --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:6:5 + --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:8:5 | -LL | fn self_ty_ref_hello(_: &T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn self_ty_ref_hello(_: &Self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0599]: no method named `self_ty_hello` found for struct `GenericAssocMethod<{integer}>` in the current scope - --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:16:7 + --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:19:7 | LL | struct GenericAssocMethod(T); | ---------------------------- method `self_ty_hello` not found for this struct ... LL | x.self_ty_hello(); - | --^^^^^^^^^^^^^ + | --^^^^^^^^^^^^^-- | | | | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_hello` + | help: use associated function syntax instead: `GenericAssocMethod::<_>::self_ty_hello(x)` | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` - --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:5:5 + --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:7:5 | -LL | fn self_ty_hello(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | fn self_ty_hello(_: Self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0599]: no method named `default_hello` found for struct `GenericAssocMethod` in the current scope - --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:20:7 + --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:23:7 | LL | struct GenericAssocMethod(T); | ---------------------------- method `default_hello` not found for this struct ... LL | y.default_hello(); - | --^^^^^^^^^^^^^ + | --^^^^^^^^^^^^^-- | | | | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::::default_hello` - | - = note: found the following associated functions; to be used as methods, functions must have a `self` parameter -note: the candidate is defined in an impl for the type `GenericAssocMethod` - --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:4:5 - | -LL | fn default_hello() {} - | ^^^^^^^^^^^^^^^^^^ - -error[E0599]: no method named `self_ty_ref_hello` found for struct `GenericAssocMethod` in the current scope - --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:22:7 - | -LL | struct GenericAssocMethod(T); - | ---------------------------- method `self_ty_ref_hello` not found for this struct -... -LL | y.self_ty_ref_hello(); - | --^^^^^^^^^^^^^^^^^ - | | | - | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::::self_ty_ref_hello` + | help: use associated function syntax instead: `GenericAssocMethod::::default_hello()` | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:6:5 | -LL | fn self_ty_ref_hello(_: &T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn default_hello() {} + | ^^^^^^^^^^^^^^^^^^ + +error[E0599]: no method named `self_ty_ref_hello` found for struct `GenericAssocMethod` in the current scope + --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:25:7 + | +LL | struct GenericAssocMethod(T); + | ---------------------------- method `self_ty_ref_hello` not found for this struct +... +LL | y.self_ty_ref_hello(); + | --^^^^^^^^^^^^^^^^^-- + | | | + | | this is an associated function, not a method + | help: use associated function syntax instead: `GenericAssocMethod::::self_ty_ref_hello(&y)` + | + = note: found the following associated functions; to be used as methods, functions must have a `self` parameter +note: the candidate is defined in an impl for the type `GenericAssocMethod` + --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:8:5 + | +LL | fn self_ty_ref_hello(_: &Self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0599]: no method named `self_ty_hello` found for struct `GenericAssocMethod` in the current scope - --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:24:7 + --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:27:7 | LL | struct GenericAssocMethod(T); | ---------------------------- method `self_ty_hello` not found for this struct ... LL | y.self_ty_hello(); - | --^^^^^^^^^^^^^ + | --^^^^^^^^^^^^^-- | | | | | this is an associated function, not a method - | help: use associated function syntax instead: `GenericAssocMethod::::self_ty_hello` + | help: use associated function syntax instead: `GenericAssocMethod::::self_ty_hello(y)` | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in an impl for the type `GenericAssocMethod` - --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:5:5 + --> $DIR/suggest-assoc-fn-call-with-turbofish.rs:7:5 | -LL | fn self_ty_hello(_: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | fn self_ty_hello(_: Self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0599`.