diff options
Diffstat (limited to 'crates')
24 files changed, 554 insertions, 65 deletions
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml index 467628236..328b2436f 100644 --- a/crates/ra_cli/Cargo.toml +++ b/crates/ra_cli/Cargo.toml | |||
@@ -18,3 +18,4 @@ tools = { path = "../tools" } | |||
18 | ra_batch = { path = "../ra_batch" } | 18 | ra_batch = { path = "../ra_batch" } |
19 | ra_hir = { path = "../ra_hir" } | 19 | ra_hir = { path = "../ra_hir" } |
20 | ra_db = { path = "../ra_db" } | 20 | ra_db = { path = "../ra_db" } |
21 | ra_prof = { path = "../ra_prof" } | ||
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs index 1f2750d89..45555be6e 100644 --- a/crates/ra_cli/src/main.rs +++ b/crates/ra_cli/src/main.rs | |||
@@ -1,12 +1,13 @@ | |||
1 | mod analysis_stats; | 1 | mod analysis_stats; |
2 | 2 | ||
3 | use std::{fs, io::Read, path::Path, time::Instant}; | 3 | use std::{fs, io::Read, path::Path}; |
4 | 4 | ||
5 | use clap::{App, Arg, SubCommand}; | 5 | use clap::{App, Arg, SubCommand}; |
6 | use ra_ide_api::file_structure; | 6 | use ra_ide_api::file_structure; |
7 | use ra_syntax::{SourceFile, TreeArc, AstNode}; | 7 | use ra_syntax::{SourceFile, TreeArc, AstNode}; |
8 | use tools::collect_tests; | 8 | use tools::collect_tests; |
9 | use flexi_logger::Logger; | 9 | use flexi_logger::Logger; |
10 | use ra_prof::profile; | ||
10 | 11 | ||
11 | type Result<T> = ::std::result::Result<T, failure::Error>; | 12 | type Result<T> = ::std::result::Result<T, failure::Error>; |
12 | 13 | ||
@@ -27,13 +28,11 @@ fn main() -> Result<()> { | |||
27 | .get_matches(); | 28 | .get_matches(); |
28 | match matches.subcommand() { | 29 | match matches.subcommand() { |
29 | ("parse", Some(matches)) => { | 30 | ("parse", Some(matches)) => { |
30 | let start = Instant::now(); | 31 | let _p = profile("parsing"); |
31 | let file = file()?; | 32 | let file = file()?; |
32 | let elapsed = start.elapsed(); | ||
33 | if !matches.is_present("no-dump") { | 33 | if !matches.is_present("no-dump") { |
34 | println!("{}", file.syntax().debug_dump()); | 34 | println!("{}", file.syntax().debug_dump()); |
35 | } | 35 | } |
36 | eprintln!("parsing: {:?}", elapsed); | ||
37 | ::std::mem::forget(file); | 36 | ::std::mem::forget(file); |
38 | } | 37 | } |
39 | ("symbols", _) => { | 38 | ("symbols", _) => { |
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index 501308acc..a2858dad9 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml | |||
@@ -19,6 +19,7 @@ ra_db = { path = "../ra_db" } | |||
19 | mbe = { path = "../ra_mbe", package = "ra_mbe" } | 19 | mbe = { path = "../ra_mbe", package = "ra_mbe" } |
20 | tt = { path = "../ra_tt", package = "ra_tt" } | 20 | tt = { path = "../ra_tt", package = "ra_tt" } |
21 | test_utils = { path = "../test_utils" } | 21 | test_utils = { path = "../test_utils" } |
22 | ra_prof = {path = "../ra_prof" } | ||
22 | 23 | ||
23 | [dev-dependencies] | 24 | [dev-dependencies] |
24 | flexi_logger = "0.11.0" | 25 | flexi_logger = "0.11.0" |
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 87d81f4a4..9e6170440 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -429,6 +429,45 @@ impl Docs for EnumVariant { | |||
429 | } | 429 | } |
430 | } | 430 | } |
431 | 431 | ||
432 | /// The defs which have a body. | ||
433 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
434 | pub enum DefWithBody { | ||
435 | Function(Function), | ||
436 | Const(Const), | ||
437 | Static(Static), | ||
438 | } | ||
439 | |||
440 | impl_froms!(DefWithBody: Function, Const, Static); | ||
441 | |||
442 | impl DefWithBody { | ||
443 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { | ||
444 | db.infer(*self) | ||
445 | } | ||
446 | |||
447 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
448 | db.body_with_source_map(*self).1 | ||
449 | } | ||
450 | |||
451 | pub fn body(&self, db: &impl HirDatabase) -> Arc<Body> { | ||
452 | db.body_hir(*self) | ||
453 | } | ||
454 | |||
455 | /// Builds a resolver for code inside this item. | ||
456 | pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { | ||
457 | match *self { | ||
458 | DefWithBody::Const(ref c) => c.resolver(db), | ||
459 | DefWithBody::Function(ref f) => f.resolver(db), | ||
460 | DefWithBody::Static(ref s) => s.resolver(db), | ||
461 | } | ||
462 | } | ||
463 | |||
464 | pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSourceMap { | ||
465 | let scopes = db.expr_scopes(*self); | ||
466 | let source_map = db.body_with_source_map(*self).1; | ||
467 | ScopesWithSourceMap { scopes, source_map } | ||
468 | } | ||
469 | } | ||
470 | |||
432 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 471 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
433 | pub struct Function { | 472 | pub struct Function { |
434 | pub(crate) id: FunctionId, | 473 | pub(crate) id: FunctionId, |
@@ -479,11 +518,11 @@ impl Function { | |||
479 | } | 518 | } |
480 | 519 | ||
481 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | 520 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { |
482 | db.body_with_source_map(*self).1 | 521 | db.body_with_source_map((*self).into()).1 |
483 | } | 522 | } |
484 | 523 | ||
485 | pub fn body(&self, db: &impl HirDatabase) -> Arc<Body> { | 524 | pub fn body(&self, db: &impl HirDatabase) -> Arc<Body> { |
486 | db.body_hir(*self) | 525 | db.body_hir((*self).into()) |
487 | } | 526 | } |
488 | 527 | ||
489 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { | 528 | pub fn ty(&self, db: &impl HirDatabase) -> Ty { |
@@ -491,8 +530,8 @@ impl Function { | |||
491 | } | 530 | } |
492 | 531 | ||
493 | pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSourceMap { | 532 | pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSourceMap { |
494 | let scopes = db.expr_scopes(*self); | 533 | let scopes = db.expr_scopes((*self).into()); |
495 | let source_map = db.body_with_source_map(*self).1; | 534 | let source_map = db.body_with_source_map((*self).into()).1; |
496 | ScopesWithSourceMap { scopes, source_map } | 535 | ScopesWithSourceMap { scopes, source_map } |
497 | } | 536 | } |
498 | 537 | ||
@@ -501,7 +540,7 @@ impl Function { | |||
501 | } | 540 | } |
502 | 541 | ||
503 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { | 542 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { |
504 | db.infer(*self) | 543 | db.infer((*self).into()) |
505 | } | 544 | } |
506 | 545 | ||
507 | pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { | 546 | pub fn generic_params(&self, db: &impl DefDatabase) -> Arc<GenericParams> { |
@@ -557,6 +596,14 @@ impl Const { | |||
557 | db.const_signature(*self) | 596 | db.const_signature(*self) |
558 | } | 597 | } |
559 | 598 | ||
599 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { | ||
600 | db.infer((*self).into()) | ||
601 | } | ||
602 | |||
603 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
604 | db.body_with_source_map((*self).into()).1 | ||
605 | } | ||
606 | |||
560 | /// The containing impl block, if this is a method. | 607 | /// The containing impl block, if this is a method. |
561 | pub fn impl_block(&self, db: &impl DefDatabase) -> Option<ImplBlock> { | 608 | pub fn impl_block(&self, db: &impl DefDatabase) -> Option<ImplBlock> { |
562 | let module_impls = db.impls_in_module(self.module(db)); | 609 | let module_impls = db.impls_in_module(self.module(db)); |
@@ -621,6 +668,14 @@ impl Static { | |||
621 | // take the outer scope... | 668 | // take the outer scope... |
622 | self.module(db).resolver(db) | 669 | self.module(db).resolver(db) |
623 | } | 670 | } |
671 | |||
672 | pub fn infer(&self, db: &impl HirDatabase) -> Arc<InferenceResult> { | ||
673 | db.infer((*self).into()) | ||
674 | } | ||
675 | |||
676 | pub fn body_source_map(&self, db: &impl HirDatabase) -> Arc<BodySourceMap> { | ||
677 | db.body_with_source_map((*self).into()).1 | ||
678 | } | ||
624 | } | 679 | } |
625 | 680 | ||
626 | impl Docs for Static { | 681 | impl Docs for Static { |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 147005848..be8a8c98b 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -8,6 +8,7 @@ use crate::{ | |||
8 | Function, FnSignature, ExprScopes, TypeAlias, | 8 | Function, FnSignature, ExprScopes, TypeAlias, |
9 | Struct, Enum, StructField, | 9 | Struct, Enum, StructField, |
10 | Const, ConstSignature, Static, | 10 | Const, ConstSignature, Static, |
11 | DefWithBody, | ||
11 | nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap}, | 12 | nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap}, |
12 | ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig}, | 13 | ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig}, |
13 | adt::{StructData, EnumData}, | 14 | adt::{StructData, EnumData}, |
@@ -83,10 +84,10 @@ pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> { | |||
83 | #[salsa::query_group(HirDatabaseStorage)] | 84 | #[salsa::query_group(HirDatabaseStorage)] |
84 | pub trait HirDatabase: DefDatabase { | 85 | pub trait HirDatabase: DefDatabase { |
85 | #[salsa::invoke(ExprScopes::expr_scopes_query)] | 86 | #[salsa::invoke(ExprScopes::expr_scopes_query)] |
86 | fn expr_scopes(&self, func: Function) -> Arc<ExprScopes>; | 87 | fn expr_scopes(&self, def: DefWithBody) -> Arc<ExprScopes>; |
87 | 88 | ||
88 | #[salsa::invoke(crate::ty::infer)] | 89 | #[salsa::invoke(crate::ty::infer)] |
89 | fn infer(&self, func: Function) -> Arc<InferenceResult>; | 90 | fn infer(&self, def: DefWithBody) -> Arc<InferenceResult>; |
90 | 91 | ||
91 | #[salsa::invoke(crate::ty::type_for_def)] | 92 | #[salsa::invoke(crate::ty::type_for_def)] |
92 | fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty; | 93 | fn type_for_def(&self, def: TypableDef, ns: Namespace) -> Ty; |
@@ -100,11 +101,11 @@ pub trait HirDatabase: DefDatabase { | |||
100 | #[salsa::invoke(crate::expr::body_with_source_map_query)] | 101 | #[salsa::invoke(crate::expr::body_with_source_map_query)] |
101 | fn body_with_source_map( | 102 | fn body_with_source_map( |
102 | &self, | 103 | &self, |
103 | func: Function, | 104 | def: DefWithBody, |
104 | ) -> (Arc<crate::expr::Body>, Arc<crate::expr::BodySourceMap>); | 105 | ) -> (Arc<crate::expr::Body>, Arc<crate::expr::BodySourceMap>); |
105 | 106 | ||
106 | #[salsa::invoke(crate::expr::body_hir_query)] | 107 | #[salsa::invoke(crate::expr::body_hir_query)] |
107 | fn body_hir(&self, func: Function) -> Arc<crate::expr::Body>; | 108 | fn body_hir(&self, def: DefWithBody) -> Arc<crate::expr::Body>; |
108 | 109 | ||
109 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] | 110 | #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] |
110 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; | 111 | fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>; |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 45012827f..b2a237ece 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -10,7 +10,7 @@ use ra_syntax::{ | |||
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | Path, Name, HirDatabase, Function, Resolver, | 13 | Path, Name, HirDatabase, Resolver,DefWithBody, |
14 | name::AsName, | 14 | name::AsName, |
15 | type_ref::{Mutability, TypeRef}, | 15 | type_ref::{Mutability, TypeRef}, |
16 | }; | 16 | }; |
@@ -27,9 +27,8 @@ impl_arena_id!(ExprId); | |||
27 | /// The body of an item (function, const etc.). | 27 | /// The body of an item (function, const etc.). |
28 | #[derive(Debug, Eq, PartialEq)] | 28 | #[derive(Debug, Eq, PartialEq)] |
29 | pub struct Body { | 29 | pub struct Body { |
30 | // FIXME: this should be more general, consts & statics also have bodies | 30 | /// The def of the item this body belongs to |
31 | /// The Function of the item this body belongs to | 31 | owner: DefWithBody, |
32 | owner: Function, | ||
33 | exprs: Arena<ExprId, Expr>, | 32 | exprs: Arena<ExprId, Expr>, |
34 | pats: Arena<PatId, Pat>, | 33 | pats: Arena<PatId, Pat>, |
35 | /// The patterns for the function's parameters. While the parameter types are | 34 | /// The patterns for the function's parameters. While the parameter types are |
@@ -66,7 +65,7 @@ impl Body { | |||
66 | self.body_expr | 65 | self.body_expr |
67 | } | 66 | } |
68 | 67 | ||
69 | pub fn owner(&self) -> Function { | 68 | pub fn owner(&self) -> DefWithBody { |
70 | self.owner | 69 | self.owner |
71 | } | 70 | } |
72 | 71 | ||
@@ -463,8 +462,8 @@ impl Pat { | |||
463 | 462 | ||
464 | // Queries | 463 | // Queries |
465 | 464 | ||
466 | struct ExprCollector { | 465 | pub(crate) struct ExprCollector { |
467 | owner: Function, | 466 | owner: DefWithBody, |
468 | exprs: Arena<ExprId, Expr>, | 467 | exprs: Arena<ExprId, Expr>, |
469 | pats: Arena<PatId, Pat>, | 468 | pats: Arena<PatId, Pat>, |
470 | source_map: BodySourceMap, | 469 | source_map: BodySourceMap, |
@@ -473,7 +472,7 @@ struct ExprCollector { | |||
473 | } | 472 | } |
474 | 473 | ||
475 | impl ExprCollector { | 474 | impl ExprCollector { |
476 | fn new(owner: Function) -> Self { | 475 | fn new(owner: DefWithBody) -> Self { |
477 | ExprCollector { | 476 | ExprCollector { |
478 | owner, | 477 | owner, |
479 | exprs: Arena::default(), | 478 | exprs: Arena::default(), |
@@ -866,6 +865,16 @@ impl ExprCollector { | |||
866 | } | 865 | } |
867 | } | 866 | } |
868 | 867 | ||
868 | fn collect_const_body(&mut self, node: &ast::ConstDef) { | ||
869 | let body = self.collect_expr_opt(node.body()); | ||
870 | self.body_expr = Some(body); | ||
871 | } | ||
872 | |||
873 | fn collect_static_body(&mut self, node: &ast::StaticDef) { | ||
874 | let body = self.collect_expr_opt(node.body()); | ||
875 | self.body_expr = Some(body); | ||
876 | } | ||
877 | |||
869 | fn collect_fn_body(&mut self, node: &ast::FnDef) { | 878 | fn collect_fn_body(&mut self, node: &ast::FnDef) { |
870 | if let Some(param_list) = node.param_list() { | 879 | if let Some(param_list) = node.param_list() { |
871 | if let Some(self_param) = param_list.self_param() { | 880 | if let Some(self_param) = param_list.self_param() { |
@@ -910,24 +919,20 @@ impl ExprCollector { | |||
910 | 919 | ||
911 | pub(crate) fn body_with_source_map_query( | 920 | pub(crate) fn body_with_source_map_query( |
912 | db: &impl HirDatabase, | 921 | db: &impl HirDatabase, |
913 | func: Function, | 922 | def: DefWithBody, |
914 | ) -> (Arc<Body>, Arc<BodySourceMap>) { | 923 | ) -> (Arc<Body>, Arc<BodySourceMap>) { |
915 | let mut collector = ExprCollector::new(func); | 924 | let mut collector = ExprCollector::new(def); |
916 | 925 | ||
917 | // FIXME: consts, etc. | 926 | match def { |
918 | collector.collect_fn_body(&func.source(db).1); | 927 | DefWithBody::Const(ref c) => collector.collect_const_body(&c.source(db).1), |
928 | DefWithBody::Function(ref f) => collector.collect_fn_body(&f.source(db).1), | ||
929 | DefWithBody::Static(ref s) => collector.collect_static_body(&s.source(db).1), | ||
930 | } | ||
919 | 931 | ||
920 | let (body, source_map) = collector.finish(); | 932 | let (body, source_map) = collector.finish(); |
921 | (Arc::new(body), Arc::new(source_map)) | 933 | (Arc::new(body), Arc::new(source_map)) |
922 | } | 934 | } |
923 | 935 | ||
924 | pub(crate) fn body_hir_query(db: &impl HirDatabase, func: Function) -> Arc<Body> { | 936 | pub(crate) fn body_hir_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> { |
925 | db.body_with_source_map(func).0 | 937 | db.body_with_source_map(def).0 |
926 | } | ||
927 | |||
928 | #[cfg(test)] | ||
929 | fn collect_fn_body_syntax(function: Function, node: &ast::FnDef) -> (Body, BodySourceMap) { | ||
930 | let mut collector = ExprCollector::new(function); | ||
931 | collector.collect_fn_body(node); | ||
932 | collector.finish() | ||
933 | } | 938 | } |
diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index ed005c9f7..48283907b 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs | |||
@@ -10,7 +10,7 @@ use ra_syntax::{ | |||
10 | use ra_arena::{Arena, RawId, impl_arena_id}; | 10 | use ra_arena::{Arena, RawId, impl_arena_id}; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | Name, AsName, Function, | 13 | Name, AsName,DefWithBody, |
14 | expr::{PatId, ExprId, Pat, Expr, Body, Statement, BodySourceMap}, | 14 | expr::{PatId, ExprId, Pat, Expr, Body, Statement, BodySourceMap}, |
15 | HirDatabase, | 15 | HirDatabase, |
16 | }; | 16 | }; |
@@ -40,8 +40,8 @@ pub struct ScopeData { | |||
40 | 40 | ||
41 | impl ExprScopes { | 41 | impl ExprScopes { |
42 | // FIXME: This should take something more general than Function | 42 | // FIXME: This should take something more general than Function |
43 | pub(crate) fn expr_scopes_query(db: &impl HirDatabase, function: Function) -> Arc<ExprScopes> { | 43 | pub(crate) fn expr_scopes_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<ExprScopes> { |
44 | let body = db.body_hir(function); | 44 | let body = db.body_hir(def); |
45 | let res = ExprScopes::new(body); | 45 | let res = ExprScopes::new(body); |
46 | Arc::new(res) | 46 | Arc::new(res) |
47 | } | 47 | } |
@@ -297,8 +297,9 @@ mod tests { | |||
297 | use ra_syntax::{SourceFile, algo::find_node_at_offset}; | 297 | use ra_syntax::{SourceFile, algo::find_node_at_offset}; |
298 | use test_utils::{extract_offset, assert_eq_text}; | 298 | use test_utils::{extract_offset, assert_eq_text}; |
299 | use ra_arena::ArenaId; | 299 | use ra_arena::ArenaId; |
300 | use crate::Function; | ||
300 | 301 | ||
301 | use crate::expr; | 302 | use crate::expr::{ExprCollector}; |
302 | 303 | ||
303 | use super::*; | 304 | use super::*; |
304 | 305 | ||
@@ -316,7 +317,7 @@ mod tests { | |||
316 | let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); | 317 | let marker: &ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); |
317 | let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); | 318 | let fn_def: &ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap(); |
318 | let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) }; | 319 | let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) }; |
319 | let (body, source_map) = expr::collect_fn_body_syntax(irrelevant_function, fn_def); | 320 | let (body, source_map) = collect_fn_body_syntax(irrelevant_function, fn_def); |
320 | let scopes = ExprScopes::new(Arc::new(body)); | 321 | let scopes = ExprScopes::new(Arc::new(body)); |
321 | let scopes = | 322 | let scopes = |
322 | ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; | 323 | ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; |
@@ -405,6 +406,12 @@ mod tests { | |||
405 | ); | 406 | ); |
406 | } | 407 | } |
407 | 408 | ||
409 | fn collect_fn_body_syntax(function: Function, node: &ast::FnDef) -> (Body, BodySourceMap) { | ||
410 | let mut collector = ExprCollector::new(DefWithBody::Function(function)); | ||
411 | collector.collect_fn_body(node); | ||
412 | collector.finish() | ||
413 | } | ||
414 | |||
408 | fn do_check_local_name(code: &str, expected_offset: u32) { | 415 | fn do_check_local_name(code: &str, expected_offset: u32) { |
409 | let (off, code) = extract_offset(code); | 416 | let (off, code) = extract_offset(code); |
410 | let file = SourceFile::parse(&code); | 417 | let file = SourceFile::parse(&code); |
@@ -415,7 +422,7 @@ mod tests { | |||
415 | let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); | 422 | let name_ref: &ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); |
416 | 423 | ||
417 | let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) }; | 424 | let irrelevant_function = Function { id: crate::ids::FunctionId::from_raw(0.into()) }; |
418 | let (body, source_map) = expr::collect_fn_body_syntax(irrelevant_function, fn_def); | 425 | let (body, source_map) = collect_fn_body_syntax(irrelevant_function, fn_def); |
419 | let scopes = ExprScopes::new(Arc::new(body)); | 426 | let scopes = ExprScopes::new(Arc::new(body)); |
420 | let scopes = | 427 | let scopes = |
421 | ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; | 428 | ScopesWithSourceMap { scopes: Arc::new(scopes), source_map: Arc::new(source_map) }; |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 643bee6cd..c19450f39 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -67,6 +67,7 @@ pub use self::{ | |||
67 | 67 | ||
68 | pub use self::code_model_api::{ | 68 | pub use self::code_model_api::{ |
69 | Crate, CrateDependency, | 69 | Crate, CrateDependency, |
70 | DefWithBody, | ||
70 | Module, ModuleDef, ModuleSource, | 71 | Module, ModuleDef, ModuleSource, |
71 | Struct, Enum, EnumVariant, | 72 | Struct, Enum, EnumVariant, |
72 | Function, FnSignature, | 73 | Function, FnSignature, |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 6f049acfc..4ae04514a 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -60,6 +60,7 @@ use ra_arena::{Arena, RawId, impl_arena_id}; | |||
60 | use ra_db::{FileId, Edition}; | 60 | use ra_db::{FileId, Edition}; |
61 | use test_utils::tested_by; | 61 | use test_utils::tested_by; |
62 | use ra_syntax::ast; | 62 | use ra_syntax::ast; |
63 | use ra_prof::profile; | ||
63 | 64 | ||
64 | use crate::{ | 65 | use crate::{ |
65 | ModuleDef, Name, Crate, Module, | 66 | ModuleDef, Name, Crate, Module, |
@@ -181,7 +182,7 @@ enum ReachedFixedPoint { | |||
181 | 182 | ||
182 | impl CrateDefMap { | 183 | impl CrateDefMap { |
183 | pub(crate) fn crate_def_map_query(db: &impl DefDatabase, krate: Crate) -> Arc<CrateDefMap> { | 184 | pub(crate) fn crate_def_map_query(db: &impl DefDatabase, krate: Crate) -> Arc<CrateDefMap> { |
184 | let start = std::time::Instant::now(); | 185 | let _p = profile("crate_def_map_query"); |
185 | let def_map = { | 186 | let def_map = { |
186 | let edition = krate.edition(db); | 187 | let edition = krate.edition(db); |
187 | let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default(); | 188 | let mut modules: Arena<CrateModuleId, ModuleData> = Arena::default(); |
@@ -198,7 +199,6 @@ impl CrateDefMap { | |||
198 | } | 199 | } |
199 | }; | 200 | }; |
200 | let def_map = collector::collect_defs(db, def_map); | 201 | let def_map = collector::collect_defs(db, def_map); |
201 | log::info!("crate_def_map_query: {:?}", start.elapsed()); | ||
202 | Arc::new(def_map) | 202 | Arc::new(def_map) |
203 | } | 203 | } |
204 | 204 | ||
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 54dc27399..182ed4c91 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -13,7 +13,7 @@ use ra_syntax::{ | |||
13 | }; | 13 | }; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | HirDatabase, Function, Struct, Enum, | 16 | HirDatabase, Function, Struct, Enum,Const,Static, |
17 | AsName, Module, HirFileId, Crate, Trait, Resolver, | 17 | AsName, Module, HirFileId, Crate, Trait, Resolver, |
18 | ids::LocationCtx, | 18 | ids::LocationCtx, |
19 | expr, AstId | 19 | expr, AstId |
@@ -87,6 +87,27 @@ fn module_from_source( | |||
87 | ) | 87 | ) |
88 | } | 88 | } |
89 | 89 | ||
90 | pub fn const_from_source( | ||
91 | db: &impl HirDatabase, | ||
92 | file_id: FileId, | ||
93 | const_def: &ast::ConstDef, | ||
94 | ) -> Option<Const> { | ||
95 | let module = module_from_child_node(db, file_id, const_def.syntax())?; | ||
96 | let res = const_from_module(db, module, const_def); | ||
97 | Some(res) | ||
98 | } | ||
99 | |||
100 | pub fn const_from_module( | ||
101 | db: &impl HirDatabase, | ||
102 | module: Module, | ||
103 | const_def: &ast::ConstDef, | ||
104 | ) -> Const { | ||
105 | let (file_id, _) = module.definition_source(db); | ||
106 | let file_id = file_id.into(); | ||
107 | let ctx = LocationCtx::new(db, module, file_id); | ||
108 | Const { id: ctx.to_def(const_def) } | ||
109 | } | ||
110 | |||
90 | pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> { | 111 | pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> { |
91 | let file = db.parse(position.file_id); | 112 | let file = db.parse(position.file_id); |
92 | let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), position.offset)?; | 113 | let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), position.offset)?; |
@@ -134,6 +155,27 @@ pub fn struct_from_module( | |||
134 | Struct { id: ctx.to_def(struct_def) } | 155 | Struct { id: ctx.to_def(struct_def) } |
135 | } | 156 | } |
136 | 157 | ||
158 | pub fn static_from_source( | ||
159 | db: &impl HirDatabase, | ||
160 | file_id: FileId, | ||
161 | static_def: &ast::StaticDef, | ||
162 | ) -> Option<Static> { | ||
163 | let module = module_from_child_node(db, file_id, static_def.syntax())?; | ||
164 | let res = static_from_module(db, module, static_def); | ||
165 | Some(res) | ||
166 | } | ||
167 | |||
168 | pub fn static_from_module( | ||
169 | db: &impl HirDatabase, | ||
170 | module: Module, | ||
171 | static_def: &ast::StaticDef, | ||
172 | ) -> Static { | ||
173 | let (file_id, _) = module.definition_source(db); | ||
174 | let file_id = file_id.into(); | ||
175 | let ctx = LocationCtx::new(db, module, file_id); | ||
176 | Static { id: ctx.to_def(static_def) } | ||
177 | } | ||
178 | |||
137 | pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum { | 179 | pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum { |
138 | let (file_id, _) = module.definition_source(db); | 180 | let (file_id, _) = module.definition_source(db); |
139 | let file_id = file_id.into(); | 181 | let file_id = file_id.into(); |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 573115321..887153484 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -27,8 +27,9 @@ use test_utils::tested_by; | |||
27 | 27 | ||
28 | use crate::{ | 28 | use crate::{ |
29 | Function, StructField, Path, Name, | 29 | Function, StructField, Path, Name, |
30 | FnSignature, AdtDef, | 30 | FnSignature, AdtDef,ConstSignature, |
31 | HirDatabase, | 31 | HirDatabase, |
32 | DefWithBody, | ||
32 | ImplItem, | 33 | ImplItem, |
33 | type_ref::{TypeRef, Mutability}, | 34 | type_ref::{TypeRef, Mutability}, |
34 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, | 35 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, |
@@ -43,14 +44,17 @@ use crate::{ | |||
43 | use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeCtor}; | 44 | use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeCtor}; |
44 | 45 | ||
45 | /// The entry point of type inference. | 46 | /// The entry point of type inference. |
46 | pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> { | 47 | pub fn infer(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { |
47 | db.check_canceled(); | 48 | db.check_canceled(); |
48 | let body = func.body(db); | 49 | let body = def.body(db); |
49 | let resolver = func.resolver(db); | 50 | let resolver = def.resolver(db); |
50 | let mut ctx = InferenceContext::new(db, body, resolver); | 51 | let mut ctx = InferenceContext::new(db, body, resolver); |
51 | 52 | ||
52 | let signature = func.signature(db); | 53 | match def { |
53 | ctx.collect_fn_signature(&signature); | 54 | DefWithBody::Const(ref c) => ctx.collect_const_signature(&c.signature(db)), |
55 | DefWithBody::Function(ref f) => ctx.collect_fn_signature(&f.signature(db)), | ||
56 | DefWithBody::Static(ref s) => ctx.collect_const_signature(&s.signature(db)), | ||
57 | } | ||
54 | 58 | ||
55 | ctx.infer_body(); | 59 | ctx.infer_body(); |
56 | 60 | ||
@@ -1142,6 +1146,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1142 | ty | 1146 | ty |
1143 | } | 1147 | } |
1144 | 1148 | ||
1149 | fn collect_const_signature(&mut self, signature: &ConstSignature) { | ||
1150 | self.return_ty = self.make_ty(signature.type_ref()); | ||
1151 | } | ||
1152 | |||
1145 | fn collect_fn_signature(&mut self, signature: &FnSignature) { | 1153 | fn collect_fn_signature(&mut self, signature: &FnSignature) { |
1146 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 1154 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
1147 | for (type_ref, pat) in signature.params().iter().zip(body.params()) { | 1155 | for (type_ref, pat) in signature.params().iter().zip(body.params()) { |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 943c5499b..0b7c841df 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -11,6 +11,8 @@ use crate::{ | |||
11 | source_binder, | 11 | source_binder, |
12 | mock::MockDatabase, | 12 | mock::MockDatabase, |
13 | ty::display::HirDisplay, | 13 | ty::display::HirDisplay, |
14 | ty::InferenceResult, | ||
15 | expr::BodySourceMap | ||
14 | }; | 16 | }; |
15 | 17 | ||
16 | // These tests compare the inference results for all expressions in a file | 18 | // These tests compare the inference results for all expressions in a file |
@@ -1267,6 +1269,9 @@ fn test() { | |||
1267 | } | 1269 | } |
1268 | "#), | 1270 | "#), |
1269 | @r###" | 1271 | @r###" |
1272 | [52; 53) '1': u32 | ||
1273 | [103; 104) '2': u32 | ||
1274 | [211; 212) '5': u32 | ||
1270 | [227; 305) '{ ...:ID; }': () | 1275 | [227; 305) '{ ...:ID; }': () |
1271 | [237; 238) 'x': u32 | 1276 | [237; 238) 'x': u32 |
1272 | [241; 252) 'Struct::FOO': u32 | 1277 | [241; 252) 'Struct::FOO': u32 |
@@ -1855,6 +1860,9 @@ fn test() { | |||
1855 | } | 1860 | } |
1856 | "#), | 1861 | "#), |
1857 | @r###" | 1862 | @r###" |
1863 | [49; 50) '0': u32 | ||
1864 | [80; 83) '101': u32 | ||
1865 | [126; 128) '99': u32 | ||
1858 | [95; 213) '{ ...NST; }': () | 1866 | [95; 213) '{ ...NST; }': () |
1859 | [138; 139) 'x': {unknown} | 1867 | [138; 139) 'x': {unknown} |
1860 | [142; 153) 'LOCAL_CONST': {unknown} | 1868 | [142; 153) 'LOCAL_CONST': {unknown} |
@@ -1881,6 +1889,10 @@ fn test() { | |||
1881 | } | 1889 | } |
1882 | "#), | 1890 | "#), |
1883 | @r###" | 1891 | @r###" |
1892 | [29; 32) '101': u32 | ||
1893 | [70; 73) '101': u32 | ||
1894 | [118; 120) '99': u32 | ||
1895 | [161; 163) '99': u32 | ||
1884 | [85; 280) '{ ...MUT; }': () | 1896 | [85; 280) '{ ...MUT; }': () |
1885 | [173; 174) 'x': {unknown} | 1897 | [173; 174) 'x': {unknown} |
1886 | [177; 189) 'LOCAL_STATIC': {unknown} | 1898 | [177; 189) 'LOCAL_STATIC': {unknown} |
@@ -2212,6 +2224,24 @@ fn test<T: Iterable<Item=u32>>() { | |||
2212 | ); | 2224 | ); |
2213 | } | 2225 | } |
2214 | 2226 | ||
2227 | #[test] | ||
2228 | fn infer_const_body() { | ||
2229 | assert_snapshot_matches!( | ||
2230 | infer(r#" | ||
2231 | const A: u32 = 1 + 1; | ||
2232 | static B: u64 = { let x = 1; x }; | ||
2233 | "#), | ||
2234 | @r###" | ||
2235 | [16; 17) '1': u32 | ||
2236 | [16; 21) '1 + 1': u32 | ||
2237 | [20; 21) '1': u32 | ||
2238 | [39; 55) '{ let ...1; x }': u64 | ||
2239 | [45; 46) 'x': u64 | ||
2240 | [49; 50) '1': u64 | ||
2241 | [52; 53) 'x': u64"### | ||
2242 | ); | ||
2243 | } | ||
2244 | |||
2215 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 2245 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
2216 | let func = source_binder::function_from_position(db, pos).unwrap(); | 2246 | let func = source_binder::function_from_position(db, pos).unwrap(); |
2217 | let body_source_map = func.body_source_map(db); | 2247 | let body_source_map = func.body_source_map(db); |
@@ -2228,11 +2258,11 @@ fn infer(content: &str) -> String { | |||
2228 | let source_file = db.parse(file_id); | 2258 | let source_file = db.parse(file_id); |
2229 | let mut acc = String::new(); | 2259 | let mut acc = String::new(); |
2230 | acc.push_str("\n"); | 2260 | acc.push_str("\n"); |
2231 | for fn_def in source_file.syntax().descendants().filter_map(ast::FnDef::cast) { | 2261 | |
2232 | let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap(); | 2262 | let mut infer_def = |inference_result: Arc<InferenceResult>, |
2233 | let inference_result = func.infer(&db); | 2263 | body_source_map: Arc<BodySourceMap>| { |
2234 | let body_source_map = func.body_source_map(&db); | ||
2235 | let mut types = Vec::new(); | 2264 | let mut types = Vec::new(); |
2265 | |||
2236 | for (pat, ty) in inference_result.type_of_pat.iter() { | 2266 | for (pat, ty) in inference_result.type_of_pat.iter() { |
2237 | let syntax_ptr = match body_source_map.pat_syntax(pat) { | 2267 | let syntax_ptr = match body_source_map.pat_syntax(pat) { |
2238 | Some(sp) => sp, | 2268 | Some(sp) => sp, |
@@ -2240,6 +2270,7 @@ fn infer(content: &str) -> String { | |||
2240 | }; | 2270 | }; |
2241 | types.push((syntax_ptr, ty)); | 2271 | types.push((syntax_ptr, ty)); |
2242 | } | 2272 | } |
2273 | |||
2243 | for (expr, ty) in inference_result.type_of_expr.iter() { | 2274 | for (expr, ty) in inference_result.type_of_expr.iter() { |
2244 | let syntax_ptr = match body_source_map.expr_syntax(expr) { | 2275 | let syntax_ptr = match body_source_map.expr_syntax(expr) { |
2245 | Some(sp) => sp, | 2276 | Some(sp) => sp, |
@@ -2258,7 +2289,29 @@ fn infer(content: &str) -> String { | |||
2258 | }; | 2289 | }; |
2259 | write!(acc, "{} '{}': {}\n", range, ellipsize(text, 15), ty.display(&db)).unwrap(); | 2290 | write!(acc, "{} '{}': {}\n", range, ellipsize(text, 15), ty.display(&db)).unwrap(); |
2260 | } | 2291 | } |
2292 | }; | ||
2293 | |||
2294 | for const_def in source_file.syntax().descendants().filter_map(ast::ConstDef::cast) { | ||
2295 | let konst = source_binder::const_from_source(&db, file_id, const_def).unwrap(); | ||
2296 | let inference_result = konst.infer(&db); | ||
2297 | let body_source_map = konst.body_source_map(&db); | ||
2298 | infer_def(inference_result, body_source_map) | ||
2261 | } | 2299 | } |
2300 | |||
2301 | for static_def in source_file.syntax().descendants().filter_map(ast::StaticDef::cast) { | ||
2302 | let static_ = source_binder::static_from_source(&db, file_id, static_def).unwrap(); | ||
2303 | let inference_result = static_.infer(&db); | ||
2304 | let body_source_map = static_.body_source_map(&db); | ||
2305 | infer_def(inference_result, body_source_map) | ||
2306 | } | ||
2307 | |||
2308 | for fn_def in source_file.syntax().descendants().filter_map(ast::FnDef::cast) { | ||
2309 | let func = source_binder::function_from_source(&db, file_id, fn_def).unwrap(); | ||
2310 | let inference_result = func.infer(&db); | ||
2311 | let body_source_map = func.body_source_map(&db); | ||
2312 | infer_def(inference_result, body_source_map) | ||
2313 | } | ||
2314 | |||
2262 | acc.truncate(acc.trim_end().len()); | 2315 | acc.truncate(acc.trim_end().len()); |
2263 | acc | 2316 | acc |
2264 | } | 2317 | } |
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index d82410700..bc181e4eb 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml | |||
@@ -27,6 +27,7 @@ ra_ide_api = { path = "../ra_ide_api" } | |||
27 | ra_arena = { path = "../ra_arena" } | 27 | ra_arena = { path = "../ra_arena" } |
28 | gen_lsp_server = { path = "../gen_lsp_server" } | 28 | gen_lsp_server = { path = "../gen_lsp_server" } |
29 | ra_project_model = { path = "../ra_project_model" } | 29 | ra_project_model = { path = "../ra_project_model" } |
30 | ra_prof = { path = "../ra_prof" } | ||
30 | 31 | ||
31 | [dev-dependencies] | 32 | [dev-dependencies] |
32 | tempfile = "3" | 33 | tempfile = "3" |
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs index 5a2905207..eb4091a3d 100644 --- a/crates/ra_lsp_server/src/main.rs +++ b/crates/ra_lsp_server/src/main.rs | |||
@@ -3,6 +3,7 @@ use flexi_logger::{Duplicate, Logger}; | |||
3 | use gen_lsp_server::{run_server, stdio_transport}; | 3 | use gen_lsp_server::{run_server, stdio_transport}; |
4 | 4 | ||
5 | use ra_lsp_server::{Result, InitializationOptions}; | 5 | use ra_lsp_server::{Result, InitializationOptions}; |
6 | use ra_prof; | ||
6 | 7 | ||
7 | fn main() -> Result<()> { | 8 | fn main() -> Result<()> { |
8 | ::std::env::set_var("RUST_BACKTRACE", "short"); | 9 | ::std::env::set_var("RUST_BACKTRACE", "short"); |
@@ -11,6 +12,15 @@ fn main() -> Result<()> { | |||
11 | Ok(ref v) if v == "1" => logger.log_to_file().directory("log").start()?, | 12 | Ok(ref v) if v == "1" => logger.log_to_file().directory("log").start()?, |
12 | _ => logger.start()?, | 13 | _ => logger.start()?, |
13 | }; | 14 | }; |
15 | let prof_depth = match ::std::env::var("RA_PROFILE_DEPTH") { | ||
16 | Ok(ref d) => d.parse()?, | ||
17 | _ => 0, | ||
18 | }; | ||
19 | let profile_allowed = match ::std::env::var("RA_PROFILE") { | ||
20 | Ok(ref p) => p.split(";").map(String::from).collect(), | ||
21 | _ => Vec::new(), | ||
22 | }; | ||
23 | ra_prof::set_filter(ra_prof::Filter::new(prof_depth, profile_allowed)); | ||
14 | log::info!("lifecycle: server started"); | 24 | log::info!("lifecycle: server started"); |
15 | match ::std::panic::catch_unwind(main_inner) { | 25 | match ::std::panic::catch_unwind(main_inner) { |
16 | Ok(res) => { | 26 | Ok(res) => { |
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index eecf278a8..82410bee3 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs | |||
@@ -24,6 +24,7 @@ use crate::{ | |||
24 | Result, | 24 | Result, |
25 | InitializationOptions, | 25 | InitializationOptions, |
26 | }; | 26 | }; |
27 | use ra_prof::profile; | ||
27 | 28 | ||
28 | #[derive(Debug, Fail)] | 29 | #[derive(Debug, Fail)] |
29 | #[fail(display = "Language Server request failed with {}. ({})", code, message)] | 30 | #[fail(display = "Language Server request failed with {}. ({})", code, message)] |
@@ -181,7 +182,7 @@ fn main_loop_inner( | |||
181 | recv(libdata_receiver) -> data => Event::Lib(data.unwrap()) | 182 | recv(libdata_receiver) -> data => Event::Lib(data.unwrap()) |
182 | }; | 183 | }; |
183 | log::info!("loop_turn = {:?}", event); | 184 | log::info!("loop_turn = {:?}", event); |
184 | let start = std::time::Instant::now(); | 185 | let _p = profile("loop_turn"); |
185 | let mut state_changed = false; | 186 | let mut state_changed = false; |
186 | match event { | 187 | match event { |
187 | Event::Task(task) => on_task(task, msg_sender, pending_requests), | 188 | Event::Task(task) => on_task(task, msg_sender, pending_requests), |
@@ -235,10 +236,9 @@ fn main_loop_inner( | |||
235 | in_flight_libraries += 1; | 236 | in_flight_libraries += 1; |
236 | let sender = libdata_sender.clone(); | 237 | let sender = libdata_sender.clone(); |
237 | pool.execute(move || { | 238 | pool.execute(move || { |
238 | let start = ::std::time::Instant::now(); | ||
239 | log::info!("indexing {:?} ... ", root); | 239 | log::info!("indexing {:?} ... ", root); |
240 | let _p = profile(&format!("indexed {:?}", root)); | ||
240 | let data = LibraryData::prepare(root, files); | 241 | let data = LibraryData::prepare(root, files); |
241 | log::info!("indexed {:?} {:?}", start.elapsed(), root); | ||
242 | sender.send(data).unwrap(); | 242 | sender.send(data).unwrap(); |
243 | }); | 243 | }); |
244 | } | 244 | } |
@@ -266,7 +266,6 @@ fn main_loop_inner( | |||
266 | subs.subscriptions(), | 266 | subs.subscriptions(), |
267 | ) | 267 | ) |
268 | } | 268 | } |
269 | log::info!("loop_turn = {:?}", start.elapsed()); | ||
270 | } | 269 | } |
271 | } | 270 | } |
272 | 271 | ||
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs index c4b8ef3c7..318fd69a1 100644 --- a/crates/ra_parser/src/grammar/items.rs +++ b/crates/ra_parser/src/grammar/items.rs | |||
@@ -79,19 +79,22 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul | |||
79 | let mut has_mods = false; | 79 | let mut has_mods = false; |
80 | 80 | ||
81 | // modifiers | 81 | // modifiers |
82 | // test_err async_without_semicolon | ||
83 | // fn foo() { let _ = async {} } | ||
84 | has_mods |= p.eat(CONST_KW); | 82 | has_mods |= p.eat(CONST_KW); |
85 | if p.at(ASYNC_KW) && p.nth(1) != L_CURLY && p.nth(1) != MOVE_KW && p.nth(1) != PIPE { | 83 | |
86 | p.eat(ASYNC_KW); | ||
87 | has_mods = true; | ||
88 | } | ||
89 | // test_err unsafe_block_in_mod | 84 | // test_err unsafe_block_in_mod |
90 | // fn foo(){} unsafe { } fn bar(){} | 85 | // fn foo(){} unsafe { } fn bar(){} |
91 | if p.at(UNSAFE_KW) && p.nth(1) != L_CURLY { | 86 | if p.at(UNSAFE_KW) && p.nth(1) != L_CURLY { |
92 | p.eat(UNSAFE_KW); | 87 | p.eat(UNSAFE_KW); |
93 | has_mods = true; | 88 | has_mods = true; |
94 | } | 89 | } |
90 | |||
91 | // test_err async_without_semicolon | ||
92 | // fn foo() { let _ = async {} } | ||
93 | if p.at(ASYNC_KW) && p.nth(1) != L_CURLY && p.nth(1) != MOVE_KW && p.nth(1) != PIPE { | ||
94 | p.eat(ASYNC_KW); | ||
95 | has_mods = true; | ||
96 | } | ||
97 | |||
95 | if p.at(EXTERN_KW) { | 98 | if p.at(EXTERN_KW) { |
96 | has_mods = true; | 99 | has_mods = true; |
97 | abi(p); | 100 | abi(p); |
@@ -124,6 +127,14 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker, flavor: ItemFlavor) -> Resul | |||
124 | 127 | ||
125 | // test unsafe_fn | 128 | // test unsafe_fn |
126 | // unsafe fn foo() {} | 129 | // unsafe fn foo() {} |
130 | |||
131 | // test combined_fns | ||
132 | // unsafe async fn foo() {} | ||
133 | // const unsafe fn bar() {} | ||
134 | |||
135 | // test_err wrong_order_fns | ||
136 | // async unsafe fn foo() {} | ||
137 | // unsafe const fn bar() {} | ||
127 | FN_KW => { | 138 | FN_KW => { |
128 | fn_def(p, flavor); | 139 | fn_def(p, flavor); |
129 | m.complete(p, FN_DEF); | 140 | m.complete(p, FN_DEF); |
diff --git a/crates/ra_prof/Cargo.toml b/crates/ra_prof/Cargo.toml new file mode 100644 index 000000000..19ce21783 --- /dev/null +++ b/crates/ra_prof/Cargo.toml | |||
@@ -0,0 +1,9 @@ | |||
1 | [package] | ||
2 | edition = "2018" | ||
3 | name = "ra_prof" | ||
4 | version = "0.1.0" | ||
5 | authors = ["rust-analyzer developers"] | ||
6 | publish = false | ||
7 | |||
8 | [dependencies] | ||
9 | lazy_static = "1.3.0" \ No newline at end of file | ||
diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs new file mode 100644 index 000000000..1cc8e361d --- /dev/null +++ b/crates/ra_prof/src/lib.rs | |||
@@ -0,0 +1,198 @@ | |||
1 | use std::cell::RefCell; | ||
2 | use std::time::{Duration, Instant}; | ||
3 | use std::mem; | ||
4 | use std::io::{stderr, Write}; | ||
5 | use std::iter::repeat; | ||
6 | use std::collections::{HashSet}; | ||
7 | use std::default::Default; | ||
8 | use std::iter::FromIterator; | ||
9 | use std::sync::RwLock; | ||
10 | use lazy_static::lazy_static; | ||
11 | |||
12 | /// Set profiling filter. It specifies descriptions allowed to profile. | ||
13 | /// This is helpful when call stack has too many nested profiling scopes. | ||
14 | /// Additionally filter can specify maximum depth of profiling scopes nesting. | ||
15 | /// | ||
16 | /// #Example | ||
17 | /// ``` | ||
18 | /// use ra_prof::set_filter; | ||
19 | /// use ra_prof::Filter; | ||
20 | /// let max_depth = 2; | ||
21 | /// let allowed = vec!["profile1".to_string(), "profile2".to_string()]; | ||
22 | /// let f = Filter::new( max_depth, allowed ); | ||
23 | /// set_filter(f); | ||
24 | /// ``` | ||
25 | /// | ||
26 | pub fn set_filter(f: Filter) { | ||
27 | let set = HashSet::from_iter(f.allowed.iter().cloned()); | ||
28 | let mut old = FILTER.write().unwrap(); | ||
29 | let filter_data = FilterData { depth: f.depth, allowed: set, version: old.version + 1 }; | ||
30 | *old = filter_data; | ||
31 | } | ||
32 | |||
33 | /// This function starts a profiling scope in the current execution stack with a given description. | ||
34 | /// It returns a Profile structure and measure elapsed time between this method invocation and Profile structure drop. | ||
35 | /// It supports nested profiling scopes in case when this function invoked multiple times at the execution stack. In this case the profiling information will be nested at the output. | ||
36 | /// Profiling information is being printed in the stderr. | ||
37 | /// | ||
38 | /// #Example | ||
39 | /// ``` | ||
40 | /// use ra_prof::profile; | ||
41 | /// use ra_prof::set_filter; | ||
42 | /// use ra_prof::Filter; | ||
43 | /// | ||
44 | /// let allowed = vec!["profile1".to_string(), "profile2".to_string()]; | ||
45 | /// let f = Filter::new(2, allowed); | ||
46 | /// set_filter(f); | ||
47 | /// profiling_function1(); | ||
48 | /// | ||
49 | /// fn profiling_function1() { | ||
50 | /// let _p = profile("profile1"); | ||
51 | /// profiling_function2(); | ||
52 | /// } | ||
53 | /// | ||
54 | /// fn profiling_function2() { | ||
55 | /// let _p = profile("profile2"); | ||
56 | /// } | ||
57 | /// ``` | ||
58 | /// This will print in the stderr the following: | ||
59 | /// ```text | ||
60 | /// 0ms - profile | ||
61 | /// 0ms - profile2 | ||
62 | /// ``` | ||
63 | /// | ||
64 | pub fn profile(desc: &str) -> Profiler { | ||
65 | PROFILE_STACK.with(|stack| { | ||
66 | let mut stack = stack.borrow_mut(); | ||
67 | if stack.starts.len() == 0 { | ||
68 | match FILTER.try_read() { | ||
69 | Ok(f) => { | ||
70 | if f.version > stack.filter_data.version { | ||
71 | stack.filter_data = f.clone(); | ||
72 | } | ||
73 | } | ||
74 | Err(_) => (), | ||
75 | }; | ||
76 | } | ||
77 | let desc_str = desc.to_string(); | ||
78 | if desc_str.is_empty() { | ||
79 | Profiler { desc: None } | ||
80 | } else if stack.starts.len() < stack.filter_data.depth | ||
81 | && stack.filter_data.allowed.contains(&desc_str) | ||
82 | { | ||
83 | stack.starts.push(Instant::now()); | ||
84 | Profiler { desc: Some(desc_str) } | ||
85 | } else { | ||
86 | Profiler { desc: None } | ||
87 | } | ||
88 | }) | ||
89 | } | ||
90 | |||
91 | pub struct Profiler { | ||
92 | desc: Option<String>, | ||
93 | } | ||
94 | |||
95 | pub struct Filter { | ||
96 | depth: usize, | ||
97 | allowed: Vec<String>, | ||
98 | } | ||
99 | |||
100 | impl Filter { | ||
101 | pub fn new(depth: usize, allowed: Vec<String>) -> Filter { | ||
102 | Filter { depth, allowed } | ||
103 | } | ||
104 | } | ||
105 | |||
106 | struct ProfileStack { | ||
107 | starts: Vec<Instant>, | ||
108 | messages: Vec<Message>, | ||
109 | filter_data: FilterData, | ||
110 | } | ||
111 | |||
112 | struct Message { | ||
113 | level: usize, | ||
114 | duration: Duration, | ||
115 | message: String, | ||
116 | } | ||
117 | |||
118 | impl ProfileStack { | ||
119 | fn new() -> ProfileStack { | ||
120 | ProfileStack { starts: Vec::new(), messages: Vec::new(), filter_data: Default::default() } | ||
121 | } | ||
122 | } | ||
123 | |||
124 | #[derive(Default, Clone)] | ||
125 | struct FilterData { | ||
126 | depth: usize, | ||
127 | version: usize, | ||
128 | allowed: HashSet<String>, | ||
129 | } | ||
130 | |||
131 | lazy_static! { | ||
132 | static ref FILTER: RwLock<FilterData> = RwLock::new(Default::default()); | ||
133 | } | ||
134 | |||
135 | thread_local!(static PROFILE_STACK: RefCell<ProfileStack> = RefCell::new(ProfileStack::new())); | ||
136 | |||
137 | impl Drop for Profiler { | ||
138 | fn drop(&mut self) { | ||
139 | match self { | ||
140 | Profiler { desc: Some(desc) } => { | ||
141 | PROFILE_STACK.with(|stack| { | ||
142 | let mut stack = stack.borrow_mut(); | ||
143 | let start = stack.starts.pop().unwrap(); | ||
144 | let duration = start.elapsed(); | ||
145 | let level = stack.starts.len(); | ||
146 | let message = mem::replace(desc, String::new()); | ||
147 | stack.messages.push(Message { level, duration, message }); | ||
148 | if level == 0 { | ||
149 | let stdout = stderr(); | ||
150 | print(0, &stack.messages, &mut stdout.lock()); | ||
151 | stack.messages.clear(); | ||
152 | } | ||
153 | }); | ||
154 | } | ||
155 | Profiler { desc: None } => (), | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | |||
160 | fn print(lvl: usize, msgs: &[Message], out: &mut impl Write) { | ||
161 | let mut last = 0; | ||
162 | let indent = repeat(" ").take(lvl + 1).collect::<String>(); | ||
163 | for (i, &Message { level: l, duration: dur, message: ref msg }) in msgs.iter().enumerate() { | ||
164 | if l != lvl { | ||
165 | continue; | ||
166 | } | ||
167 | writeln!(out, "{} {:6}ms - {}", indent, dur.as_millis(), msg) | ||
168 | .expect("printing profiling info to stdout"); | ||
169 | |||
170 | print(lvl + 1, &msgs[last..i], out); | ||
171 | last = i; | ||
172 | } | ||
173 | } | ||
174 | |||
175 | #[cfg(test)] | ||
176 | mod tests { | ||
177 | |||
178 | use super::profile; | ||
179 | use super::set_filter; | ||
180 | use super::Filter; | ||
181 | |||
182 | #[test] | ||
183 | fn test_basic_profile() { | ||
184 | let s = vec!["profile1".to_string(), "profile2".to_string()]; | ||
185 | let f = Filter::new(2, s); | ||
186 | set_filter(f); | ||
187 | profiling_function1(); | ||
188 | } | ||
189 | |||
190 | fn profiling_function1() { | ||
191 | let _p = profile("profile1"); | ||
192 | profiling_function2(); | ||
193 | } | ||
194 | |||
195 | fn profiling_function2() { | ||
196 | let _p = profile("profile2"); | ||
197 | } | ||
198 | } | ||
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index c2e89de15..0376c91c8 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -513,7 +513,11 @@ impl ast::TypeParamsOwner for ConstDef {} | |||
513 | impl ast::AttrsOwner for ConstDef {} | 513 | impl ast::AttrsOwner for ConstDef {} |
514 | impl ast::DocCommentsOwner for ConstDef {} | 514 | impl ast::DocCommentsOwner for ConstDef {} |
515 | impl ast::TypeAscriptionOwner for ConstDef {} | 515 | impl ast::TypeAscriptionOwner for ConstDef {} |
516 | impl ConstDef {} | 516 | impl ConstDef { |
517 | pub fn body(&self) -> Option<&Expr> { | ||
518 | super::child_opt(self) | ||
519 | } | ||
520 | } | ||
517 | 521 | ||
518 | // ContinueExpr | 522 | // ContinueExpr |
519 | #[derive(Debug, PartialEq, Eq, Hash)] | 523 | #[derive(Debug, PartialEq, Eq, Hash)] |
@@ -3364,7 +3368,11 @@ impl ast::TypeParamsOwner for StaticDef {} | |||
3364 | impl ast::AttrsOwner for StaticDef {} | 3368 | impl ast::AttrsOwner for StaticDef {} |
3365 | impl ast::DocCommentsOwner for StaticDef {} | 3369 | impl ast::DocCommentsOwner for StaticDef {} |
3366 | impl ast::TypeAscriptionOwner for StaticDef {} | 3370 | impl ast::TypeAscriptionOwner for StaticDef {} |
3367 | impl StaticDef {} | 3371 | impl StaticDef { |
3372 | pub fn body(&self) -> Option<&Expr> { | ||
3373 | super::child_opt(self) | ||
3374 | } | ||
3375 | } | ||
3368 | 3376 | ||
3369 | // Stmt | 3377 | // Stmt |
3370 | #[derive(Debug, PartialEq, Eq, Hash)] | 3378 | #[derive(Debug, PartialEq, Eq, Hash)] |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index dc0de5808..0a35e25d5 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -315,6 +315,7 @@ Grammar( | |||
315 | "DocCommentsOwner", | 315 | "DocCommentsOwner", |
316 | "TypeAscriptionOwner", | 316 | "TypeAscriptionOwner", |
317 | ], | 317 | ], |
318 | options: [ ["body","Expr"]], | ||
318 | ), | 319 | ), |
319 | "StaticDef": ( | 320 | "StaticDef": ( |
320 | traits: [ | 321 | traits: [ |
@@ -325,6 +326,7 @@ Grammar( | |||
325 | "DocCommentsOwner", | 326 | "DocCommentsOwner", |
326 | "TypeAscriptionOwner", | 327 | "TypeAscriptionOwner", |
327 | ], | 328 | ], |
329 | options: [ ["body","Expr"]], | ||
328 | ), | 330 | ), |
329 | "TypeAliasDef": ( | 331 | "TypeAliasDef": ( |
330 | traits: [ | 332 | traits: [ |
diff --git a/crates/ra_syntax/tests/data/parser/inline/err/0010_wrong_order_fns.rs b/crates/ra_syntax/tests/data/parser/inline/err/0010_wrong_order_fns.rs new file mode 100644 index 000000000..16edee95d --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/inline/err/0010_wrong_order_fns.rs | |||
@@ -0,0 +1,2 @@ | |||
1 | async unsafe fn foo() {} | ||
2 | unsafe const fn bar() {} | ||
diff --git a/crates/ra_syntax/tests/data/parser/inline/err/0010_wrong_order_fns.txt b/crates/ra_syntax/tests/data/parser/inline/err/0010_wrong_order_fns.txt new file mode 100644 index 000000000..220191ffa --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/inline/err/0010_wrong_order_fns.txt | |||
@@ -0,0 +1,39 @@ | |||
1 | SOURCE_FILE@[0; 50) | ||
2 | ERROR@[0; 5) | ||
3 | ASYNC_KW@[0; 5) "async" | ||
4 | err: `expected fn, trait or impl` | ||
5 | WHITESPACE@[5; 6) " " | ||
6 | FN_DEF@[6; 24) | ||
7 | UNSAFE_KW@[6; 12) "unsafe" | ||
8 | WHITESPACE@[12; 13) " " | ||
9 | FN_KW@[13; 15) "fn" | ||
10 | WHITESPACE@[15; 16) " " | ||
11 | NAME@[16; 19) | ||
12 | IDENT@[16; 19) "foo" | ||
13 | PARAM_LIST@[19; 21) | ||
14 | L_PAREN@[19; 20) "(" | ||
15 | R_PAREN@[20; 21) ")" | ||
16 | WHITESPACE@[21; 22) " " | ||
17 | BLOCK@[22; 24) | ||
18 | L_CURLY@[22; 23) "{" | ||
19 | R_CURLY@[23; 24) "}" | ||
20 | WHITESPACE@[24; 25) "\n" | ||
21 | ERROR@[25; 31) | ||
22 | UNSAFE_KW@[25; 31) "unsafe" | ||
23 | err: `expected fn, trait or impl` | ||
24 | WHITESPACE@[31; 32) " " | ||
25 | FN_DEF@[32; 49) | ||
26 | CONST_KW@[32; 37) "const" | ||
27 | WHITESPACE@[37; 38) " " | ||
28 | FN_KW@[38; 40) "fn" | ||
29 | WHITESPACE@[40; 41) " " | ||
30 | NAME@[41; 44) | ||
31 | IDENT@[41; 44) "bar" | ||
32 | PARAM_LIST@[44; 46) | ||
33 | L_PAREN@[44; 45) "(" | ||
34 | R_PAREN@[45; 46) ")" | ||
35 | WHITESPACE@[46; 47) " " | ||
36 | BLOCK@[47; 49) | ||
37 | L_CURLY@[47; 48) "{" | ||
38 | R_CURLY@[48; 49) "}" | ||
39 | WHITESPACE@[49; 50) "\n" | ||
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0128_combined_fns.rs b/crates/ra_syntax/tests/data/parser/inline/ok/0128_combined_fns.rs new file mode 100644 index 000000000..46af91b82 --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/inline/ok/0128_combined_fns.rs | |||
@@ -0,0 +1,2 @@ | |||
1 | unsafe async fn foo() {} | ||
2 | const unsafe fn bar() {} | ||
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0128_combined_fns.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0128_combined_fns.txt new file mode 100644 index 000000000..2a16aeb61 --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/inline/ok/0128_combined_fns.txt | |||
@@ -0,0 +1,35 @@ | |||
1 | SOURCE_FILE@[0; 50) | ||
2 | FN_DEF@[0; 24) | ||
3 | UNSAFE_KW@[0; 6) "unsafe" | ||
4 | WHITESPACE@[6; 7) " " | ||
5 | ASYNC_KW@[7; 12) "async" | ||
6 | WHITESPACE@[12; 13) " " | ||
7 | FN_KW@[13; 15) "fn" | ||
8 | WHITESPACE@[15; 16) " " | ||
9 | NAME@[16; 19) | ||
10 | IDENT@[16; 19) "foo" | ||
11 | PARAM_LIST@[19; 21) | ||
12 | L_PAREN@[19; 20) "(" | ||
13 | R_PAREN@[20; 21) ")" | ||
14 | WHITESPACE@[21; 22) " " | ||
15 | BLOCK@[22; 24) | ||
16 | L_CURLY@[22; 23) "{" | ||
17 | R_CURLY@[23; 24) "}" | ||
18 | WHITESPACE@[24; 25) "\n" | ||
19 | FN_DEF@[25; 49) | ||
20 | CONST_KW@[25; 30) "const" | ||
21 | WHITESPACE@[30; 31) " " | ||
22 | UNSAFE_KW@[31; 37) "unsafe" | ||
23 | WHITESPACE@[37; 38) " " | ||
24 | FN_KW@[38; 40) "fn" | ||
25 | WHITESPACE@[40; 41) " " | ||
26 | NAME@[41; 44) | ||
27 | IDENT@[41; 44) "bar" | ||
28 | PARAM_LIST@[44; 46) | ||
29 | L_PAREN@[44; 45) "(" | ||
30 | R_PAREN@[45; 46) ")" | ||
31 | WHITESPACE@[46; 47) " " | ||
32 | BLOCK@[47; 49) | ||
33 | L_CURLY@[47; 48) "{" | ||
34 | R_CURLY@[48; 49) "}" | ||
35 | WHITESPACE@[49; 50) "\n" | ||