about summary refs log tree commit diff
diff options
context:
space:
mode:
authorclubby789 <jamie@hill-daniel.co.uk>2022-09-18 18:45:36 +0100
committerclubby789 <jamie@hill-daniel.co.uk>2022-11-05 22:56:02 +0000
commit87de9bd1088ec0f1a2e8893a517cde2005a546a0 (patch)
tree224b1792f604cbaf3973372db498868d6e5bc7be
parent371100b1fb811e604f7451eff3b06960587fe1af (diff)
downloadrust-87de9bd1088ec0f1a2e8893a517cde2005a546a0.tar.gz
rust-87de9bd1088ec0f1a2e8893a517cde2005a546a0.zip
Prevent auto-application of associated functions with placeholders
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs51
1 files changed, 34 insertions, 17 deletions
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 04ecd2757b4..613acd3d705 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -18,7 +18,7 @@ use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKi
 use rustc_middle::traits::util::supertraits;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::print::with_crate_prefix;
-use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, DefIdTree, GenericArgKind, ToPredicate, Ty, TyCtxt, TypeVisitable};
 use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Symbol;
@@ -392,28 +392,45 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     custom_span_label = true;
                 }
                 if static_candidates.len() == 1 {
-                    let ty_str =
-                        if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) {
-                            // When the "method" is resolved through dereferencing, we really want the
-                            // original type that has the associated function for accurate suggestions.
-                            // (#61411)
-                            let ty = tcx.at(span).type_of(*impl_did);
-                            match (&ty.peel_refs().kind(), &actual.peel_refs().kind()) {
-                                (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => {
-                                    // Use `actual` as it will have more `substs` filled in.
-                                    self.ty_to_value_string(actual.peel_refs())
-                                }
-                                _ => self.ty_to_value_string(ty.peel_refs()),
+                    let (ty_str, placeholders) = if let Some(CandidateSource::Impl(impl_did)) =
+                    static_candidates.get(0)
+                    {
+                        // When the "method" is resolved through dereferencing, we really want the
+                        // original type that has the associated function for accurate suggestions.
+                        // (#61411)
+                        let ty = tcx.at(span).type_of(*impl_did);
+                        match (&ty.peel_refs().kind(), &actual.peel_refs().kind()) {
+                            (ty::Adt(def, _), ty::Adt(def_actual, substs)) if def == def_actual => {
+                                // If there are any inferred arguments, (`{integer}`), we shouldn't mark
+                                // this as machine-applicable.
+                                let placeholders = substs
+                                    .iter()
+                                    .filter_map(|arg| {
+                                        if let GenericArgKind::Type(ty) = arg.unpack() {
+                                            Some(ty)
+                                        } else {
+                                            None
+                                        }
+                                    })
+                                    .any(|ty| matches!(ty.kind(), ty::Infer(_)));
+                                // Use `actual` as it will have more `substs` filled in.
+                                (self.ty_to_value_string(actual.peel_refs()), placeholders)
                             }
-                        } else {
-                            self.ty_to_value_string(actual.peel_refs())
-                        };
+                            _ => (self.ty_to_value_string(ty.peel_refs()), true),
+                        }
+                    } else {
+                        (self.ty_to_value_string(actual.peel_refs()), true)
+                    };
+                    let applicability = match placeholders {
+                        true => Applicability::HasPlaceholders,
+                        false => Applicability::MachineApplicable,
+                    };
                     if let SelfSource::MethodCall(expr) = source {
                         err.span_suggestion(
                             expr.span.to(span),
                             "use associated function syntax instead",
                             format!("{}::{}", ty_str, item_name),
-                            Applicability::MachineApplicable,
+                            applicability,
                         );
                     } else {
                         err.help(&format!("try with `{}::{}`", ty_str, item_name,));