Skip to content

Commit

Permalink
Merge pull request #1083 from kngwyu/async
Browse files Browse the repository at this point in the history
Complete async fn
  • Loading branch information
kngwyu committed Nov 23, 2019
2 parents 39ab1c5 + 4e8d38f commit c2255dc
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 41 deletions.
33 changes: 23 additions & 10 deletions src/racer/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1137,13 +1137,11 @@ pub fn parse_pat_idents(s: String) -> Vec<ByteRange> {
v.ident_points
}

pub fn parse_fn_output(s: String, scope: Scope) -> Option<Ty> {
let mut v = FnOutputVisitor {
result: None,
scope,
};
pub fn parse_fn_output(s: String, scope: Scope) -> (Option<Ty>, bool) {
let mut v = FnOutputVisitor::new(scope);
with_stmt(s, |stmt| visit::walk_stmt(&mut v, stmt));
v.result
let FnOutputVisitor { ty, is_async, .. } = v;
(ty, is_async)
}

pub fn parse_extern_crate(s: String) -> ExternCrateVisitor {
Expand Down Expand Up @@ -1212,20 +1210,35 @@ pub fn get_match_arm_type(

pub struct FnOutputVisitor {
scope: Scope,
pub result: Option<Ty>,
pub ty: Option<Ty>,
pub is_async: bool,
}

impl FnOutputVisitor {
pub(crate) fn new(scope: Scope) -> Self {
FnOutputVisitor {
scope,
ty: None,
is_async: false,
}
}
}

impl<'ast> visit::Visitor<'ast> for FnOutputVisitor {
fn visit_fn(
&mut self,
_: visit::FnKind<'_>,
kind: visit::FnKind<'_>,
fd: &ast::FnDecl,
_: source_map::Span,
_: ast::NodeId,
) {
self.result = match fd.output {
self.is_async = kind
.header()
.map(|header| header.asyncness.node.is_async())
.unwrap_or(false);
self.ty = match fd.output {
FunctionRetTy::Ty(ref ty) => Ty::from_ast(ty, &self.scope),
FunctionRetTy::Default(_) => None,
FunctionRetTy::Default(_) => Some(Ty::Default),
};
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/racer/ast_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ pub enum Ty {
Ptr(Box<Ty>, Mutability),
TraitObject(TraitBounds),
Self_(Scope),
Future(Box<Ty>, Scope),
Never,
Default,
Unsupported,
}

Expand Down Expand Up @@ -249,6 +252,9 @@ impl fmt::Display for Ty {
write!(f, ">")
}
Ty::Self_(_) => write!(f, "Self"),
Ty::Future(ref ty, _) => write!(f, "impl Future<Output={}>", ty),
Ty::Never => write!(f, "!"),
Ty::Default => write!(f, "()"),
Ty::Unsupported => write!(f, "_"),
}
}
Expand Down
Empty file modified src/racer/lib.rs
100644 → 100755
Empty file.
2 changes: 1 addition & 1 deletion src/racer/matchers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ fn match_fn_common(
context: &MatchCxt<'_, '_>,
session: &Session<'_>,
) -> Option<Match> {
let (start, s) = context.get_key_ident(blob, "fn", &["const", "unsafe"])?;
let (start, s) = context.get_key_ident(blob, "fn", &["const", "unsafe", "async"])?;
let start = context.range.start + start;
let doc_src = session.load_raw_src_ranged(&msrc, context.filepath);
Some(Match {
Expand Down
26 changes: 23 additions & 3 deletions src/racer/nameres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::matchers::{find_doc, ImportInfo, MatchCxt};
use crate::primitive;
use crate::util::{
self, calculate_str_hash, find_ident_end, get_rust_src_path, strip_words, symbol_matches,
trim_visibility, txt_matches,
trim_visibility, txt_matches, txt_matches_with_pos,
};
use crate::{ast, core, matchers, scopes, typeinf};

Expand Down Expand Up @@ -660,7 +660,7 @@ fn search_scope_headers(
// TODO: handle extern ".." fn
fn preblock_is_fn(preblock: &str) -> bool {
let s = trim_visibility(preblock);
let p = strip_words(s, &["const", "unsafe"]);
let p = strip_words(s, &["const", "unsafe", "async"]);
if p.0 < s.len() {
s[p.0..].starts_with("fn")
} else {
Expand All @@ -672,6 +672,7 @@ fn preblock_is_fn(preblock: &str) -> bool {
fn is_fn() {
assert!(preblock_is_fn("pub fn bar()"));
assert!(preblock_is_fn("fn foo()"));
assert!(preblock_is_fn("async fn foo()"));
assert!(preblock_is_fn("const fn baz()"));
assert!(preblock_is_fn("pub(crate) fn bar()"));
assert!(preblock_is_fn("pub(in foo::bar) fn bar()"));
Expand Down Expand Up @@ -2370,10 +2371,28 @@ pub(crate) fn get_field_matches_from_ty(
.into_iter()
.flat_map(|ps| get_field_matches_from_ty(Ty::PathSearch(ps), searchstr, stype, session))
.collect(),
Ty::Future(_, scope) => get_future(scope, session)
.into_iter()
.flat_map(|f| search_for_trait_methods(f, searchstr, stype, session))
.chain(
txt_matches_with_pos(stype, searchstr, "await")
.and_then(|_| PrimKind::Await.to_doc_match(session))
.into_iter(),
)
.collect(),
_ => vec![],
}
}

fn get_future(scope: Scope, session: &Session<'_>) -> Option<Match> {
let path = RacerPath::from_iter(
false,
["std", "future", "Future"].iter().map(|s| s.to_string()),
);

ast::find_type_match(&path, &scope.filepath, scope.point, session)
}

fn get_assoc_type_from_header(
target_path: &RacerPath, // type target = ~
type_match: &Match, // the type which implements trait
Expand Down Expand Up @@ -2424,11 +2443,12 @@ fn get_std_macros(
for macro_file in &[
"libstd/macros.rs",
"libcore/macros.rs",
"libcore/macros/mod.rs",
"liballoc/macros.rs",
] {
let macro_path = std_path.join(macro_file);
if !macro_path.exists() {
return;
continue;
}
get_std_macros_(
&macro_path,
Expand Down
28 changes: 23 additions & 5 deletions src/racer/primitive.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::ast_types::PathSegment;
use crate::core::{BytePos, Match, MatchType, Namespace, SearchType, Session};
use crate::matchers::ImportInfo;
use crate::nameres::{self, RUST_SRC_PATH};
use std::path::PathBuf;
use syntax::ast::{IntTy, LitIntType, UintTy};

const PRIM_DOC: &str = "libstd/primitive_docs.rs";
const KEY_DOC: &str = "libstd/keyword_docs.rs";

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum PrimKind {
Expand Down Expand Up @@ -34,6 +34,7 @@ pub enum PrimKind {
Usize,
Ref,
Fn,
Await,
}

const PRIM_MATCHES: [PrimKind; 17] = [
Expand Down Expand Up @@ -105,6 +106,13 @@ impl PrimKind {
PrimKind::Usize => Some(&["libcore/num/mod.rs"]),
PrimKind::Ref => None,
PrimKind::Fn => None,
PrimKind::Await => None,
}
}
fn is_keyword(self) -> bool {
match self {
PrimKind::Await => true,
_ => false,
}
}
fn match_name(self) -> &'static str {
Expand Down Expand Up @@ -134,6 +142,7 @@ impl PrimKind {
PrimKind::Usize => "usize",
PrimKind::Ref => "ref",
PrimKind::Fn => "fn",
PrimKind::Await => "await",
}
}
pub(crate) fn get_impl_files(&self) -> Option<Vec<PathBuf>> {
Expand All @@ -155,12 +164,21 @@ impl PrimKind {
})
}
pub fn to_doc_match(self, session: &Session<'_>) -> Option<Match> {
let seg: PathSegment = format!("prim_{}", self.match_name()).into();
let src_path = RUST_SRC_PATH.as_ref()?;
let prim_path = src_path.join(PRIM_DOC);
let (path, seg) = if self.is_keyword() {
(
src_path.join(KEY_DOC),
format!("{}_keyword", self.match_name()),
)
} else {
(
src_path.join(PRIM_DOC),
format!("prim_{}", self.match_name()),
)
};
let mut m = nameres::resolve_name(
&seg,
&prim_path,
&seg.into(),
&path,
BytePos::ZERO,
SearchType::ExactMatch,
Namespace::Mod,
Expand Down
50 changes: 28 additions & 22 deletions src/racer/typeinf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,32 +520,38 @@ pub fn get_return_type_of_function(
) -> Option<Ty> {
let src = session.load_source_file(&fnmatch.filepath);
let point = scopes::expect_stmt_start(src.as_src(), fnmatch.point);
let out = src[point.0..].find('{').and_then(|n| {
// wrap in "impl b { }" so that methods get parsed correctly too
let decl = "impl b{".to_string() + &src[point.0..point.0 + n + 1] + "}}";
debug!("get_return_type_of_function: passing in |{}|", decl);
let mut scope = Scope::from_match(fnmatch);
// TODO(kngwyu): if point <= 5 scope is incorrect
scope.point = point.checked_sub("impl b{".len()).unwrap_or(BytePos::ZERO);
ast::parse_fn_output(decl, scope)
});
// Convert output arg of type Self to the correct type
if let Some(Ty::PathSearch(ref paths)) = out {
let path = &paths.path;
if let Some(ref path_seg) = path.segments.get(0) {
if "Self" == path_seg.name {
return get_type_of_self_arg(fnmatch, src.as_src(), session);
}
if path.segments.len() == 1 && path_seg.generics.is_empty() {
for type_param in fnmatch.generics() {
if type_param.name() == &path_seg.name {
return Some(Ty::Match(contextm.clone()));
let block_start = src[point.0..].find('{')?;
let decl = "impl b{".to_string() + &src[point.0..point.0 + block_start + 1] + "}}";
debug!("get_return_type_of_function: passing in |{}|", decl);
let mut scope = Scope::from_match(fnmatch);
// TODO(kngwyu): if point <= 5 scope is incorrect
scope.point = point.checked_sub("impl b{".len()).unwrap_or(BytePos::ZERO);
let (ty, is_async) = ast::parse_fn_output(decl, scope);
let resolve_ty = |ty| {
if let Some(Ty::PathSearch(ref paths)) = ty {
let path = &paths.path;
if let Some(ref path_seg) = path.segments.get(0) {
if "Self" == path_seg.name {
return get_type_of_self_arg(fnmatch, src.as_src(), session);
}
if path.segments.len() == 1 && path_seg.generics.is_empty() {
for type_param in fnmatch.generics() {
if type_param.name() == &path_seg.name {
return Some(Ty::Match(contextm.clone()));
}
}
}
}
}
}
out
ty
};
resolve_ty(ty).map(|ty| {
if is_async {
Ty::Future(Box::new(ty), Scope::from_match(fnmatch))
} else {
ty
}
})
}

pub(crate) fn get_type_of_indexed_value(body: Ty, session: &Session<'_>) -> Option<Ty> {
Expand Down
45 changes: 45 additions & 0 deletions tests/async.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use racer_testutils::*;

#[test]
fn completes_async_fn() {
let src = r#"
async fn say_hey() {
println!("Hey!")
}
fn main() {
say_h~
}
"#;
let got = get_only_completion(src, None);
assert_eq!(got.matchstr, "say_hey");
}

#[test]
fn completes_poll() {
let src = r#"
async fn say_hey() {
println!("Hey!")
}
async fn waiting_for() {
let handle = say_hey();
handle.po~
}
"#;
let got = get_only_completion(src, None);
assert_eq!(got.matchstr, "poll");
}

#[test]
fn completes_await() {
let src = r#"
async fn say_hey() {
println!("Hey!")
}
async fn waiting_for() {
let handle = say_hey();
handle.awa~
}
"#;
let got = get_only_completion(src, None);
assert_eq!(got.matchstr, "await");
}

0 comments on commit c2255dc

Please sign in to comment.