Repository: racer-rust/racer (language: rust)

Issue:
Not handle Box<Trait + Send>
Consider such code:

```Rust
pub trait Foo {
    fn foo(&self);
}

fn get_foo() -> Box<Foo + Send> {
    unimplemented!();
}

fn main() {
    let mut t = get_foo();
    t.foo();//X
}
```
if I place cursor at `foo` at **line X**, and execute `racer-find-definition`,
it returns "No definition found", also no completion if I type `t.` 

But if replace ` Box<Foo + Send>` with ` Box<Foo>` all works fine.

So looks like racer doesn't like `Box<Trait + Send>`?

I use racer 2.0.14.


Discussion / hints:
Thanks for reporting, it sounds weird...


Fix patch:
diff --git a/src/racer/ast_types.rs b/src/racer/ast_types.rs
index d40484f2..a165cfa3 100644
--- a/src/racer/ast_types.rs
+++ b/src/racer/ast_types.rs
@@ -49,6 +49,7 @@ pub enum Ty {
     RefPtr(Box<Ty>, Mutability),
     Slice(Box<Ty>),
     Ptr(Box<Ty>, Mutability),
+    TraitObject(TraitBounds),
     Unsupported,
 }
 
@@ -109,6 +110,9 @@ impl Ty {
                 Ty::from_ast(&*ty.ty, scope).map(|rty| Ty::Ptr(Box::new(rty), ty.mutbl))
             }
             TyKind::Never => None,
+            TyKind::TraitObject(ref traits, _) => {
+                Some(Ty::TraitObject(TraitBounds::from_generic_bounds(&traits, scope.filepath.clone(), ty.span.lo().0 as i32)))
+            }
             _ => {
                 trace!("unhandled Ty node: {:?}", ty.node);
                 None
@@ -173,6 +177,18 @@ impl fmt::Display for Ty {
                 Mutability::Immutable => write!(f, "*const {}", ty),
                 Mutability::Mutable => write!(f, "*mut {}", ty),
             },
+            Ty::TraitObject(ref bounds) => {
+                write!(f, "<")?;
+                let last = bounds.len() - 1;
+                for (i, ps) in bounds.iter().enumerate() {
+                    if i == last {
+                        write!(f, "{}", ps.path)?;
+                    } else {
+                        write!(f, "{},", ps.path)?;
+                    }
+                }
+                write!(f, ">")
+            }
             Ty::Unsupported => write!(f, "_"),
         }
     }
@@ -545,6 +561,14 @@ impl TraitBounds {
         })
     }
     
+    pub fn iter(&self) -> impl Iterator<Item=&PathSearch> {
+        self.0.iter()
+    }
+
+    pub fn into_iter(self) -> impl Iterator<Item=PathSearch> {
+        self.0.into_iter()
+    }
+
     pub fn find_by_name_mut(&mut self, name: &str) -> Option<&mut PathSearch> {
         self.0.iter_mut().find(|path_search| {
             let seg = &path_search.path.segments;
diff --git a/src/racer/nameres.rs b/src/racer/nameres.rs
index d6a3b2ee..9af1f228 100644
--- a/src/racer/nameres.rs
+++ b/src/racer/nameres.rs
@@ -2201,6 +2201,12 @@ pub(crate) fn get_field_matches_from_ty(
             m.matchstr = "[T]".to_owned();
             search_for_field_or_method(m, searchstr, stype, session)
         }
+        Ty::TraitObject(traitbounds) => {
+            traitbounds.into_iter().fold(Vec::new(), |mut out, ps| {
+                out.extend(get_field_matches_from_ty(Ty::PathSearch(ps), searchstr, stype, session));
+                out
+            })
+        }
         _ => vec![],
     }
 }


Test patch:
diff --git a/tests/system.rs b/tests/system.rs
index e063e181..26b56f8a 100644
--- a/tests/system.rs
+++ b/tests/system.rs
@@ -4016,3 +4016,23 @@ fn completes_impl_generic_arg_in_closure() {
     let got = get_one_completion(src, None);
     assert_eq!("clone", got.matchstr);
 }
+
+#[test]
+fn completes_functions_from_trait_objects() {
+    let src = r"
+    pub trait Foo {
+        fn foo(&self);
+    }
+
+    fn get_foo() -> Box<Foo + Send> {
+        unimplemented!();
+    }
+
+    fn main() {
+        let mut t = get_foo();
+        t.f~
+    }
+";
+    let got = get_all_completions(src, None);
+    assert!(got.into_iter().any(|ma| ma.matchstr == "foo"));
+}