]> git.lizzy.rs Git - rust.git/commitdiff
Hide unnecessary reference to trait
authorEsteban Küber <esteban@kuber.com.ar>
Tue, 30 Mar 2021 02:53:48 +0000 (19:53 -0700)
committerEsteban Küber <esteban@kuber.com.ar>
Tue, 30 Mar 2021 03:39:42 +0000 (20:39 -0700)
When the problem for a method not being found in its receiver is due to
arbitrary self-types, we don't want to mention importing or implementing
the trait, instead we suggest wrapping.

compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/method/suggest.rs
compiler/rustc_typeck/src/check/pat.rs
src/test/ui/async-await/pin-needed-to-poll.stderr

index 9a2e933eb0b44d6fdc8cb29c58297e304bdd7b5b..30d60514063d993b29f6c1de36075c9d8c288b89 100644 (file)
@@ -6,7 +6,7 @@
 use crate::check::cast;
 use crate::check::coercion::CoerceMany;
 use crate::check::fatally_break_rust;
-use crate::check::method::{probe, MethodError, SelfSource};
+use crate::check::method::SelfSource;
 use crate::check::report_unexpected_variant_res;
 use crate::check::BreakableCtxt;
 use crate::check::Diverges;
@@ -30,7 +30,6 @@
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, QPath};
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -461,7 +460,11 @@ fn check_lang_item_path(
         self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1
     }
 
-    fn check_expr_path(&self, qpath: &hir::QPath<'_>, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
+    fn check_expr_path(
+        &self,
+        qpath: &'tcx hir::QPath<'tcx>,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let (res, opt_ty, segs) = self.resolve_ty_and_res_ufcs(qpath, expr.hir_id, expr.span);
         let ty = match res {
@@ -947,7 +950,16 @@ fn check_method_call(
             }
             Err(error) => {
                 if segment.ident.name != kw::Empty {
-                    self.report_extended_method_error(segment, span, args, rcvr_t, error);
+                    if let Some(mut err) = self.report_method_error(
+                        span,
+                        rcvr_t,
+                        segment.ident,
+                        SelfSource::MethodCall(&args[0]),
+                        error,
+                        Some(args),
+                    ) {
+                        err.emit();
+                    }
                 }
                 Err(())
             }
@@ -964,82 +976,6 @@ fn check_method_call(
         )
     }
 
-    fn report_extended_method_error(
-        &self,
-        segment: &hir::PathSegment<'_>,
-        span: Span,
-        args: &'tcx [hir::Expr<'tcx>],
-        rcvr_t: Ty<'tcx>,
-        error: MethodError<'tcx>,
-    ) {
-        let rcvr = &args[0];
-        let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, new_rcvr_t, pre: &str, post: &str| {
-            if let Some(new_rcvr_t) = new_rcvr_t {
-                if let Ok(pick) = self.lookup_probe(
-                    span,
-                    segment.ident,
-                    new_rcvr_t,
-                    rcvr,
-                    probe::ProbeScope::AllTraits,
-                ) {
-                    debug!("try_alt_rcvr: pick candidate {:?}", pick);
-                    // Make sure the method is defined for the *actual* receiver:
-                    // we don't want to treat `Box<Self>` as a receiver if
-                    // it only works because of an autoderef to `&self`
-                    if pick.autoderefs == 0
-                        // We don't want to suggest a container type when the missing method is
-                        // `.clone()`, otherwise we'd suggest `Arc::new(foo).clone()`, which is
-                        // far from what the user really wants.
-                        && Some(pick.item.container.id()) != self.tcx.lang_items().clone_trait()
-                    {
-                        err.span_label(
-                            pick.item.ident.span,
-                            &format!("the method is available for `{}` here", new_rcvr_t),
-                        );
-                        err.multipart_suggestion(
-                            "consider wrapping the receiver expression with the appropriate type",
-                            vec![
-                                (rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)),
-                                (rcvr.span.shrink_to_hi(), ")".to_string()),
-                            ],
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                }
-            }
-        };
-
-        if let Some(mut err) = self.report_method_error(
-            span,
-            rcvr_t,
-            segment.ident,
-            SelfSource::MethodCall(rcvr),
-            error,
-            Some(args),
-        ) {
-            if let ty::Adt(..) = rcvr_t.kind() {
-                // Try alternative arbitrary self types that could fulfill this call.
-                // FIXME: probe for all types that *could* be arbitrary self-types, not
-                // just this list.
-                for (rcvr_t, post) in &[
-                    (rcvr_t, ""),
-                    (self.tcx.mk_mut_ref(&ty::ReErased, rcvr_t), "&mut "),
-                    (self.tcx.mk_imm_ref(&ty::ReErased, rcvr_t), "&"),
-                ] {
-                    for (rcvr_t, pre) in &[
-                        (self.tcx.mk_lang_item(rcvr_t, LangItem::OwnedBox), "Box::new"),
-                        (self.tcx.mk_lang_item(rcvr_t, LangItem::Pin), "Pin::new"),
-                        (self.tcx.mk_diagnostic_item(rcvr_t, sym::Arc), "Arc::new"),
-                        (self.tcx.mk_diagnostic_item(rcvr_t, sym::Rc), "Rc::new"),
-                    ] {
-                        try_alt_rcvr(&mut err, *rcvr_t, pre, post);
-                    }
-                }
-            }
-            err.emit();
-        }
-    }
-
     fn check_expr_cast(
         &self,
         e: &'tcx hir::Expr<'tcx>,
index e64d8367676b0e90ae94d1fb4985d684795aaef0..a7a412f06becc706a24d9f6c294162de27bc6f78 100644 (file)
@@ -905,12 +905,12 @@ pub(in super::super) fn resolve_lang_item_path(
 
     /// Resolves an associated value path into a base type and associated constant, or method
     /// resolution. The newly resolved definition is written into `type_dependent_defs`.
-    pub fn resolve_ty_and_res_ufcs<'b>(
+    pub fn resolve_ty_and_res_ufcs(
         &self,
-        qpath: &'b QPath<'b>,
+        qpath: &'tcx QPath<'tcx>,
         hir_id: hir::HirId,
         span: Span,
-    ) -> (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]) {
+    ) -> (Res, Option<Ty<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) {
         debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span);
         let (ty, qself, item_segment) = match *qpath {
             QPath::Resolved(ref opt_qself, ref path) => {
index 13757ac41325b245a8e83f10e6235d3a83d67edc..72eff009473a11b26b2c6d8ad6b4392cc0cc417a 100644 (file)
@@ -68,12 +68,12 @@ fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
         }
     }
 
-    pub fn report_method_error<'b>(
+    pub fn report_method_error(
         &self,
         span: Span,
         rcvr_ty: Ty<'tcx>,
         item_name: Ident,
-        source: SelfSource<'b>,
+        source: SelfSource<'tcx>,
         error: MethodError<'tcx>,
         args: Option<&'tcx [hir::Expr<'tcx>]>,
     ) -> Option<DiagnosticBuilder<'_>> {
@@ -323,8 +323,8 @@ pub fn report_method_error<'b>(
                                 err.span_suggestion(
                                     lit.span,
                                     &format!(
-                                        "you must specify a concrete type for \
-                                              this numeric value, like `{}`",
+                                        "you must specify a concrete type for this numeric value, \
+                                         like `{}`",
                                         concrete_type
                                     ),
                                     format!("{}_{}", snippet, concrete_type),
@@ -975,17 +975,78 @@ fn suggest_valid_traits(
         }
     }
 
-    fn suggest_traits_to_import<'b>(
+    fn suggest_traits_to_import(
         &self,
         err: &mut DiagnosticBuilder<'_>,
         span: Span,
         rcvr_ty: Ty<'tcx>,
         item_name: Ident,
-        source: SelfSource<'b>,
+        source: SelfSource<'tcx>,
         valid_out_of_scope_traits: Vec<DefId>,
         unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)],
     ) {
-        if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
+        let mut alt_rcvr_sugg = false;
+        if let SelfSource::MethodCall(rcvr) = source {
+            info!(?span, ?item_name, ?rcvr_ty, ?rcvr);
+            if let ty::Adt(..) = rcvr_ty.kind() {
+                // Try alternative arbitrary self types that could fulfill this call.
+                // FIXME: probe for all types that *could* be arbitrary self-types, not
+                // just this list.
+                for (rcvr_ty, post) in &[
+                    (rcvr_ty, ""),
+                    (self.tcx.mk_mut_ref(&ty::ReErased, rcvr_ty), "&mut "),
+                    (self.tcx.mk_imm_ref(&ty::ReErased, rcvr_ty), "&"),
+                ] {
+                    for (rcvr_ty, pre) in &[
+                        (self.tcx.mk_lang_item(rcvr_ty, LangItem::OwnedBox), "Box::new"),
+                        (self.tcx.mk_lang_item(rcvr_ty, LangItem::Pin), "Pin::new"),
+                        (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Arc), "Arc::new"),
+                        (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Rc), "Rc::new"),
+                    ] {
+                        if let Some(new_rcvr_t) = *rcvr_ty {
+                            if let Ok(pick) = self.lookup_probe(
+                                span,
+                                item_name,
+                                new_rcvr_t,
+                                rcvr,
+                                crate::check::method::probe::ProbeScope::AllTraits,
+                            ) {
+                                debug!("try_alt_rcvr: pick candidate {:?}", pick);
+                                // Make sure the method is defined for the *actual* receiver:
+                                // we don't want to treat `Box<Self>` as a receiver if
+                                // it only works because of an autoderef to `&self`
+                                if pick.autoderefs == 0
+                                    // We don't want to suggest a container type when the missing method is
+                                    // `.clone()`, otherwise we'd suggest `Arc::new(foo).clone()`, which is
+                                    // far from what the user really wants.
+                                    && Some(pick.item.container.id()) != self.tcx.lang_items().clone_trait()
+                                {
+                                    err.span_label(
+                                        pick.item.ident.span,
+                                        &format!(
+                                            "the method is available for `{}` here",
+                                            new_rcvr_t
+                                        ),
+                                    );
+                                    err.multipart_suggestion(
+                                        "consider wrapping the receiver expression with the \
+                                         appropriate type",
+                                        vec![
+                                            (rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)),
+                                            (rcvr.span.shrink_to_hi(), ")".to_string()),
+                                        ],
+                                        Applicability::MaybeIncorrect,
+                                    );
+                                    // We don't care about the other suggestions.
+                                    alt_rcvr_sugg = true;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if !alt_rcvr_sugg && self.suggest_valid_traits(err, valid_out_of_scope_traits) {
             return;
         }
 
@@ -1075,6 +1136,9 @@ fn suggest_traits_to_import<'b>(
                 "the method might not be found because of this arbitrary self type",
             );
         }
+        if alt_rcvr_sugg {
+            return;
+        }
 
         if !candidates.is_empty() {
             // Sort from most relevant to least relevant.
@@ -1284,7 +1348,12 @@ fn suggest_traits_to_import<'b>(
 
     /// Checks whether there is a local type somewhere in the chain of
     /// autoderefs of `rcvr_ty`.
-    fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'_>) -> bool {
+    fn type_derefs_to_local(
+        &self,
+        span: Span,
+        rcvr_ty: Ty<'tcx>,
+        source: SelfSource<'tcx>,
+    ) -> bool {
         fn is_local(ty: Ty<'_>) -> bool {
             match ty.kind() {
                 ty::Adt(def, _) => def.did.is_local(),
@@ -1310,7 +1379,7 @@ fn is_local(ty: Ty<'_>) -> bool {
     }
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
 pub enum SelfSource<'a> {
     QPath(&'a hir::Ty<'a>),
     MethodCall(&'a hir::Expr<'a> /* rcvr */),
index 79c544bd3860556ff9de4e165ff1869daf9a587f..53593b9bab4b82a184704ebbc1c2d611e91e1109 100644 (file)
@@ -861,7 +861,7 @@ fn emit_bad_pat_path(
     fn check_pat_tuple_struct(
         &self,
         pat: &'tcx Pat<'tcx>,
-        qpath: &hir::QPath<'_>,
+        qpath: &'tcx hir::QPath<'tcx>,
         subpats: &'tcx [&'tcx Pat<'tcx>],
         ddpos: Option<usize>,
         expected: Ty<'tcx>,
index 0e3716d6156accbfbcfd01d1c26cd04a264337f8..0756a4d59c19b1fe3d19f16d72d540a7bb1d9e70 100644 (file)
@@ -12,9 +12,6 @@ LL |         self.sleep.poll(cx)
 LL |     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
    |        ---- the method is available for `Pin<&mut Sleep>` here
    |
-   = help: items from traits can only be used if the trait is implemented and in scope
-   = note: the following trait defines an item `poll`, perhaps you need to implement it:
-           candidate #1: `Future`
 help: consider wrapping the receiver expression with the appropriate type
    |
 LL |         Pin::new(&mut self.sleep).poll(cx)