]> git.lizzy.rs Git - rust.git/commitdiff
Account for arbitrary self types in E0599
authorEsteban Küber <esteban@kuber.com.ar>
Wed, 19 Feb 2020 23:57:21 +0000 (15:57 -0800)
committerEsteban Küber <esteban@kuber.com.ar>
Fri, 28 Feb 2020 19:37:59 +0000 (11:37 -0800)
src/librustc_typeck/check/method/suggest.rs
src/test/ui/issues/issue-5153.stderr
src/test/ui/object-pointer-types.stderr
src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr

index 410b8883a29d98b4db45ff2761b7ce39c09cf673..cfd6356b0a1579def18e5df275ff9c7f3d43ef21 100644 (file)
@@ -16,6 +16,7 @@
 use rustc_hir::{ExprKind, Node, QPath};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::traits::Obligation;
+use rustc_span::symbol::kw;
 use rustc_span::{source_map, FileName, Span};
 use syntax::ast;
 use syntax::util::lev_distance;
@@ -893,6 +894,7 @@ fn suggest_traits_to_import<'b>(
 
         let type_is_local = self.type_derefs_to_local(span, rcvr_ty, source);
 
+        let mut arbitrary_rcvr = vec![];
         // There are no traits implemented, so lets suggest some traits to
         // implement, by finding ones that have the item name, and are
         // legal to implement.
@@ -909,12 +911,61 @@ fn suggest_traits_to_import<'b>(
                     && self
                         .associated_item(info.def_id, item_name, Namespace::ValueNS)
                         .filter(|item| {
+                            if let ty::AssocKind::Method = item.kind {
+                                let id = self.tcx.hir().as_local_hir_id(item.def_id);
+                                if let Some(hir::Node::TraitItem(hir::TraitItem {
+                                    kind: hir::TraitItemKind::Method(fn_sig, method),
+                                    ..
+                                })) = id.map(|id| self.tcx.hir().get(id))
+                                {
+                                    let self_first_arg = match method {
+                                        hir::TraitMethod::Required([ident, ..]) => {
+                                            ident.name == kw::SelfLower
+                                        }
+                                        hir::TraitMethod::Provided(body_id) => {
+                                            match &self.tcx.hir().body(*body_id).params[..] {
+                                                [hir::Param {
+                                                    pat:
+                                                        hir::Pat {
+                                                            kind:
+                                                                hir::PatKind::Binding(
+                                                                    _,
+                                                                    _,
+                                                                    ident,
+                                                                    ..,
+                                                                ),
+                                                            ..
+                                                        },
+                                                    ..
+                                                }, ..] => ident.name == kw::SelfLower,
+                                                _ => false,
+                                            }
+                                        }
+                                        _ => false,
+                                    };
+
+                                    if !fn_sig.decl.implicit_self.has_implicit_self()
+                                        && self_first_arg
+                                    {
+                                        if let Some(ty) = fn_sig.decl.inputs.get(0) {
+                                            arbitrary_rcvr.push(ty.span);
+                                        }
+                                        return false;
+                                    }
+                                }
+                            }
                             // We only want to suggest public or local traits (#45781).
                             item.vis == ty::Visibility::Public || info.def_id.is_local()
                         })
                         .is_some()
             })
             .collect::<Vec<_>>();
+        for span in &arbitrary_rcvr {
+            err.span_label(
+                *span,
+                "the method might not be found because of this arbitrary self type",
+            );
+        }
 
         if !candidates.is_empty() {
             // Sort from most relevant to least relevant.
index 44ef73550f8a4f1242be8652cf5c916ff58b6955..93aaf4b9d823758dd83840a8fb5327e79e228613 100644 (file)
@@ -1,13 +1,11 @@
 error[E0599]: no method named `foo` found for reference `&dyn Foo` in the current scope
   --> $DIR/issue-5153.rs:10:27
    |
-LL | trait Foo {
-   | --------- `Foo` defines an item `foo`, perhaps you need to implement it
+LL |     fn foo(self: Box<Self>);
+   |                  --------- the method might not be found because of this arbitrary self type
 ...
 LL |     (&5isize as &dyn Foo).foo();
    |                           ^^^ method not found in `&dyn Foo`
-   |
-   = help: items from traits can only be used if the trait is implemented and in scope
 
 error: aborting due to previous error
 
index 07b7da94097b502f79c41d817254dfc681b31d85..021aa8670f78f7b46027091c63ea6c4e008247fb 100644 (file)
@@ -1,24 +1,20 @@
 error[E0599]: no method named `owned` found for reference `&dyn Foo` in the current scope
   --> $DIR/object-pointer-types.rs:11:7
    |
-LL | trait Foo {
-   | --------- `Foo` defines an item `owned`, perhaps you need to implement it
+LL |     fn owned(self: Box<Self>);
+   |                    --------- the method might not be found because of this arbitrary self type
 ...
 LL |     x.owned();
    |       ^^^^^ method not found in `&dyn Foo`
-   |
-   = help: items from traits can only be used if the trait is implemented and in scope
 
 error[E0599]: no method named `owned` found for mutable reference `&mut dyn Foo` in the current scope
   --> $DIR/object-pointer-types.rs:17:7
    |
-LL | trait Foo {
-   | --------- `Foo` defines an item `owned`, perhaps you need to implement it
+LL |     fn owned(self: Box<Self>);
+   |                    --------- the method might not be found because of this arbitrary self type
 ...
 LL |     x.owned();
    |       ^^^^^ method not found in `&mut dyn Foo`
-   |
-   = help: items from traits can only be used if the trait is implemented and in scope
 
 error[E0599]: no method named `managed` found for struct `std::boxed::Box<(dyn Foo + 'static)>` in the current scope
   --> $DIR/object-pointer-types.rs:23:7
index 999bbcca6bcb97e6ace90b135a288424c74308de..37873031da3e982ad9847868c3023f2e0d9ea917 100644 (file)
@@ -2,16 +2,14 @@ error[E0599]: no method named `foo` found for struct `A` in the current scope
   --> $DIR/point-at-arbitrary-self-type-trait-method.rs:9:7
    |
 LL | trait B { fn foo(self: Box<Self>); }
-   | -------      --- the method is available for `std::boxed::Box<A>` here
-   | |
-   | `B` defines an item `foo`, perhaps you need to implement it
+   |              ---       --------- the method might not be found because of this arbitrary self type
+   |              |
+   |              the method is available for `std::boxed::Box<A>` here
 LL | struct A;
    | --------- method `foo` not found for this
 ...
 LL |     A.foo()
    |       ^^^ method not found in `A`
-   |
-   = help: items from traits can only be used if the trait is implemented and in scope
 
 error: aborting due to previous error