aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_cli/Cargo.toml1
-rw-r--r--crates/ra_cli/src/main.rs7
-rw-r--r--crates/ra_hir/Cargo.toml1
-rw-r--r--crates/ra_hir/src/code_model_api.rs65
-rw-r--r--crates/ra_hir/src/db.rs9
-rw-r--r--crates/ra_hir/src/expr.rs47
-rw-r--r--crates/ra_hir/src/expr/scope.rs19
-rw-r--r--crates/ra_hir/src/lib.rs1
-rw-r--r--crates/ra_hir/src/nameres.rs4
-rw-r--r--crates/ra_hir/src/source_binder.rs44
-rw-r--r--crates/ra_hir/src/ty/infer.rs20
-rw-r--r--crates/ra_hir/src/ty/tests.rs61
-rw-r--r--crates/ra_lsp_server/Cargo.toml1
-rw-r--r--crates/ra_lsp_server/src/main.rs10
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs7
-rw-r--r--crates/ra_parser/src/grammar/items.rs23
-rw-r--r--crates/ra_prof/Cargo.toml9
-rw-r--r--crates/ra_prof/src/lib.rs198
-rw-r--r--crates/ra_syntax/src/ast/generated.rs12
-rw-r--r--crates/ra_syntax/src/grammar.ron2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/err/0010_wrong_order_fns.rs2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/err/0010_wrong_order_fns.txt39
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0128_combined_fns.rs2
-rw-r--r--crates/ra_syntax/tests/data/parser/inline/ok/0128_combined_fns.txt35
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" }
18ra_batch = { path = "../ra_batch" } 18ra_batch = { path = "../ra_batch" }
19ra_hir = { path = "../ra_hir" } 19ra_hir = { path = "../ra_hir" }
20ra_db = { path = "../ra_db" } 20ra_db = { path = "../ra_db" }
21ra_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 @@
1mod analysis_stats; 1mod analysis_stats;
2 2
3use std::{fs, io::Read, path::Path, time::Instant}; 3use std::{fs, io::Read, path::Path};
4 4
5use clap::{App, Arg, SubCommand}; 5use clap::{App, Arg, SubCommand};
6use ra_ide_api::file_structure; 6use ra_ide_api::file_structure;
7use ra_syntax::{SourceFile, TreeArc, AstNode}; 7use ra_syntax::{SourceFile, TreeArc, AstNode};
8use tools::collect_tests; 8use tools::collect_tests;
9use flexi_logger::Logger; 9use flexi_logger::Logger;
10use ra_prof::profile;
10 11
11type Result<T> = ::std::result::Result<T, failure::Error>; 12type 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" }
19mbe = { path = "../ra_mbe", package = "ra_mbe" } 19mbe = { path = "../ra_mbe", package = "ra_mbe" }
20tt = { path = "../ra_tt", package = "ra_tt" } 20tt = { path = "../ra_tt", package = "ra_tt" }
21test_utils = { path = "../test_utils" } 21test_utils = { path = "../test_utils" }
22ra_prof = {path = "../ra_prof" }
22 23
23[dev-dependencies] 24[dev-dependencies]
24flexi_logger = "0.11.0" 25flexi_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)]
434pub enum DefWithBody {
435 Function(Function),
436 Const(Const),
437 Static(Static),
438}
439
440impl_froms!(DefWithBody: Function, Const, Static);
441
442impl 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)]
433pub struct Function { 472pub 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
626impl Docs for Static { 681impl 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)]
84pub trait HirDatabase: DefDatabase { 85pub 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
12use crate::{ 12use 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)]
29pub struct Body { 29pub 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
466struct ExprCollector { 465pub(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
475impl ExprCollector { 474impl 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
911pub(crate) fn body_with_source_map_query( 920pub(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
924pub(crate) fn body_hir_query(db: &impl HirDatabase, func: Function) -> Arc<Body> { 936pub(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)]
929fn 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::{
10use ra_arena::{Arena, RawId, impl_arena_id}; 10use ra_arena::{Arena, RawId, impl_arena_id};
11 11
12use crate::{ 12use 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
41impl ExprScopes { 41impl 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
68pub use self::code_model_api::{ 68pub 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};
60use ra_db::{FileId, Edition}; 60use ra_db::{FileId, Edition};
61use test_utils::tested_by; 61use test_utils::tested_by;
62use ra_syntax::ast; 62use ra_syntax::ast;
63use ra_prof::profile;
63 64
64use crate::{ 65use crate::{
65 ModuleDef, Name, Crate, Module, 66 ModuleDef, Name, Crate, Module,
@@ -181,7 +182,7 @@ enum ReachedFixedPoint {
181 182
182impl CrateDefMap { 183impl 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
15use crate::{ 15use 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
90pub 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
100pub 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
90pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> { 111pub 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
158pub 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
168pub 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
137pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum { 179pub 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
28use crate::{ 28use 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::{
43use super::{Ty, TypableDef, Substs, primitive, op, FnSig, ApplicationTy, TypeCtor}; 44use 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.
46pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> { 47pub 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]
2228fn infer_const_body() {
2229 assert_snapshot_matches!(
2230 infer(r#"
2231const A: u32 = 1 + 1;
2232static 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
2215fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 2245fn 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" }
27ra_arena = { path = "../ra_arena" } 27ra_arena = { path = "../ra_arena" }
28gen_lsp_server = { path = "../gen_lsp_server" } 28gen_lsp_server = { path = "../gen_lsp_server" }
29ra_project_model = { path = "../ra_project_model" } 29ra_project_model = { path = "../ra_project_model" }
30ra_prof = { path = "../ra_prof" }
30 31
31[dev-dependencies] 32[dev-dependencies]
32tempfile = "3" 33tempfile = "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};
3use gen_lsp_server::{run_server, stdio_transport}; 3use gen_lsp_server::{run_server, stdio_transport};
4 4
5use ra_lsp_server::{Result, InitializationOptions}; 5use ra_lsp_server::{Result, InitializationOptions};
6use ra_prof;
6 7
7fn main() -> Result<()> { 8fn 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};
27use 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]
2edition = "2018"
3name = "ra_prof"
4version = "0.1.0"
5authors = ["rust-analyzer developers"]
6publish = false
7
8[dependencies]
9lazy_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 @@
1use std::cell::RefCell;
2use std::time::{Duration, Instant};
3use std::mem;
4use std::io::{stderr, Write};
5use std::iter::repeat;
6use std::collections::{HashSet};
7use std::default::Default;
8use std::iter::FromIterator;
9use std::sync::RwLock;
10use 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///
26pub 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///
64pub 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
91pub struct Profiler {
92 desc: Option<String>,
93}
94
95pub struct Filter {
96 depth: usize,
97 allowed: Vec<String>,
98}
99
100impl Filter {
101 pub fn new(depth: usize, allowed: Vec<String>) -> Filter {
102 Filter { depth, allowed }
103 }
104}
105
106struct ProfileStack {
107 starts: Vec<Instant>,
108 messages: Vec<Message>,
109 filter_data: FilterData,
110}
111
112struct Message {
113 level: usize,
114 duration: Duration,
115 message: String,
116}
117
118impl ProfileStack {
119 fn new() -> ProfileStack {
120 ProfileStack { starts: Vec::new(), messages: Vec::new(), filter_data: Default::default() }
121 }
122}
123
124#[derive(Default, Clone)]
125struct FilterData {
126 depth: usize,
127 version: usize,
128 allowed: HashSet<String>,
129}
130
131lazy_static! {
132 static ref FILTER: RwLock<FilterData> = RwLock::new(Default::default());
133}
134
135thread_local!(static PROFILE_STACK: RefCell<ProfileStack> = RefCell::new(ProfileStack::new()));
136
137impl 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
160fn 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)]
176mod 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 {}
513impl ast::AttrsOwner for ConstDef {} 513impl ast::AttrsOwner for ConstDef {}
514impl ast::DocCommentsOwner for ConstDef {} 514impl ast::DocCommentsOwner for ConstDef {}
515impl ast::TypeAscriptionOwner for ConstDef {} 515impl ast::TypeAscriptionOwner for ConstDef {}
516impl ConstDef {} 516impl 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 {}
3364impl ast::AttrsOwner for StaticDef {} 3368impl ast::AttrsOwner for StaticDef {}
3365impl ast::DocCommentsOwner for StaticDef {} 3369impl ast::DocCommentsOwner for StaticDef {}
3366impl ast::TypeAscriptionOwner for StaticDef {} 3370impl ast::TypeAscriptionOwner for StaticDef {}
3367impl StaticDef {} 3371impl 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 @@
1async unsafe fn foo() {}
2unsafe 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 @@
1SOURCE_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 @@
1unsafe async fn foo() {}
2const 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 @@
1SOURCE_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"