From fcf343269d4a140b8b59dc1f41e2f9a16e89ec7a Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Mon, 30 Nov 2020 21:47:56 +0100 Subject: [PATCH 1/3] Try to naively skip attributes when parsing generics --- src/racer/matchers.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/racer/matchers.rs b/src/racer/matchers.rs index 6868fba8..cf79d9fd 100644 --- a/src/racer/matchers.rs +++ b/src/racer/matchers.rs @@ -425,8 +425,27 @@ fn match_mod_inner( } fn find_generics_end(blob: &str) -> Option { + // Naive version that attempts to skip over attributes + let mut in_attr = false; + let mut attr_level = 0; + let mut level = 0; for (i, b) in blob.as_bytes().into_iter().enumerate() { + // Naively skip attributes `#[...]` + if in_attr { + match b { + b'[' => attr_level += 1, + b']' => { + attr_level -=1; + if attr_level == 0 { + in_attr = false; + continue; + } + }, + _ => continue, + } + } + // ...otherwise just try to find the last `>` match b { b'{' | b'(' | b';' => return None, b'<' => level += 1, @@ -436,6 +455,7 @@ fn find_generics_end(blob: &str) -> Option { return Some(i.into()); } } + b'#' if blob.bytes().nth(i + 1) == Some(b'[') => in_attr = true, _ => {} } } @@ -871,3 +891,24 @@ pub fn match_impl(decl: String, context: &MatchCxt<'_, '_>, offset: BytePos) -> } Some(out) } + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn find_generics_end() { + use super::find_generics_end; + assert_eq!( + find_generics_end("Vec"), + Some(BytePos(64)) + ); + assert_eq!( + find_generics_end("Vec"), + Some(BytePos(27)) + ); + assert_eq!( + find_generics_end("Result, Option<&str>>"), + Some(BytePos(32)) + ); + } +} From e344dd17cf7fe76383a13414c948e86b0af0a407 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Tue, 1 Dec 2020 01:16:14 +0100 Subject: [PATCH 2/3] Account for resolved generics for `Self`-returning methods One concrete example is when we have a partially resolved generic type which calls a `Self`-returning method, e.g. `Vec::new()`. Previously, the returned type for `Self`-returning methods would return the unresolved, generic type as encountered in the impl header (so `Vec` in this case). However, if the method match already carries some information about generics (T := String here), make sure to account for it. --- src/racer/ast.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/racer/ast.rs b/src/racer/ast.rs index 14aefa84..15ff852f 100644 --- a/src/racer/ast.rs +++ b/src/racer/ast.rs @@ -527,7 +527,16 @@ impl<'c, 's, 'ast> visit::Visitor<'ast> for ExprTypeVisitor<'c, 's> { .and_then(|ty| path_to_match(ty, self.session)) } MatchType::Method(ref gen) => { - typeinf::get_return_type_of_function(&m, &m, self.session).and_then( + let mut return_ty = typeinf::get_return_type_of_function(&m, &m, self.session); + // Account for already resolved generics if the return type is Self + // (in which case we return bare type as found in the `impl` header) + if let (Some(Ty::Match(ref mut m)), Some(gen)) = (&mut return_ty, gen) { + let resolved = gen.args().filter_map(|tp| tp.resolved()); + for (l, r) in m.generics_mut().zip(resolved) { + l.resolve(r.clone()); + } + } + return_ty.and_then( |ty| { path_to_match_including_generics( ty, From a67ca96aa869d3df084f22bf3f43988adca355fc Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Tue, 1 Dec 2020 15:07:47 +0100 Subject: [PATCH 3/3] Don't filter out possible unresolved type params Otherwise we may have an order mismatch Co-authored-by: Yuji Kanagawa --- src/racer/ast.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/racer/ast.rs b/src/racer/ast.rs index 15ff852f..d9687a2a 100644 --- a/src/racer/ast.rs +++ b/src/racer/ast.rs @@ -531,9 +531,10 @@ impl<'c, 's, 'ast> visit::Visitor<'ast> for ExprTypeVisitor<'c, 's> { // Account for already resolved generics if the return type is Self // (in which case we return bare type as found in the `impl` header) if let (Some(Ty::Match(ref mut m)), Some(gen)) = (&mut return_ty, gen) { - let resolved = gen.args().filter_map(|tp| tp.resolved()); - for (l, r) in m.generics_mut().zip(resolved) { - l.resolve(r.clone()); + for (type_param, arg) in m.generics_mut().zip(gen.args()) { + if let Some(resolved) = arg.resolved() { + type_param.resolve(resolved.clone()); + } } } return_ty.and_then(