diff options
Diffstat (limited to 'crates')
34 files changed, 1003 insertions, 216 deletions
diff --git a/crates/ra_assists/src/introduce_variable.rs b/crates/ra_assists/src/introduce_variable.rs index 934d1d6b3..954b97b05 100644 --- a/crates/ra_assists/src/introduce_variable.rs +++ b/crates/ra_assists/src/introduce_variable.rs | |||
@@ -44,7 +44,22 @@ pub(crate) fn introduce_variable(ctx: AssistCtx<impl HirDatabase>) -> Option<Ass | |||
44 | edit.replace(expr.syntax().range(), buf); | 44 | edit.replace(expr.syntax().range(), buf); |
45 | } else { | 45 | } else { |
46 | buf.push_str(";"); | 46 | buf.push_str(";"); |
47 | indent.text().push_to(&mut buf); | 47 | |
48 | // We want to maintain the indent level, | ||
49 | // but we do not want to duplicate possible | ||
50 | // extra newlines in the indent block | ||
51 | for chunk in indent.text().chunks() { | ||
52 | if chunk.starts_with("\r\n") { | ||
53 | buf.push_str("\r\n"); | ||
54 | buf.push_str(chunk.trim_start_matches("\r\n")); | ||
55 | } else if chunk.starts_with("\n") { | ||
56 | buf.push_str("\n"); | ||
57 | buf.push_str(chunk.trim_start_matches("\n")); | ||
58 | } else { | ||
59 | buf.push_str(chunk); | ||
60 | } | ||
61 | } | ||
62 | |||
48 | edit.target(expr.syntax().range()); | 63 | edit.target(expr.syntax().range()); |
49 | edit.replace(expr.syntax().range(), "var_name".to_string()); | 64 | edit.replace(expr.syntax().range(), "var_name".to_string()); |
50 | edit.insert(anchor_stmt.range().start(), buf); | 65 | edit.insert(anchor_stmt.range().start(), buf); |
@@ -345,6 +360,70 @@ fn foo() -> u32 { | |||
345 | } | 360 | } |
346 | 361 | ||
347 | #[test] | 362 | #[test] |
363 | fn test_introduce_var_does_not_add_extra_whitespace() { | ||
364 | check_assist( | ||
365 | introduce_variable, | ||
366 | " | ||
367 | fn foo() -> u32 { | ||
368 | |||
369 | |||
370 | r<|>eturn 2 + 2; | ||
371 | } | ||
372 | ", | ||
373 | " | ||
374 | fn foo() -> u32 { | ||
375 | |||
376 | |||
377 | let <|>var_name = 2 + 2; | ||
378 | return var_name; | ||
379 | } | ||
380 | ", | ||
381 | ); | ||
382 | |||
383 | check_assist( | ||
384 | introduce_variable, | ||
385 | " | ||
386 | fn foo() -> u32 { | ||
387 | |||
388 | r<|>eturn 2 + 2; | ||
389 | } | ||
390 | ", | ||
391 | " | ||
392 | fn foo() -> u32 { | ||
393 | |||
394 | let <|>var_name = 2 + 2; | ||
395 | return var_name; | ||
396 | } | ||
397 | ", | ||
398 | ); | ||
399 | |||
400 | check_assist( | ||
401 | introduce_variable, | ||
402 | " | ||
403 | fn foo() -> u32 { | ||
404 | let foo = 1; | ||
405 | |||
406 | // bar | ||
407 | |||
408 | |||
409 | r<|>eturn 2 + 2; | ||
410 | } | ||
411 | ", | ||
412 | " | ||
413 | fn foo() -> u32 { | ||
414 | let foo = 1; | ||
415 | |||
416 | // bar | ||
417 | |||
418 | |||
419 | let <|>var_name = 2 + 2; | ||
420 | return var_name; | ||
421 | } | ||
422 | ", | ||
423 | ); | ||
424 | } | ||
425 | |||
426 | #[test] | ||
348 | fn test_introduce_var_break() { | 427 | fn test_introduce_var_break() { |
349 | check_assist( | 428 | check_assist( |
350 | introduce_variable, | 429 | introduce_variable, |
diff --git a/crates/ra_batch/Cargo.toml b/crates/ra_batch/Cargo.toml new file mode 100644 index 000000000..30a0749c7 --- /dev/null +++ b/crates/ra_batch/Cargo.toml | |||
@@ -0,0 +1,20 @@ | |||
1 | [package] | ||
2 | edition = "2018" | ||
3 | name = "ra_batch" | ||
4 | version = "0.1.0" | ||
5 | authors = ["Aleksey Kladov <[email protected]>"] | ||
6 | |||
7 | [dependencies] | ||
8 | log = "0.4.5" | ||
9 | rustc-hash = "1.0" | ||
10 | |||
11 | failure = "0.1.4" | ||
12 | |||
13 | ra_syntax = { path = "../ra_syntax" } | ||
14 | ra_db = { path = "../ra_db" } | ||
15 | ra_hir = { path = "../ra_hir" } | ||
16 | ra_vfs = { path = "../ra_vfs" } | ||
17 | ra_project_model = { path = "../ra_project_model" } | ||
18 | |||
19 | [dev-dependencies] | ||
20 | test_utils = { path = "../test_utils" } | ||
diff --git a/crates/ra_batch/src/lib.rs b/crates/ra_batch/src/lib.rs new file mode 100644 index 000000000..837fff4dc --- /dev/null +++ b/crates/ra_batch/src/lib.rs | |||
@@ -0,0 +1,151 @@ | |||
1 | use std::sync::Arc; | ||
2 | use std::path::Path; | ||
3 | use std::collections::HashSet; | ||
4 | |||
5 | use rustc_hash::FxHashMap; | ||
6 | |||
7 | use ra_db::{ | ||
8 | CrateGraph, FileId, SourceRoot, SourceRootId, SourceDatabase, salsa, | ||
9 | }; | ||
10 | use ra_hir::{db, HirInterner}; | ||
11 | use ra_project_model::ProjectWorkspace; | ||
12 | use ra_vfs::{Vfs, VfsChange}; | ||
13 | |||
14 | type Result<T> = std::result::Result<T, failure::Error>; | ||
15 | |||
16 | #[salsa::database( | ||
17 | ra_db::SourceDatabaseStorage, | ||
18 | db::HirDatabaseStorage, | ||
19 | db::PersistentHirDatabaseStorage | ||
20 | )] | ||
21 | #[derive(Debug)] | ||
22 | pub struct BatchDatabase { | ||
23 | runtime: salsa::Runtime<BatchDatabase>, | ||
24 | interner: Arc<HirInterner>, | ||
25 | } | ||
26 | |||
27 | impl salsa::Database for BatchDatabase { | ||
28 | fn salsa_runtime(&self) -> &salsa::Runtime<BatchDatabase> { | ||
29 | &self.runtime | ||
30 | } | ||
31 | } | ||
32 | |||
33 | impl AsRef<HirInterner> for BatchDatabase { | ||
34 | fn as_ref(&self) -> &HirInterner { | ||
35 | &self.interner | ||
36 | } | ||
37 | } | ||
38 | |||
39 | fn vfs_file_to_id(f: ra_vfs::VfsFile) -> FileId { | ||
40 | FileId(f.0.into()) | ||
41 | } | ||
42 | fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId { | ||
43 | SourceRootId(r.0.into()) | ||
44 | } | ||
45 | |||
46 | impl BatchDatabase { | ||
47 | pub fn load(crate_graph: CrateGraph, vfs: &mut Vfs) -> BatchDatabase { | ||
48 | let mut db = | ||
49 | BatchDatabase { runtime: salsa::Runtime::default(), interner: Default::default() }; | ||
50 | db.set_crate_graph(Arc::new(crate_graph)); | ||
51 | |||
52 | // wait until Vfs has loaded all roots | ||
53 | let receiver = vfs.task_receiver().clone(); | ||
54 | let mut roots_loaded = HashSet::new(); | ||
55 | for task in receiver { | ||
56 | vfs.handle_task(task); | ||
57 | let mut done = false; | ||
58 | for change in vfs.commit_changes() { | ||
59 | match change { | ||
60 | VfsChange::AddRoot { root, files } => { | ||
61 | let source_root_id = vfs_root_to_id(root); | ||
62 | log::debug!( | ||
63 | "loaded source root {:?} with path {:?}", | ||
64 | source_root_id, | ||
65 | vfs.root2path(root) | ||
66 | ); | ||
67 | let mut file_map = FxHashMap::default(); | ||
68 | for (vfs_file, path, text) in files { | ||
69 | let file_id = vfs_file_to_id(vfs_file); | ||
70 | db.set_file_text(file_id, text); | ||
71 | db.set_file_relative_path(file_id, path.clone()); | ||
72 | db.set_file_source_root(file_id, source_root_id); | ||
73 | file_map.insert(path, file_id); | ||
74 | } | ||
75 | let source_root = SourceRoot { files: file_map }; | ||
76 | db.set_source_root(source_root_id, Arc::new(source_root)); | ||
77 | roots_loaded.insert(source_root_id); | ||
78 | if roots_loaded.len() == vfs.num_roots() { | ||
79 | done = true; | ||
80 | } | ||
81 | } | ||
82 | VfsChange::AddFile { .. } | ||
83 | | VfsChange::RemoveFile { .. } | ||
84 | | VfsChange::ChangeFile { .. } => { | ||
85 | // We just need the first scan, so just ignore these | ||
86 | } | ||
87 | } | ||
88 | } | ||
89 | if done { | ||
90 | break; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | db | ||
95 | } | ||
96 | |||
97 | pub fn load_cargo(root: impl AsRef<Path>) -> Result<(BatchDatabase, Vec<SourceRootId>)> { | ||
98 | let root = root.as_ref().canonicalize()?; | ||
99 | let ws = ProjectWorkspace::discover(root.as_ref())?; | ||
100 | let mut roots = Vec::new(); | ||
101 | roots.push(root.clone()); | ||
102 | for pkg in ws.cargo.packages() { | ||
103 | roots.push(pkg.root(&ws.cargo).to_path_buf()); | ||
104 | } | ||
105 | for krate in ws.sysroot.crates() { | ||
106 | roots.push(krate.root_dir(&ws.sysroot).to_path_buf()) | ||
107 | } | ||
108 | let (mut vfs, roots) = Vfs::new(roots); | ||
109 | let mut load = |path: &Path| { | ||
110 | let vfs_file = vfs.load(path); | ||
111 | log::debug!("vfs file {:?} -> {:?}", path, vfs_file); | ||
112 | vfs_file.map(vfs_file_to_id) | ||
113 | }; | ||
114 | let crate_graph = ws.to_crate_graph(&mut load); | ||
115 | log::debug!("crate graph: {:?}", crate_graph); | ||
116 | |||
117 | let local_roots = roots | ||
118 | .into_iter() | ||
119 | .filter(|r| vfs.root2path(*r).starts_with(&root)) | ||
120 | .map(vfs_root_to_id) | ||
121 | .collect(); | ||
122 | |||
123 | let db = BatchDatabase::load(crate_graph, &mut vfs); | ||
124 | let _ = vfs.shutdown(); | ||
125 | Ok((db, local_roots)) | ||
126 | } | ||
127 | } | ||
128 | |||
129 | #[cfg(test)] | ||
130 | mod tests { | ||
131 | use ra_hir::Crate; | ||
132 | use super::*; | ||
133 | |||
134 | #[test] | ||
135 | fn test_loading_rust_analyzer() { | ||
136 | let mut path = std::env::current_exe().unwrap(); | ||
137 | while !path.join("Cargo.toml").is_file() { | ||
138 | path = path.parent().unwrap().to_owned(); | ||
139 | } | ||
140 | let (db, roots) = BatchDatabase::load_cargo(path).unwrap(); | ||
141 | let mut num_crates = 0; | ||
142 | for root in roots { | ||
143 | for _krate in Crate::source_root_crates(&db, root) { | ||
144 | num_crates += 1; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | // RA has quite a few crates, but the exact count doesn't matter | ||
149 | assert!(num_crates > 20); | ||
150 | } | ||
151 | } | ||
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml index eb1722d5e..641ac5cbd 100644 --- a/crates/ra_cli/Cargo.toml +++ b/crates/ra_cli/Cargo.toml | |||
@@ -9,6 +9,12 @@ publish = false | |||
9 | clap = "2.32.0" | 9 | clap = "2.32.0" |
10 | failure = "0.1.4" | 10 | failure = "0.1.4" |
11 | join_to_string = "0.1.1" | 11 | join_to_string = "0.1.1" |
12 | flexi_logger = "0.10.0" | ||
13 | indicatif = "0.11.0" | ||
14 | |||
12 | ra_syntax = { path = "../ra_syntax" } | 15 | ra_syntax = { path = "../ra_syntax" } |
13 | ra_ide_api_light = { path = "../ra_ide_api_light" } | 16 | ra_ide_api_light = { path = "../ra_ide_api_light" } |
14 | tools = { path = "../tools" } | 17 | tools = { path = "../tools" } |
18 | ra_batch = { path = "../ra_batch" } | ||
19 | ra_hir = { path = "../ra_hir" } | ||
20 | ra_db = { path = "../ra_db" } | ||
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs new file mode 100644 index 000000000..a46ac974d --- /dev/null +++ b/crates/ra_cli/src/analysis_stats.rs | |||
@@ -0,0 +1,100 @@ | |||
1 | use std::collections::HashSet; | ||
2 | |||
3 | use ra_db::SourceDatabase; | ||
4 | use ra_batch::BatchDatabase; | ||
5 | use ra_hir::{Crate, ModuleDef, Ty, ImplItem}; | ||
6 | use ra_syntax::AstNode; | ||
7 | |||
8 | use crate::Result; | ||
9 | |||
10 | pub fn run(verbose: bool) -> Result<()> { | ||
11 | let (db, roots) = BatchDatabase::load_cargo(".")?; | ||
12 | println!("Database loaded, {} roots", roots.len()); | ||
13 | let mut num_crates = 0; | ||
14 | let mut visited_modules = HashSet::new(); | ||
15 | let mut visit_queue = Vec::new(); | ||
16 | for root in roots { | ||
17 | for krate in Crate::source_root_crates(&db, root) { | ||
18 | num_crates += 1; | ||
19 | let module = krate.root_module(&db).expect("crate in source root without root module"); | ||
20 | visit_queue.push(module); | ||
21 | } | ||
22 | } | ||
23 | println!("Crates in this dir: {}", num_crates); | ||
24 | let mut num_decls = 0; | ||
25 | let mut funcs = Vec::new(); | ||
26 | while let Some(module) = visit_queue.pop() { | ||
27 | if visited_modules.insert(module) { | ||
28 | visit_queue.extend(module.children(&db)); | ||
29 | |||
30 | for decl in module.declarations(&db) { | ||
31 | num_decls += 1; | ||
32 | match decl { | ||
33 | ModuleDef::Function(f) => funcs.push(f), | ||
34 | _ => {} | ||
35 | } | ||
36 | } | ||
37 | |||
38 | for impl_block in module.impl_blocks(&db) { | ||
39 | for item in impl_block.items() { | ||
40 | num_decls += 1; | ||
41 | match item { | ||
42 | ImplItem::Method(f) => funcs.push(*f), | ||
43 | _ => {} | ||
44 | } | ||
45 | } | ||
46 | } | ||
47 | } | ||
48 | } | ||
49 | println!("Total modules found: {}", visited_modules.len()); | ||
50 | println!("Total declarations: {}", num_decls); | ||
51 | println!("Total functions: {}", funcs.len()); | ||
52 | let bar = indicatif::ProgressBar::new(funcs.len() as u64); | ||
53 | bar.tick(); | ||
54 | let mut num_exprs = 0; | ||
55 | let mut num_exprs_unknown = 0; | ||
56 | let mut num_exprs_partially_unknown = 0; | ||
57 | for f in funcs { | ||
58 | if verbose { | ||
59 | let (file_id, source) = f.source(&db); | ||
60 | let original_file = file_id.original_file(&db); | ||
61 | let path = db.file_relative_path(original_file); | ||
62 | let syntax_range = source.syntax().range(); | ||
63 | let name = f.name(&db); | ||
64 | println!("{} ({:?} {})", name, path, syntax_range); | ||
65 | } | ||
66 | let body = f.body(&db); | ||
67 | let inference_result = f.infer(&db); | ||
68 | for (expr_id, _) in body.exprs() { | ||
69 | let ty = &inference_result[expr_id]; | ||
70 | num_exprs += 1; | ||
71 | if let Ty::Unknown = ty { | ||
72 | num_exprs_unknown += 1; | ||
73 | } else { | ||
74 | let mut is_partially_unknown = false; | ||
75 | ty.walk(&mut |ty| { | ||
76 | if let Ty::Unknown = ty { | ||
77 | is_partially_unknown = true; | ||
78 | } | ||
79 | }); | ||
80 | if is_partially_unknown { | ||
81 | num_exprs_partially_unknown += 1; | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | bar.inc(1); | ||
86 | } | ||
87 | bar.finish_and_clear(); | ||
88 | println!("Total expressions: {}", num_exprs); | ||
89 | println!( | ||
90 | "Expressions of unknown type: {} ({}%)", | ||
91 | num_exprs_unknown, | ||
92 | (num_exprs_unknown * 100 / num_exprs) | ||
93 | ); | ||
94 | println!( | ||
95 | "Expressions of partially unknown type: {} ({}%)", | ||
96 | num_exprs_partially_unknown, | ||
97 | (num_exprs_partially_unknown * 100 / num_exprs) | ||
98 | ); | ||
99 | Ok(()) | ||
100 | } | ||
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs index a4debeb48..72e6ae4d5 100644 --- a/crates/ra_cli/src/main.rs +++ b/crates/ra_cli/src/main.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | mod analysis_stats; | ||
2 | |||
1 | use std::{fs, io::Read, path::Path, time::Instant}; | 3 | use std::{fs, io::Read, path::Path, time::Instant}; |
2 | 4 | ||
3 | use clap::{App, Arg, SubCommand}; | 5 | use clap::{App, Arg, SubCommand}; |
@@ -5,10 +7,12 @@ use join_to_string::join; | |||
5 | use ra_ide_api_light::{extend_selection, file_structure, syntax_tree}; | 7 | use ra_ide_api_light::{extend_selection, file_structure, syntax_tree}; |
6 | use ra_syntax::{SourceFile, TextRange, TreeArc, AstNode}; | 8 | use ra_syntax::{SourceFile, TextRange, TreeArc, AstNode}; |
7 | use tools::collect_tests; | 9 | use tools::collect_tests; |
10 | use flexi_logger::Logger; | ||
8 | 11 | ||
9 | type Result<T> = ::std::result::Result<T, failure::Error>; | 12 | type Result<T> = ::std::result::Result<T, failure::Error>; |
10 | 13 | ||
11 | fn main() -> Result<()> { | 14 | fn main() -> Result<()> { |
15 | Logger::with_env().start()?; | ||
12 | let matches = App::new("ra-cli") | 16 | let matches = App::new("ra-cli") |
13 | .setting(clap::AppSettings::SubcommandRequiredElseHelp) | 17 | .setting(clap::AppSettings::SubcommandRequiredElseHelp) |
14 | .subcommand( | 18 | .subcommand( |
@@ -23,6 +27,9 @@ fn main() -> Result<()> { | |||
23 | .arg(Arg::with_name("start")) | 27 | .arg(Arg::with_name("start")) |
24 | .arg(Arg::with_name("end")), | 28 | .arg(Arg::with_name("end")), |
25 | ) | 29 | ) |
30 | .subcommand( | ||
31 | SubCommand::with_name("analysis-stats").arg(Arg::with_name("verbose").short("v")), | ||
32 | ) | ||
26 | .get_matches(); | 33 | .get_matches(); |
27 | match matches.subcommand() { | 34 | match matches.subcommand() { |
28 | ("parse", Some(matches)) => { | 35 | ("parse", Some(matches)) => { |
@@ -56,6 +63,10 @@ fn main() -> Result<()> { | |||
56 | let sels = selections(&file, start, end); | 63 | let sels = selections(&file, start, end); |
57 | println!("{}", sels) | 64 | println!("{}", sels) |
58 | } | 65 | } |
66 | ("analysis-stats", Some(matches)) => { | ||
67 | let verbose = matches.is_present("verbose"); | ||
68 | analysis_stats::run(verbose)?; | ||
69 | } | ||
59 | _ => unreachable!(), | 70 | _ => unreachable!(), |
60 | } | 71 | } |
61 | Ok(()) | 72 | Ok(()) |
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index 614325a0f..8decc65c5 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -91,6 +91,7 @@ impl CrateGraph { | |||
91 | assert!(prev.is_none()); | 91 | assert!(prev.is_none()); |
92 | crate_id | 92 | crate_id |
93 | } | 93 | } |
94 | |||
94 | pub fn add_dep( | 95 | pub fn add_dep( |
95 | &mut self, | 96 | &mut self, |
96 | from: CrateId, | 97 | from: CrateId, |
@@ -102,22 +103,41 @@ impl CrateGraph { | |||
102 | } | 103 | } |
103 | Ok(self.arena.get_mut(&from).unwrap().add_dep(name, to)) | 104 | Ok(self.arena.get_mut(&from).unwrap().add_dep(name, to)) |
104 | } | 105 | } |
106 | |||
105 | pub fn is_empty(&self) -> bool { | 107 | pub fn is_empty(&self) -> bool { |
106 | self.arena.is_empty() | 108 | self.arena.is_empty() |
107 | } | 109 | } |
110 | |||
108 | pub fn crate_root(&self, crate_id: CrateId) -> FileId { | 111 | pub fn crate_root(&self, crate_id: CrateId) -> FileId { |
109 | self.arena[&crate_id].file_id | 112 | self.arena[&crate_id].file_id |
110 | } | 113 | } |
114 | |||
115 | // TODO: this only finds one crate with the given root; we could have multiple | ||
111 | pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { | 116 | pub fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { |
112 | let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?; | 117 | let (&crate_id, _) = self.arena.iter().find(|(_crate_id, data)| data.file_id == file_id)?; |
113 | Some(crate_id) | 118 | Some(crate_id) |
114 | } | 119 | } |
120 | |||
115 | pub fn dependencies<'a>( | 121 | pub fn dependencies<'a>( |
116 | &'a self, | 122 | &'a self, |
117 | crate_id: CrateId, | 123 | crate_id: CrateId, |
118 | ) -> impl Iterator<Item = &'a Dependency> + 'a { | 124 | ) -> impl Iterator<Item = &'a Dependency> + 'a { |
119 | self.arena[&crate_id].dependencies.iter() | 125 | self.arena[&crate_id].dependencies.iter() |
120 | } | 126 | } |
127 | |||
128 | /// Extends this crate graph by adding a complete disjoint second crate | ||
129 | /// graph. | ||
130 | pub fn extend(&mut self, other: CrateGraph) { | ||
131 | let start = self.arena.len() as u32; | ||
132 | self.arena.extend(other.arena.into_iter().map(|(id, mut data)| { | ||
133 | let new_id = CrateId(id.0 + start); | ||
134 | for dep in &mut data.dependencies { | ||
135 | dep.crate_id = CrateId(dep.crate_id.0 + start); | ||
136 | } | ||
137 | (new_id, data) | ||
138 | })); | ||
139 | } | ||
140 | |||
121 | fn dfs_find(&self, target: CrateId, from: CrateId, visited: &mut FxHashSet<CrateId>) -> bool { | 141 | fn dfs_find(&self, target: CrateId, from: CrateId, visited: &mut FxHashSet<CrateId>) -> bool { |
122 | if !visited.insert(from) { | 142 | if !visited.insert(from) { |
123 | return false; | 143 | return false; |
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index cafc5279d..19f103855 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use relative_path::RelativePathBuf; | 3 | use relative_path::RelativePathBuf; |
4 | use ra_db::{CrateId, FileId}; | 4 | use ra_db::{CrateId, FileId, SourceRootId}; |
5 | use ra_syntax::{ast::self, TreeArc, SyntaxNode}; | 5 | use ra_syntax::{ast::self, TreeArc, SyntaxNode}; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
@@ -16,7 +16,7 @@ use crate::{ | |||
16 | docs::{Documentation, Docs, docs_from_ast}, | 16 | docs::{Documentation, Docs, docs_from_ast}, |
17 | module_tree::ModuleId, | 17 | module_tree::ModuleId, |
18 | ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId}, | 18 | ids::{FunctionId, StructId, EnumId, AstItemDef, ConstId, StaticId, TraitId, TypeId}, |
19 | impl_block::ImplId, | 19 | impl_block::{ImplId, ImplBlock}, |
20 | resolve::Resolver, | 20 | resolve::Resolver, |
21 | }; | 21 | }; |
22 | 22 | ||
@@ -44,6 +44,15 @@ impl Crate { | |||
44 | pub fn root_module(&self, db: &impl PersistentHirDatabase) -> Option<Module> { | 44 | pub fn root_module(&self, db: &impl PersistentHirDatabase) -> Option<Module> { |
45 | self.root_module_impl(db) | 45 | self.root_module_impl(db) |
46 | } | 46 | } |
47 | |||
48 | // TODO: should this be in source_binder? | ||
49 | pub fn source_root_crates( | ||
50 | db: &impl PersistentHirDatabase, | ||
51 | source_root: SourceRootId, | ||
52 | ) -> Vec<Crate> { | ||
53 | let crate_ids = db.source_root_crates(source_root); | ||
54 | crate_ids.iter().map(|&crate_id| Crate { crate_id }).collect() | ||
55 | } | ||
47 | } | 56 | } |
48 | 57 | ||
49 | #[derive(Debug)] | 58 | #[derive(Debug)] |
@@ -168,6 +177,27 @@ impl Module { | |||
168 | let item_map = db.item_map(self.krate); | 177 | let item_map = db.item_map(self.krate); |
169 | Resolver::default().push_module_scope(item_map, *self) | 178 | Resolver::default().push_module_scope(item_map, *self) |
170 | } | 179 | } |
180 | |||
181 | pub fn declarations(self, db: &impl HirDatabase) -> Vec<ModuleDef> { | ||
182 | let (lowered_module, _) = db.lower_module(self); | ||
183 | lowered_module | ||
184 | .declarations | ||
185 | .values() | ||
186 | .cloned() | ||
187 | .flat_map(|per_ns| { | ||
188 | per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter()) | ||
189 | }) | ||
190 | .collect() | ||
191 | } | ||
192 | |||
193 | pub fn impl_blocks(self, db: &impl HirDatabase) -> Vec<ImplBlock> { | ||
194 | let module_impl_blocks = db.impls_in_module(self); | ||
195 | module_impl_blocks | ||
196 | .impls | ||
197 | .iter() | ||
198 | .map(|(impl_id, _)| ImplBlock::from_id(module_impl_blocks.clone(), impl_id)) | ||
199 | .collect() | ||
200 | } | ||
171 | } | 201 | } |
172 | 202 | ||
173 | impl Docs for Module { | 203 | impl Docs for Module { |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 4e61d87ff..4e73590d0 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -70,6 +70,14 @@ impl Body { | |||
70 | self.owner | 70 | self.owner |
71 | } | 71 | } |
72 | 72 | ||
73 | pub fn exprs(&self) -> impl Iterator<Item = (ExprId, &Expr)> { | ||
74 | self.exprs.iter() | ||
75 | } | ||
76 | |||
77 | pub fn pats(&self) -> impl Iterator<Item = (PatId, &Pat)> { | ||
78 | self.pats.iter() | ||
79 | } | ||
80 | |||
73 | pub fn syntax_mapping(&self, db: &impl HirDatabase) -> Arc<BodySyntaxMapping> { | 81 | pub fn syntax_mapping(&self, db: &impl HirDatabase) -> Arc<BodySyntaxMapping> { |
74 | db.body_syntax_mapping(self.owner) | 82 | db.body_syntax_mapping(self.owner) |
75 | } | 83 | } |
@@ -831,18 +839,18 @@ impl ExprCollector { | |||
831 | p.field_pat_list().expect("every struct should have a field list"); | 839 | p.field_pat_list().expect("every struct should have a field list"); |
832 | let mut fields: Vec<_> = field_pat_list | 840 | let mut fields: Vec<_> = field_pat_list |
833 | .bind_pats() | 841 | .bind_pats() |
834 | .map(|bind_pat| { | 842 | .filter_map(|bind_pat| { |
835 | let ast_pat = ast::Pat::cast(bind_pat.syntax()).expect("bind pat is a pat"); | 843 | let ast_pat = ast::Pat::cast(bind_pat.syntax()).expect("bind pat is a pat"); |
836 | let pat = self.collect_pat(ast_pat); | 844 | let pat = self.collect_pat(ast_pat); |
837 | let name = bind_pat.name().expect("bind pat has a name").as_name(); | 845 | let name = bind_pat.name()?.as_name(); |
838 | FieldPat { name, pat } | 846 | Some(FieldPat { name, pat }) |
839 | }) | 847 | }) |
840 | .collect(); | 848 | .collect(); |
841 | let iter = field_pat_list.field_pats().map(|f| { | 849 | let iter = field_pat_list.field_pats().filter_map(|f| { |
842 | let ast_pat = f.pat().expect("field pat always contains a pattern"); | 850 | let ast_pat = f.pat()?; |
843 | let pat = self.collect_pat(ast_pat); | 851 | let pat = self.collect_pat(ast_pat); |
844 | let name = f.name().expect("field pats always have a name").as_name(); | 852 | let name = f.name()?.as_name(); |
845 | FieldPat { name, pat } | 853 | Some(FieldPat { name, pat }) |
846 | }); | 854 | }); |
847 | fields.extend(iter); | 855 | fields.extend(iter); |
848 | 856 | ||
@@ -850,6 +858,7 @@ impl ExprCollector { | |||
850 | } | 858 | } |
851 | 859 | ||
852 | // TODO: implement | 860 | // TODO: implement |
861 | ast::PatKind::LiteralPat(_) => Pat::Missing, | ||
853 | ast::PatKind::SlicePat(_) | ast::PatKind::RangePat(_) => Pat::Missing, | 862 | ast::PatKind::SlicePat(_) | ast::PatKind::RangePat(_) => Pat::Missing, |
854 | }; | 863 | }; |
855 | let syntax_ptr = SyntaxNodePtr::new(pat.syntax()); | 864 | let syntax_ptr = SyntaxNodePtr::new(pat.syntax()); |
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index d704c3adb..aba0c9968 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs | |||
@@ -3,4 +3,5 @@ test_utils::marks!( | |||
3 | item_map_enum_importing | 3 | item_map_enum_importing |
4 | type_var_cycles_resolve_completely | 4 | type_var_cycles_resolve_completely |
5 | type_var_cycles_resolve_as_possible | 5 | type_var_cycles_resolve_as_possible |
6 | type_var_resolves_to_int_var | ||
6 | ); | 7 | ); |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 453520bbe..2dc1de41a 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -449,6 +449,49 @@ impl Ty { | |||
449 | Ty::Tuple(Arc::new([])) | 449 | Ty::Tuple(Arc::new([])) |
450 | } | 450 | } |
451 | 451 | ||
452 | pub fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
453 | f(self); | ||
454 | match self { | ||
455 | Ty::Slice(t) | Ty::Array(t) => t.walk(f), | ||
456 | Ty::RawPtr(t, _) => t.walk(f), | ||
457 | Ty::Ref(t, _) => t.walk(f), | ||
458 | Ty::Tuple(ts) => { | ||
459 | for t in ts.iter() { | ||
460 | t.walk(f); | ||
461 | } | ||
462 | } | ||
463 | Ty::FnPtr(sig) => { | ||
464 | for input in &sig.input { | ||
465 | input.walk(f); | ||
466 | } | ||
467 | sig.output.walk(f); | ||
468 | } | ||
469 | Ty::FnDef { substs, sig, .. } => { | ||
470 | for input in &sig.input { | ||
471 | input.walk(f); | ||
472 | } | ||
473 | sig.output.walk(f); | ||
474 | for t in substs.0.iter() { | ||
475 | t.walk(f); | ||
476 | } | ||
477 | } | ||
478 | Ty::Adt { substs, .. } => { | ||
479 | for t in substs.0.iter() { | ||
480 | t.walk(f); | ||
481 | } | ||
482 | } | ||
483 | Ty::Bool | ||
484 | | Ty::Char | ||
485 | | Ty::Int(_) | ||
486 | | Ty::Float(_) | ||
487 | | Ty::Str | ||
488 | | Ty::Never | ||
489 | | Ty::Param { .. } | ||
490 | | Ty::Infer(_) | ||
491 | | Ty::Unknown => {} | ||
492 | } | ||
493 | } | ||
494 | |||
452 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | 495 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { |
453 | f(self); | 496 | f(self); |
454 | match self { | 497 | match self { |
@@ -491,7 +534,15 @@ impl Ty { | |||
491 | } | 534 | } |
492 | substs.0 = v.into(); | 535 | substs.0 = v.into(); |
493 | } | 536 | } |
494 | _ => {} | 537 | Ty::Bool |
538 | | Ty::Char | ||
539 | | Ty::Int(_) | ||
540 | | Ty::Float(_) | ||
541 | | Ty::Str | ||
542 | | Ty::Never | ||
543 | | Ty::Param { .. } | ||
544 | | Ty::Infer(_) | ||
545 | | Ty::Unknown => {} | ||
495 | } | 546 | } |
496 | } | 547 | } |
497 | 548 | ||
@@ -879,11 +930,22 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
879 | ty | 930 | ty |
880 | } | 931 | } |
881 | 932 | ||
882 | fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs) -> bool { | 933 | fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool { |
883 | substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify(t1, t2)) | 934 | substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth)) |
884 | } | 935 | } |
885 | 936 | ||
886 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { | 937 | fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { |
938 | self.unify_inner(ty1, ty2, 0) | ||
939 | } | ||
940 | |||
941 | fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { | ||
942 | if depth > 1000 { | ||
943 | // prevent stackoverflows | ||
944 | panic!("infinite recursion in unification"); | ||
945 | } | ||
946 | if ty1 == ty2 { | ||
947 | return true; | ||
948 | } | ||
887 | // try to resolve type vars first | 949 | // try to resolve type vars first |
888 | let ty1 = self.resolve_ty_shallow(ty1); | 950 | let ty1 = self.resolve_ty_shallow(ty1); |
889 | let ty2 = self.resolve_ty_shallow(ty2); | 951 | let ty2 = self.resolve_ty_shallow(ty2); |
@@ -904,13 +966,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
904 | ( | 966 | ( |
905 | Ty::Adt { def_id: def_id1, substs: substs1, .. }, | 967 | Ty::Adt { def_id: def_id1, substs: substs1, .. }, |
906 | Ty::Adt { def_id: def_id2, substs: substs2, .. }, | 968 | Ty::Adt { def_id: def_id2, substs: substs2, .. }, |
907 | ) if def_id1 == def_id2 => self.unify_substs(substs1, substs2), | 969 | ) if def_id1 == def_id2 => self.unify_substs(substs1, substs2, depth + 1), |
908 | (Ty::Slice(t1), Ty::Slice(t2)) => self.unify(t1, t2), | 970 | (Ty::Slice(t1), Ty::Slice(t2)) => self.unify_inner(t1, t2, depth + 1), |
909 | (Ty::RawPtr(t1, m1), Ty::RawPtr(t2, m2)) if m1 == m2 => self.unify(t1, t2), | 971 | (Ty::RawPtr(t1, m1), Ty::RawPtr(t2, m2)) if m1 == m2 => { |
910 | (Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify(t1, t2), | 972 | self.unify_inner(t1, t2, depth + 1) |
973 | } | ||
974 | (Ty::Ref(t1, m1), Ty::Ref(t2, m2)) if m1 == m2 => self.unify_inner(t1, t2, depth + 1), | ||
911 | (Ty::FnPtr(sig1), Ty::FnPtr(sig2)) if sig1 == sig2 => true, | 975 | (Ty::FnPtr(sig1), Ty::FnPtr(sig2)) if sig1 == sig2 => true, |
912 | (Ty::Tuple(ts1), Ty::Tuple(ts2)) if ts1.len() == ts2.len() => { | 976 | (Ty::Tuple(ts1), Ty::Tuple(ts2)) if ts1.len() == ts2.len() => { |
913 | ts1.iter().zip(ts2.iter()).all(|(t1, t2)| self.unify(t1, t2)) | 977 | ts1.iter().zip(ts2.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth + 1)) |
914 | } | 978 | } |
915 | (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) | 979 | (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2))) |
916 | | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) | 980 | | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2))) |
@@ -989,19 +1053,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
989 | /// If `ty` is a type variable with known type, returns that type; | 1053 | /// If `ty` is a type variable with known type, returns that type; |
990 | /// otherwise, return ty. | 1054 | /// otherwise, return ty. |
991 | fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { | 1055 | fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { |
992 | match ty { | 1056 | let mut ty = Cow::Borrowed(ty); |
993 | Ty::Infer(tv) => { | 1057 | // The type variable could resolve to a int/float variable. Hence try |
994 | let inner = tv.to_inner(); | 1058 | // resolving up to three times; each type of variable shouldn't occur |
995 | match self.var_unification_table.probe_value(inner).known() { | 1059 | // more than once |
996 | Some(known_ty) => { | 1060 | for i in 0..3 { |
997 | // The known_ty can't be a type var itself | 1061 | if i > 0 { |
998 | Cow::Owned(known_ty.clone()) | 1062 | tested_by!(type_var_resolves_to_int_var); |
1063 | } | ||
1064 | match &*ty { | ||
1065 | Ty::Infer(tv) => { | ||
1066 | let inner = tv.to_inner(); | ||
1067 | match self.var_unification_table.probe_value(inner).known() { | ||
1068 | Some(known_ty) => { | ||
1069 | // The known_ty can't be a type var itself | ||
1070 | ty = Cow::Owned(known_ty.clone()); | ||
1071 | } | ||
1072 | _ => return ty, | ||
999 | } | 1073 | } |
1000 | _ => Cow::Borrowed(ty), | ||
1001 | } | 1074 | } |
1075 | _ => return ty, | ||
1002 | } | 1076 | } |
1003 | _ => Cow::Borrowed(ty), | ||
1004 | } | 1077 | } |
1078 | log::error!("Inference variable still not resolved: {:?}", ty); | ||
1079 | ty | ||
1005 | } | 1080 | } |
1006 | 1081 | ||
1007 | /// Resolves the type completely; type variables without known type are | 1082 | /// Resolves the type completely; type variables without known type are |
@@ -1185,17 +1260,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1185 | self.infer_path_expr(&resolver, &path).unwrap_or(Ty::Unknown) | 1260 | self.infer_path_expr(&resolver, &path).unwrap_or(Ty::Unknown) |
1186 | } | 1261 | } |
1187 | Pat::Bind { mode, name: _name, subpat } => { | 1262 | Pat::Bind { mode, name: _name, subpat } => { |
1188 | let subty = if let Some(subpat) = subpat { | 1263 | let inner_ty = if let Some(subpat) = subpat { |
1189 | self.infer_pat(*subpat, expected) | 1264 | self.infer_pat(*subpat, expected) |
1190 | } else { | 1265 | } else { |
1191 | expected.clone() | 1266 | expected.clone() |
1192 | }; | 1267 | }; |
1268 | let inner_ty = self.insert_type_vars_shallow(inner_ty); | ||
1193 | 1269 | ||
1194 | match mode { | 1270 | let bound_ty = match mode { |
1195 | BindingAnnotation::Ref => Ty::Ref(subty.into(), Mutability::Shared), | 1271 | BindingAnnotation::Ref => Ty::Ref(inner_ty.clone().into(), Mutability::Shared), |
1196 | BindingAnnotation::RefMut => Ty::Ref(subty.into(), Mutability::Mut), | 1272 | BindingAnnotation::RefMut => Ty::Ref(inner_ty.clone().into(), Mutability::Mut), |
1197 | BindingAnnotation::Mutable | BindingAnnotation::Unannotated => subty, | 1273 | BindingAnnotation::Mutable | BindingAnnotation::Unannotated => inner_ty.clone(), |
1198 | } | 1274 | }; |
1275 | let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty); | ||
1276 | self.write_pat_ty(pat, bound_ty); | ||
1277 | return inner_ty; | ||
1199 | } | 1278 | } |
1200 | _ => Ty::Unknown, | 1279 | _ => Ty::Unknown, |
1201 | }; | 1280 | }; |
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_1.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_1.snap new file mode 100644 index 000000000..4b99788e4 --- /dev/null +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_1.snap | |||
@@ -0,0 +1,13 @@ | |||
1 | --- | ||
2 | created: "2019-02-09T16:56:24.803326529Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_hir/src/ty/tests.rs | ||
5 | expression: "&result" | ||
6 | --- | ||
7 | [54; 139) '{ ... } }': () | ||
8 | [60; 137) 'match ... }': () | ||
9 | [66; 83) 'someth...nknown': Maybe<[unknown]> | ||
10 | [94; 124) 'Maybe:...thing)': Maybe<[unknown]> | ||
11 | [106; 123) 'ref mu...ething': &mut [unknown] | ||
12 | [128; 130) '()': () | ||
13 | |||
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_2.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_2.snap new file mode 100644 index 000000000..fd0b39b7d --- /dev/null +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_2.snap | |||
@@ -0,0 +1,14 @@ | |||
1 | --- | ||
2 | created: "2019-02-09T17:03:11.974225590Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_hir/src/ty/tests.rs | ||
5 | expression: "&result" | ||
6 | --- | ||
7 | [23; 53) '{ ...n']; }': () | ||
8 | [29; 50) '&[0, b...b'\n']': &[u8] | ||
9 | [30; 50) '[0, b'...b'\n']': [u8] | ||
10 | [31; 32) '0': u8 | ||
11 | [34; 39) 'b'\n'': u8 | ||
12 | [41; 42) '1': u8 | ||
13 | [44; 49) 'b'\n'': u8 | ||
14 | |||
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_3.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_3.snap new file mode 100644 index 000000000..d15b77e17 --- /dev/null +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_3.snap | |||
@@ -0,0 +1,13 @@ | |||
1 | --- | ||
2 | created: "2019-02-09T18:02:37.377591660Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_hir/src/ty/tests.rs | ||
5 | expression: "&result" | ||
6 | --- | ||
7 | [18; 102) '{ ... } }': () | ||
8 | [24; 100) 'match ... }': () | ||
9 | [42; 88) 'SizeSk...tail }': [unknown] | ||
10 | [76; 80) 'true': [unknown] | ||
11 | [82; 86) 'tail': [unknown] | ||
12 | [92; 94) '{}': () | ||
13 | |||
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_4.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_4.snap new file mode 100644 index 000000000..fb31883ce --- /dev/null +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_4.snap | |||
@@ -0,0 +1,16 @@ | |||
1 | --- | ||
2 | created: "2019-02-09T19:55:39.712470520Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_hir/src/ty/tests.rs | ||
5 | expression: "&result" | ||
6 | --- | ||
7 | [25; 110) '{ ... } }': () | ||
8 | [31; 108) 'match ... }': () | ||
9 | [37; 42) '*self': [unknown] | ||
10 | [38; 42) 'self': [unknown] | ||
11 | [53; 95) 'Borrow...), ..}': [unknown] | ||
12 | [74; 77) 'box': [unknown] | ||
13 | [78; 87) 'Primitive': [unknown] | ||
14 | [88; 89) 'p': [unknown] | ||
15 | [99; 101) '{}': () | ||
16 | |||
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_5.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_5.snap new file mode 100644 index 000000000..6bbf59fb6 --- /dev/null +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_5.snap | |||
@@ -0,0 +1,30 @@ | |||
1 | --- | ||
2 | created: "2019-02-09T20:28:37.294693728Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_hir/src/ty/tests.rs | ||
5 | expression: "&result" | ||
6 | --- | ||
7 | [27; 323) '{ ... } }': () | ||
8 | [33; 321) 'for co... }': () | ||
9 | [37; 44) 'content': &[unknown] | ||
10 | [48; 61) 'doesnt_matter': [unknown] | ||
11 | [62; 321) '{ ... }': () | ||
12 | [76; 80) 'name': &&[unknown] | ||
13 | [83; 167) 'if doe... }': &&[unknown] | ||
14 | [86; 99) 'doesnt_matter': bool | ||
15 | [100; 129) '{ ... }': &&[unknown] | ||
16 | [114; 119) 'first': &&[unknown] | ||
17 | [135; 167) '{ ... }': &&[unknown] | ||
18 | [149; 157) '&content': &&[unknown] | ||
19 | [150; 157) 'content': &[unknown] | ||
20 | [182; 189) 'content': &&[unknown] | ||
21 | [192; 314) 'if ICE... }': &&[unknown] | ||
22 | [195; 232) 'ICE_RE..._VALUE': [unknown] | ||
23 | [195; 248) 'ICE_RE...&name)': bool | ||
24 | [242; 247) '&name': &&&[unknown] | ||
25 | [243; 247) 'name': &&[unknown] | ||
26 | [249; 277) '{ ... }': &&[unknown] | ||
27 | [263; 267) 'name': &&[unknown] | ||
28 | [283; 314) '{ ... }': &[unknown] | ||
29 | [297; 304) 'content': &[unknown] | ||
30 | |||
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 2621d1b55..e64fd2749 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -630,6 +630,95 @@ fn test() { | |||
630 | ); | 630 | ); |
631 | } | 631 | } |
632 | 632 | ||
633 | #[test] | ||
634 | fn infer_std_crash_1() { | ||
635 | // caused stack overflow, taken from std | ||
636 | check_inference( | ||
637 | "infer_std_crash_1", | ||
638 | r#" | ||
639 | enum Maybe<T> { | ||
640 | Real(T), | ||
641 | Fake, | ||
642 | } | ||
643 | |||
644 | fn write() { | ||
645 | match something_unknown { | ||
646 | Maybe::Real(ref mut something) => (), | ||
647 | } | ||
648 | } | ||
649 | "#, | ||
650 | ); | ||
651 | } | ||
652 | |||
653 | #[test] | ||
654 | fn infer_std_crash_2() { | ||
655 | covers!(type_var_resolves_to_int_var); | ||
656 | // caused "equating two type variables, ...", taken from std | ||
657 | check_inference( | ||
658 | "infer_std_crash_2", | ||
659 | r#" | ||
660 | fn test_line_buffer() { | ||
661 | &[0, b'\n', 1, b'\n']; | ||
662 | } | ||
663 | "#, | ||
664 | ); | ||
665 | } | ||
666 | |||
667 | #[test] | ||
668 | fn infer_std_crash_3() { | ||
669 | // taken from rustc | ||
670 | check_inference( | ||
671 | "infer_std_crash_3", | ||
672 | r#" | ||
673 | pub fn compute() { | ||
674 | match _ { | ||
675 | SizeSkeleton::Pointer { non_zero: true, tail } => {} | ||
676 | } | ||
677 | } | ||
678 | "#, | ||
679 | ); | ||
680 | } | ||
681 | |||
682 | #[test] | ||
683 | fn infer_std_crash_4() { | ||
684 | // taken from rustc | ||
685 | check_inference( | ||
686 | "infer_std_crash_4", | ||
687 | r#" | ||
688 | pub fn primitive_type() { | ||
689 | match *self { | ||
690 | BorrowedRef { type_: box Primitive(p), ..} => {}, | ||
691 | } | ||
692 | } | ||
693 | "#, | ||
694 | ); | ||
695 | } | ||
696 | |||
697 | #[test] | ||
698 | fn infer_std_crash_5() { | ||
699 | // taken from rustc | ||
700 | check_inference( | ||
701 | "infer_std_crash_5", | ||
702 | r#" | ||
703 | fn extra_compiler_flags() { | ||
704 | for content in doesnt_matter { | ||
705 | let name = if doesnt_matter { | ||
706 | first | ||
707 | } else { | ||
708 | &content | ||
709 | }; | ||
710 | |||
711 | let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) { | ||
712 | name | ||
713 | } else { | ||
714 | content | ||
715 | }; | ||
716 | } | ||
717 | } | ||
718 | "#, | ||
719 | ); | ||
720 | } | ||
721 | |||
633 | fn infer(content: &str) -> String { | 722 | fn infer(content: &str) -> String { |
634 | let (db, _, file_id) = MockDatabase::with_single_file(content); | 723 | let (db, _, file_id) = MockDatabase::with_single_file(content); |
635 | let source_file = db.parse(file_id); | 724 | let source_file = db.parse(file_id); |
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index bb92747f2..f46d77893 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml | |||
@@ -19,7 +19,6 @@ url_serde = "0.2.0" | |||
19 | lsp-types = "0.55.0" | 19 | lsp-types = "0.55.0" |
20 | walkdir = "2.2.7" | 20 | walkdir = "2.2.7" |
21 | im = "12.0.0" | 21 | im = "12.0.0" |
22 | cargo_metadata = "0.7.0" | ||
23 | rustc-hash = "1.0" | 22 | rustc-hash = "1.0" |
24 | parking_lot = "0.7.0" | 23 | parking_lot = "0.7.0" |
25 | 24 | ||
@@ -30,6 +29,7 @@ ra_ide_api = { path = "../ra_ide_api" } | |||
30 | ra_arena = { path = "../ra_arena" } | 29 | ra_arena = { path = "../ra_arena" } |
31 | gen_lsp_server = { path = "../gen_lsp_server" } | 30 | gen_lsp_server = { path = "../gen_lsp_server" } |
32 | ra_vfs = { path = "../ra_vfs" } | 31 | ra_vfs = { path = "../ra_vfs" } |
32 | ra_project_model = { path = "../ra_project_model" } | ||
33 | 33 | ||
34 | [dev-dependencies] | 34 | [dev-dependencies] |
35 | tempfile = "3" | 35 | tempfile = "3" |
diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs index fd5875a0a..6800eb138 100644 --- a/crates/ra_lsp_server/src/project_model.rs +++ b/crates/ra_lsp_server/src/project_model.rs | |||
@@ -1,34 +1,13 @@ | |||
1 | mod cargo_workspace; | 1 | use std::path::PathBuf; |
2 | mod sysroot; | ||
3 | 2 | ||
4 | use std::path::{Path, PathBuf}; | ||
5 | |||
6 | use failure::bail; | ||
7 | use thread_worker::{WorkerHandle, Worker}; | 3 | use thread_worker::{WorkerHandle, Worker}; |
8 | 4 | ||
9 | use crate::Result; | 5 | use crate::Result; |
10 | 6 | ||
11 | pub use crate::project_model::{ | 7 | pub use ra_project_model::{ |
12 | cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, | 8 | ProjectWorkspace, CargoWorkspace, Package, Target, TargetKind, Sysroot, |
13 | sysroot::Sysroot, | ||
14 | }; | 9 | }; |
15 | 10 | ||
16 | #[derive(Debug, Clone)] | ||
17 | pub struct ProjectWorkspace { | ||
18 | pub(crate) cargo: CargoWorkspace, | ||
19 | pub(crate) sysroot: Sysroot, | ||
20 | } | ||
21 | |||
22 | impl ProjectWorkspace { | ||
23 | pub fn discover(path: &Path) -> Result<ProjectWorkspace> { | ||
24 | let cargo_toml = find_cargo_toml(path)?; | ||
25 | let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?; | ||
26 | let sysroot = Sysroot::discover(&cargo_toml)?; | ||
27 | let res = ProjectWorkspace { cargo, sysroot }; | ||
28 | Ok(res) | ||
29 | } | ||
30 | } | ||
31 | |||
32 | pub fn workspace_loader() -> (Worker<PathBuf, Result<ProjectWorkspace>>, WorkerHandle) { | 11 | pub fn workspace_loader() -> (Worker<PathBuf, Result<ProjectWorkspace>>, WorkerHandle) { |
33 | thread_worker::spawn::<PathBuf, Result<ProjectWorkspace>, _>( | 12 | thread_worker::spawn::<PathBuf, Result<ProjectWorkspace>, _>( |
34 | "workspace loader", | 13 | "workspace loader", |
@@ -42,18 +21,3 @@ pub fn workspace_loader() -> (Worker<PathBuf, Result<ProjectWorkspace>>, WorkerH | |||
42 | }, | 21 | }, |
43 | ) | 22 | ) |
44 | } | 23 | } |
45 | |||
46 | fn find_cargo_toml(path: &Path) -> Result<PathBuf> { | ||
47 | if path.ends_with("Cargo.toml") { | ||
48 | return Ok(path.to_path_buf()); | ||
49 | } | ||
50 | let mut curr = Some(path); | ||
51 | while let Some(path) = curr { | ||
52 | let candidate = path.join("Cargo.toml"); | ||
53 | if candidate.exists() { | ||
54 | return Ok(candidate); | ||
55 | } | ||
56 | curr = path.parent(); | ||
57 | } | ||
58 | bail!("can't find Cargo.toml at {}", path.display()) | ||
59 | } | ||
diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index 02f2a37a8..4a68c019f 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs | |||
@@ -9,13 +9,12 @@ use ra_ide_api::{ | |||
9 | SourceRootId | 9 | SourceRootId |
10 | }; | 10 | }; |
11 | use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot}; | 11 | use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot}; |
12 | use rustc_hash::FxHashMap; | ||
13 | use relative_path::RelativePathBuf; | 12 | use relative_path::RelativePathBuf; |
14 | use parking_lot::RwLock; | 13 | use parking_lot::RwLock; |
15 | use failure::format_err; | 14 | use failure::format_err; |
16 | 15 | ||
17 | use crate::{ | 16 | use crate::{ |
18 | project_model::{ProjectWorkspace, TargetKind}, | 17 | project_model::ProjectWorkspace, |
19 | Result, | 18 | Result, |
20 | }; | 19 | }; |
21 | 20 | ||
@@ -48,97 +47,21 @@ impl ServerWorldState { | |||
48 | roots.push(krate.root_dir(&ws.sysroot).to_path_buf()) | 47 | roots.push(krate.root_dir(&ws.sysroot).to_path_buf()) |
49 | } | 48 | } |
50 | } | 49 | } |
51 | roots.sort(); | ||
52 | roots.dedup(); | ||
53 | let roots_to_scan = roots.len(); | ||
54 | let (mut vfs, roots) = Vfs::new(roots); | 50 | let (mut vfs, roots) = Vfs::new(roots); |
51 | let roots_to_scan = roots.len(); | ||
55 | for r in roots { | 52 | for r in roots { |
56 | let is_local = vfs.root2path(r).starts_with(&root); | 53 | let is_local = vfs.root2path(r).starts_with(&root); |
57 | change.add_root(SourceRootId(r.0.into()), is_local); | 54 | change.add_root(SourceRootId(r.0.into()), is_local); |
58 | } | 55 | } |
59 | 56 | ||
57 | // Create crate graph from all the workspaces | ||
60 | let mut crate_graph = CrateGraph::default(); | 58 | let mut crate_graph = CrateGraph::default(); |
59 | let mut load = |path: &std::path::Path| { | ||
60 | let vfs_file = vfs.load(path); | ||
61 | vfs_file.map(|f| FileId(f.0.into())) | ||
62 | }; | ||
61 | for ws in workspaces.iter() { | 63 | for ws in workspaces.iter() { |
62 | // First, load std | 64 | crate_graph.extend(ws.to_crate_graph(&mut load)); |
63 | let mut sysroot_crates = FxHashMap::default(); | ||
64 | for krate in ws.sysroot.crates() { | ||
65 | if let Some(file_id) = vfs.load(krate.root(&ws.sysroot)) { | ||
66 | let file_id = FileId(file_id.0.into()); | ||
67 | sysroot_crates.insert(krate, crate_graph.add_crate_root(file_id)); | ||
68 | } | ||
69 | } | ||
70 | for from in ws.sysroot.crates() { | ||
71 | for to in from.deps(&ws.sysroot) { | ||
72 | let name = to.name(&ws.sysroot); | ||
73 | if let (Some(&from), Some(&to)) = | ||
74 | (sysroot_crates.get(&from), sysroot_crates.get(&to)) | ||
75 | { | ||
76 | if let Err(_) = crate_graph.add_dep(from, name.clone(), to) { | ||
77 | log::error!("cyclic dependency between sysroot crates") | ||
78 | } | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | |||
83 | let libstd = ws.sysroot.std().and_then(|it| sysroot_crates.get(&it).map(|&it| it)); | ||
84 | |||
85 | let mut pkg_to_lib_crate = FxHashMap::default(); | ||
86 | let mut pkg_crates = FxHashMap::default(); | ||
87 | // Next, create crates for each package, target pair | ||
88 | for pkg in ws.cargo.packages() { | ||
89 | let mut lib_tgt = None; | ||
90 | for tgt in pkg.targets(&ws.cargo) { | ||
91 | let root = tgt.root(&ws.cargo); | ||
92 | if let Some(file_id) = vfs.load(root) { | ||
93 | let file_id = FileId(file_id.0.into()); | ||
94 | let crate_id = crate_graph.add_crate_root(file_id); | ||
95 | if tgt.kind(&ws.cargo) == TargetKind::Lib { | ||
96 | lib_tgt = Some(crate_id); | ||
97 | pkg_to_lib_crate.insert(pkg, crate_id); | ||
98 | } | ||
99 | pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | // Set deps to the std and to the lib target of the current package | ||
104 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | ||
105 | if let Some(to) = lib_tgt { | ||
106 | if to != from { | ||
107 | if let Err(_) = | ||
108 | crate_graph.add_dep(from, pkg.name(&ws.cargo).into(), to) | ||
109 | { | ||
110 | log::error!( | ||
111 | "cyclic dependency between targets of {}", | ||
112 | pkg.name(&ws.cargo) | ||
113 | ) | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | if let Some(std) = libstd { | ||
118 | if let Err(_) = crate_graph.add_dep(from, "std".into(), std) { | ||
119 | log::error!("cyclic dependency on std for {}", pkg.name(&ws.cargo)) | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | |||
125 | // Now add a dep ednge from all targets of upstream to the lib | ||
126 | // target of downstream. | ||
127 | for pkg in ws.cargo.packages() { | ||
128 | for dep in pkg.dependencies(&ws.cargo) { | ||
129 | if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { | ||
130 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | ||
131 | if let Err(_) = crate_graph.add_dep(from, dep.name.clone(), to) { | ||
132 | log::error!( | ||
133 | "cyclic dependency {} -> {}", | ||
134 | pkg.name(&ws.cargo), | ||
135 | dep.pkg.name(&ws.cargo) | ||
136 | ) | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | } | 65 | } |
143 | change.set_crate_graph(crate_graph); | 66 | change.set_crate_graph(crate_graph); |
144 | 67 | ||
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml new file mode 100644 index 000000000..90f8b8398 --- /dev/null +++ b/crates/ra_project_model/Cargo.toml | |||
@@ -0,0 +1,21 @@ | |||
1 | [package] | ||
2 | edition = "2018" | ||
3 | name = "ra_project_model" | ||
4 | version = "0.1.0" | ||
5 | authors = ["Aleksey Kladov <[email protected]>"] | ||
6 | |||
7 | [dependencies] | ||
8 | log = "0.4.5" | ||
9 | rustc-hash = "1.0" | ||
10 | |||
11 | failure = "0.1.4" | ||
12 | |||
13 | walkdir = "2.2.7" | ||
14 | |||
15 | cargo_metadata = "0.7.0" | ||
16 | |||
17 | ra_arena = { path = "../ra_arena" } | ||
18 | ra_db = { path = "../ra_db" } | ||
19 | |||
20 | [dev-dependencies] | ||
21 | test_utils = { path = "../test_utils" } | ||
diff --git a/crates/ra_lsp_server/src/project_model/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 3b76389d2..8adf463a6 100644 --- a/crates/ra_lsp_server/src/project_model/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs | |||
@@ -1,17 +1,16 @@ | |||
1 | use std::path::{Path, PathBuf}; | 1 | use std::path::{Path, PathBuf}; |
2 | 2 | ||
3 | use cargo_metadata::{MetadataCommand, CargoOpt}; | 3 | use cargo_metadata::{MetadataCommand, CargoOpt}; |
4 | use ra_syntax::SmolStr; | ||
5 | use ra_arena::{Arena, RawId, impl_arena_id}; | 4 | use ra_arena::{Arena, RawId, impl_arena_id}; |
6 | use rustc_hash::FxHashMap; | 5 | use rustc_hash::FxHashMap; |
7 | use failure::format_err; | 6 | use failure::format_err; |
8 | 7 | ||
9 | use crate::Result; | 8 | use crate::Result; |
10 | 9 | ||
11 | /// `CargoWorksapce` represents the logical structure of, well, a Cargo | 10 | /// `CargoWorkspace` represents the logical structure of, well, a Cargo |
12 | /// workspace. It pretty closely mirrors `cargo metadata` output. | 11 | /// workspace. It pretty closely mirrors `cargo metadata` output. |
13 | /// | 12 | /// |
14 | /// Note that internally, rust analyzer uses a differnet structure: | 13 | /// Note that internally, rust analyzer uses a different structure: |
15 | /// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, | 14 | /// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates, |
16 | /// while this knows about `Pacakges` & `Targets`: purely cargo-related | 15 | /// while this knows about `Pacakges` & `Targets`: purely cargo-related |
17 | /// concepts. | 16 | /// concepts. |
@@ -31,7 +30,7 @@ impl_arena_id!(Target); | |||
31 | 30 | ||
32 | #[derive(Debug, Clone)] | 31 | #[derive(Debug, Clone)] |
33 | struct PackageData { | 32 | struct PackageData { |
34 | name: SmolStr, | 33 | name: String, |
35 | manifest: PathBuf, | 34 | manifest: PathBuf, |
36 | targets: Vec<Target>, | 35 | targets: Vec<Target>, |
37 | is_member: bool, | 36 | is_member: bool, |
@@ -41,13 +40,13 @@ struct PackageData { | |||
41 | #[derive(Debug, Clone)] | 40 | #[derive(Debug, Clone)] |
42 | pub struct PackageDependency { | 41 | pub struct PackageDependency { |
43 | pub pkg: Package, | 42 | pub pkg: Package, |
44 | pub name: SmolStr, | 43 | pub name: String, |
45 | } | 44 | } |
46 | 45 | ||
47 | #[derive(Debug, Clone)] | 46 | #[derive(Debug, Clone)] |
48 | struct TargetData { | 47 | struct TargetData { |
49 | pkg: Package, | 48 | pkg: Package, |
50 | name: SmolStr, | 49 | name: String, |
51 | root: PathBuf, | 50 | root: PathBuf, |
52 | kind: TargetKind, | 51 | kind: TargetKind, |
53 | } | 52 | } |
@@ -162,9 +161,11 @@ impl CargoWorkspace { | |||
162 | 161 | ||
163 | Ok(CargoWorkspace { packages, targets }) | 162 | Ok(CargoWorkspace { packages, targets }) |
164 | } | 163 | } |
164 | |||
165 | pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + 'a { | 165 | pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + 'a { |
166 | self.packages.iter().map(|(id, _pkg)| id) | 166 | self.packages.iter().map(|(id, _pkg)| id) |
167 | } | 167 | } |
168 | |||
168 | pub fn target_by_root(&self, root: &Path) -> Option<Target> { | 169 | pub fn target_by_root(&self, root: &Path) -> Option<Target> { |
169 | self.packages().filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root)).next() | 170 | self.packages().filter_map(|pkg| pkg.targets(self).find(|it| it.root(self) == root)).next() |
170 | } | 171 | } |
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs new file mode 100644 index 000000000..3b1e07149 --- /dev/null +++ b/crates/ra_project_model/src/lib.rs | |||
@@ -0,0 +1,130 @@ | |||
1 | mod cargo_workspace; | ||
2 | mod sysroot; | ||
3 | |||
4 | use std::path::{Path, PathBuf}; | ||
5 | |||
6 | use failure::bail; | ||
7 | use rustc_hash::FxHashMap; | ||
8 | |||
9 | use ra_db::{CrateGraph, FileId}; | ||
10 | |||
11 | pub use crate::{ | ||
12 | cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, | ||
13 | sysroot::Sysroot, | ||
14 | }; | ||
15 | |||
16 | // TODO use proper error enum | ||
17 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; | ||
18 | |||
19 | #[derive(Debug, Clone)] | ||
20 | pub struct ProjectWorkspace { | ||
21 | pub cargo: CargoWorkspace, | ||
22 | pub sysroot: Sysroot, | ||
23 | } | ||
24 | |||
25 | impl ProjectWorkspace { | ||
26 | pub fn discover(path: &Path) -> Result<ProjectWorkspace> { | ||
27 | let cargo_toml = find_cargo_toml(path)?; | ||
28 | let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?; | ||
29 | let sysroot = Sysroot::discover(&cargo_toml)?; | ||
30 | let res = ProjectWorkspace { cargo, sysroot }; | ||
31 | Ok(res) | ||
32 | } | ||
33 | |||
34 | pub fn to_crate_graph(&self, load: &mut dyn FnMut(&Path) -> Option<FileId>) -> CrateGraph { | ||
35 | let mut crate_graph = CrateGraph::default(); | ||
36 | let mut sysroot_crates = FxHashMap::default(); | ||
37 | for krate in self.sysroot.crates() { | ||
38 | if let Some(file_id) = load(krate.root(&self.sysroot)) { | ||
39 | sysroot_crates.insert(krate, crate_graph.add_crate_root(file_id)); | ||
40 | } | ||
41 | } | ||
42 | for from in self.sysroot.crates() { | ||
43 | for to in from.deps(&self.sysroot) { | ||
44 | let name = to.name(&self.sysroot); | ||
45 | if let (Some(&from), Some(&to)) = | ||
46 | (sysroot_crates.get(&from), sysroot_crates.get(&to)) | ||
47 | { | ||
48 | if let Err(_) = crate_graph.add_dep(from, name.into(), to) { | ||
49 | log::error!("cyclic dependency between sysroot crates") | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | |||
55 | let libstd = self.sysroot.std().and_then(|it| sysroot_crates.get(&it).map(|&it| it)); | ||
56 | |||
57 | let mut pkg_to_lib_crate = FxHashMap::default(); | ||
58 | let mut pkg_crates = FxHashMap::default(); | ||
59 | // Next, create crates for each package, target pair | ||
60 | for pkg in self.cargo.packages() { | ||
61 | let mut lib_tgt = None; | ||
62 | for tgt in pkg.targets(&self.cargo) { | ||
63 | let root = tgt.root(&self.cargo); | ||
64 | if let Some(file_id) = load(root) { | ||
65 | let crate_id = crate_graph.add_crate_root(file_id); | ||
66 | if tgt.kind(&self.cargo) == TargetKind::Lib { | ||
67 | lib_tgt = Some(crate_id); | ||
68 | pkg_to_lib_crate.insert(pkg, crate_id); | ||
69 | } | ||
70 | pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); | ||
71 | } | ||
72 | } | ||
73 | |||
74 | // Set deps to the std and to the lib target of the current package | ||
75 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | ||
76 | if let Some(to) = lib_tgt { | ||
77 | if to != from { | ||
78 | if let Err(_) = crate_graph.add_dep(from, pkg.name(&self.cargo).into(), to) | ||
79 | { | ||
80 | log::error!( | ||
81 | "cyclic dependency between targets of {}", | ||
82 | pkg.name(&self.cargo) | ||
83 | ) | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | if let Some(std) = libstd { | ||
88 | if let Err(_) = crate_graph.add_dep(from, "std".into(), std) { | ||
89 | log::error!("cyclic dependency on std for {}", pkg.name(&self.cargo)) | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | |||
95 | // Now add a dep ednge from all targets of upstream to the lib | ||
96 | // target of downstream. | ||
97 | for pkg in self.cargo.packages() { | ||
98 | for dep in pkg.dependencies(&self.cargo) { | ||
99 | if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { | ||
100 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | ||
101 | if let Err(_) = crate_graph.add_dep(from, dep.name.clone().into(), to) { | ||
102 | log::error!( | ||
103 | "cyclic dependency {} -> {}", | ||
104 | pkg.name(&self.cargo), | ||
105 | dep.pkg.name(&self.cargo) | ||
106 | ) | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | |||
113 | crate_graph | ||
114 | } | ||
115 | } | ||
116 | |||
117 | fn find_cargo_toml(path: &Path) -> Result<PathBuf> { | ||
118 | if path.ends_with("Cargo.toml") { | ||
119 | return Ok(path.to_path_buf()); | ||
120 | } | ||
121 | let mut curr = Some(path); | ||
122 | while let Some(path) = curr { | ||
123 | let candidate = path.join("Cargo.toml"); | ||
124 | if candidate.exists() { | ||
125 | return Ok(candidate); | ||
126 | } | ||
127 | curr = path.parent(); | ||
128 | } | ||
129 | bail!("can't find Cargo.toml at {}", path.display()) | ||
130 | } | ||
diff --git a/crates/ra_lsp_server/src/project_model/sysroot.rs b/crates/ra_project_model/src/sysroot.rs index 49210ac7a..8b87aa7bd 100644 --- a/crates/ra_lsp_server/src/project_model/sysroot.rs +++ b/crates/ra_project_model/src/sysroot.rs | |||
@@ -3,7 +3,6 @@ use std::{ | |||
3 | process::Command, | 3 | process::Command, |
4 | }; | 4 | }; |
5 | 5 | ||
6 | use ra_syntax::SmolStr; | ||
7 | use ra_arena::{Arena, RawId, impl_arena_id}; | 6 | use ra_arena::{Arena, RawId, impl_arena_id}; |
8 | 7 | ||
9 | use crate::Result; | 8 | use crate::Result; |
@@ -19,21 +18,21 @@ impl_arena_id!(SysrootCrate); | |||
19 | 18 | ||
20 | #[derive(Debug, Clone)] | 19 | #[derive(Debug, Clone)] |
21 | struct SysrootCrateData { | 20 | struct SysrootCrateData { |
22 | name: SmolStr, | 21 | name: String, |
23 | root: PathBuf, | 22 | root: PathBuf, |
24 | deps: Vec<SysrootCrate>, | 23 | deps: Vec<SysrootCrate>, |
25 | } | 24 | } |
26 | 25 | ||
27 | impl Sysroot { | 26 | impl Sysroot { |
28 | pub(crate) fn std(&self) -> Option<SysrootCrate> { | 27 | pub fn std(&self) -> Option<SysrootCrate> { |
29 | self.by_name("std") | 28 | self.by_name("std") |
30 | } | 29 | } |
31 | 30 | ||
32 | pub(crate) fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + 'a { | 31 | pub fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + 'a { |
33 | self.crates.iter().map(|(id, _data)| id) | 32 | self.crates.iter().map(|(id, _data)| id) |
34 | } | 33 | } |
35 | 34 | ||
36 | pub(super) fn discover(cargo_toml: &Path) -> Result<Sysroot> { | 35 | pub fn discover(cargo_toml: &Path) -> Result<Sysroot> { |
37 | let rustc_output = Command::new("rustc") | 36 | let rustc_output = Command::new("rustc") |
38 | .current_dir(cargo_toml.parent().unwrap()) | 37 | .current_dir(cargo_toml.parent().unwrap()) |
39 | .args(&["--print", "sysroot"]) | 38 | .args(&["--print", "sysroot"]) |
@@ -80,16 +79,16 @@ impl Sysroot { | |||
80 | } | 79 | } |
81 | 80 | ||
82 | impl SysrootCrate { | 81 | impl SysrootCrate { |
83 | pub(crate) fn name(self, sysroot: &Sysroot) -> &SmolStr { | 82 | pub fn name(self, sysroot: &Sysroot) -> &str { |
84 | &sysroot.crates[self].name | 83 | &sysroot.crates[self].name |
85 | } | 84 | } |
86 | pub(crate) fn root(self, sysroot: &Sysroot) -> &Path { | 85 | pub fn root(self, sysroot: &Sysroot) -> &Path { |
87 | sysroot.crates[self].root.as_path() | 86 | sysroot.crates[self].root.as_path() |
88 | } | 87 | } |
89 | pub(crate) fn root_dir(self, sysroot: &Sysroot) -> &Path { | 88 | pub fn root_dir(self, sysroot: &Sysroot) -> &Path { |
90 | self.root(sysroot).parent().unwrap() | 89 | self.root(sysroot).parent().unwrap() |
91 | } | 90 | } |
92 | pub(crate) fn deps<'a>(self, sysroot: &'a Sysroot) -> impl Iterator<Item = SysrootCrate> + 'a { | 91 | pub fn deps<'a>(self, sysroot: &'a Sysroot) -> impl Iterator<Item = SysrootCrate> + 'a { |
93 | sysroot.crates[self].deps.iter().map(|&it| it) | 92 | sysroot.crates[self].deps.iter().map(|&it| it) |
94 | } | 93 | } |
95 | } | 94 | } |
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml index 0ec8492aa..7c7a85a75 100644 --- a/crates/ra_syntax/Cargo.toml +++ b/crates/ra_syntax/Cargo.toml | |||
@@ -15,7 +15,7 @@ drop_bomb = "0.1.4" | |||
15 | parking_lot = "0.7.0" | 15 | parking_lot = "0.7.0" |
16 | rowan = "0.3.3" | 16 | rowan = "0.3.3" |
17 | 17 | ||
18 | # ideally, `serde` should be enabled by `ra_lsp_serder`, but we enable it here | 18 | # ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here |
19 | # to reduce number of compilations | 19 | # to reduce number of compilations |
20 | text_unit = { version = "0.1.6", features = ["serde"] } | 20 | text_unit = { version = "0.1.6", features = ["serde"] } |
21 | smol_str = { version = "0.1.9", features = ["serde"] } | 21 | smol_str = { version = "0.1.9", features = ["serde"] } |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 60314d245..256277609 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -1821,6 +1821,38 @@ impl LiteralExpr { | |||
1821 | 1821 | ||
1822 | impl LiteralExpr {} | 1822 | impl LiteralExpr {} |
1823 | 1823 | ||
1824 | // LiteralPat | ||
1825 | #[derive(Debug, PartialEq, Eq, Hash)] | ||
1826 | #[repr(transparent)] | ||
1827 | pub struct LiteralPat { | ||
1828 | pub(crate) syntax: SyntaxNode, | ||
1829 | } | ||
1830 | unsafe impl TransparentNewType for LiteralPat { | ||
1831 | type Repr = rowan::SyntaxNode<RaTypes>; | ||
1832 | } | ||
1833 | |||
1834 | impl AstNode for LiteralPat { | ||
1835 | fn cast(syntax: &SyntaxNode) -> Option<&Self> { | ||
1836 | match syntax.kind() { | ||
1837 | LITERAL_PAT => Some(LiteralPat::from_repr(syntax.into_repr())), | ||
1838 | _ => None, | ||
1839 | } | ||
1840 | } | ||
1841 | fn syntax(&self) -> &SyntaxNode { &self.syntax } | ||
1842 | } | ||
1843 | |||
1844 | impl ToOwned for LiteralPat { | ||
1845 | type Owned = TreeArc<LiteralPat>; | ||
1846 | fn to_owned(&self) -> TreeArc<LiteralPat> { TreeArc::cast(self.syntax.to_owned()) } | ||
1847 | } | ||
1848 | |||
1849 | |||
1850 | impl LiteralPat { | ||
1851 | pub fn literal(&self) -> Option<&Literal> { | ||
1852 | super::child_opt(self) | ||
1853 | } | ||
1854 | } | ||
1855 | |||
1824 | // LoopExpr | 1856 | // LoopExpr |
1825 | #[derive(Debug, PartialEq, Eq, Hash)] | 1857 | #[derive(Debug, PartialEq, Eq, Hash)] |
1826 | #[repr(transparent)] | 1858 | #[repr(transparent)] |
@@ -2594,6 +2626,7 @@ pub enum PatKind<'a> { | |||
2594 | TuplePat(&'a TuplePat), | 2626 | TuplePat(&'a TuplePat), |
2595 | SlicePat(&'a SlicePat), | 2627 | SlicePat(&'a SlicePat), |
2596 | RangePat(&'a RangePat), | 2628 | RangePat(&'a RangePat), |
2629 | LiteralPat(&'a LiteralPat), | ||
2597 | } | 2630 | } |
2598 | 2631 | ||
2599 | impl AstNode for Pat { | 2632 | impl AstNode for Pat { |
@@ -2607,7 +2640,8 @@ impl AstNode for Pat { | |||
2607 | | TUPLE_STRUCT_PAT | 2640 | | TUPLE_STRUCT_PAT |
2608 | | TUPLE_PAT | 2641 | | TUPLE_PAT |
2609 | | SLICE_PAT | 2642 | | SLICE_PAT |
2610 | | RANGE_PAT => Some(Pat::from_repr(syntax.into_repr())), | 2643 | | RANGE_PAT |
2644 | | LITERAL_PAT => Some(Pat::from_repr(syntax.into_repr())), | ||
2611 | _ => None, | 2645 | _ => None, |
2612 | } | 2646 | } |
2613 | } | 2647 | } |
@@ -2631,6 +2665,7 @@ impl Pat { | |||
2631 | TUPLE_PAT => PatKind::TuplePat(TuplePat::cast(&self.syntax).unwrap()), | 2665 | TUPLE_PAT => PatKind::TuplePat(TuplePat::cast(&self.syntax).unwrap()), |
2632 | SLICE_PAT => PatKind::SlicePat(SlicePat::cast(&self.syntax).unwrap()), | 2666 | SLICE_PAT => PatKind::SlicePat(SlicePat::cast(&self.syntax).unwrap()), |
2633 | RANGE_PAT => PatKind::RangePat(RangePat::cast(&self.syntax).unwrap()), | 2667 | RANGE_PAT => PatKind::RangePat(RangePat::cast(&self.syntax).unwrap()), |
2668 | LITERAL_PAT => PatKind::LiteralPat(LiteralPat::cast(&self.syntax).unwrap()), | ||
2634 | _ => unreachable!(), | 2669 | _ => unreachable!(), |
2635 | } | 2670 | } |
2636 | } | 2671 | } |
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 046db5885..d428bc595 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -161,6 +161,7 @@ Grammar( | |||
161 | "TUPLE_PAT", | 161 | "TUPLE_PAT", |
162 | "SLICE_PAT", | 162 | "SLICE_PAT", |
163 | "RANGE_PAT", | 163 | "RANGE_PAT", |
164 | "LITERAL_PAT", | ||
164 | 165 | ||
165 | // atoms | 166 | // atoms |
166 | "TUPLE_EXPR", | 167 | "TUPLE_EXPR", |
@@ -524,6 +525,7 @@ Grammar( | |||
524 | "TuplePat": ( collections: [["args", "Pat"]] ), | 525 | "TuplePat": ( collections: [["args", "Pat"]] ), |
525 | "SlicePat": (), | 526 | "SlicePat": (), |
526 | "RangePat": (), | 527 | "RangePat": (), |
528 | "LiteralPat": (options: ["Literal"]), | ||
527 | 529 | ||
528 | "Pat": ( | 530 | "Pat": ( |
529 | enum: [ | 531 | enum: [ |
@@ -536,6 +538,7 @@ Grammar( | |||
536 | "TuplePat", | 538 | "TuplePat", |
537 | "SlicePat", | 539 | "SlicePat", |
538 | "RangePat", | 540 | "RangePat", |
541 | "LiteralPat", | ||
539 | ], | 542 | ], |
540 | ), | 543 | ), |
541 | 544 | ||
diff --git a/crates/ra_syntax/src/grammar/patterns.rs b/crates/ra_syntax/src/grammar/patterns.rs index f3f400ae0..9d7da639d 100644 --- a/crates/ra_syntax/src/grammar/patterns.rs +++ b/crates/ra_syntax/src/grammar/patterns.rs | |||
@@ -43,21 +43,8 @@ fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { | |||
43 | return Some(path_pat(p)); | 43 | return Some(path_pat(p)); |
44 | } | 44 | } |
45 | 45 | ||
46 | // test literal_pattern | 46 | if is_literal_pat_start(p) { |
47 | // fn main() { | 47 | return Some(literal_pat(p)); |
48 | // match () { | ||
49 | // -1 => (), | ||
50 | // 92 => (), | ||
51 | // 'c' => (), | ||
52 | // "hello" => (), | ||
53 | // } | ||
54 | // } | ||
55 | if p.at(MINUS) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER) { | ||
56 | p.bump(); | ||
57 | } | ||
58 | |||
59 | if let Some(m) = expressions::literal(p) { | ||
60 | return Some(m); | ||
61 | } | 48 | } |
62 | 49 | ||
63 | let m = match la0 { | 50 | let m = match la0 { |
@@ -73,6 +60,30 @@ fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> { | |||
73 | Some(m) | 60 | Some(m) |
74 | } | 61 | } |
75 | 62 | ||
63 | fn is_literal_pat_start(p: &mut Parser) -> bool { | ||
64 | p.at(MINUS) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER) | ||
65 | || p.at_ts(expressions::LITERAL_FIRST) | ||
66 | } | ||
67 | |||
68 | // test literal_pattern | ||
69 | // fn main() { | ||
70 | // match () { | ||
71 | // -1 => (), | ||
72 | // 92 => (), | ||
73 | // 'c' => (), | ||
74 | // "hello" => (), | ||
75 | // } | ||
76 | // } | ||
77 | fn literal_pat(p: &mut Parser) -> CompletedMarker { | ||
78 | assert!(is_literal_pat_start(p)); | ||
79 | let m = p.start(); | ||
80 | if p.at(MINUS) { | ||
81 | p.bump(); | ||
82 | } | ||
83 | expressions::literal(p); | ||
84 | m.complete(p, LITERAL_PAT) | ||
85 | } | ||
86 | |||
76 | // test path_part | 87 | // test path_part |
77 | // fn foo() { | 88 | // fn foo() { |
78 | // let foo::Bar = (); | 89 | // let foo::Bar = (); |
diff --git a/crates/ra_syntax/src/syntax_kinds/generated.rs b/crates/ra_syntax/src/syntax_kinds/generated.rs index fea513458..266b95bbb 100644 --- a/crates/ra_syntax/src/syntax_kinds/generated.rs +++ b/crates/ra_syntax/src/syntax_kinds/generated.rs | |||
@@ -157,6 +157,7 @@ pub enum SyntaxKind { | |||
157 | TUPLE_PAT, | 157 | TUPLE_PAT, |
158 | SLICE_PAT, | 158 | SLICE_PAT, |
159 | RANGE_PAT, | 159 | RANGE_PAT, |
160 | LITERAL_PAT, | ||
160 | TUPLE_EXPR, | 161 | TUPLE_EXPR, |
161 | ARRAY_EXPR, | 162 | ARRAY_EXPR, |
162 | PAREN_EXPR, | 163 | PAREN_EXPR, |
@@ -493,6 +494,7 @@ impl SyntaxKind { | |||
493 | TUPLE_PAT => &SyntaxInfo { name: "TUPLE_PAT" }, | 494 | TUPLE_PAT => &SyntaxInfo { name: "TUPLE_PAT" }, |
494 | SLICE_PAT => &SyntaxInfo { name: "SLICE_PAT" }, | 495 | SLICE_PAT => &SyntaxInfo { name: "SLICE_PAT" }, |
495 | RANGE_PAT => &SyntaxInfo { name: "RANGE_PAT" }, | 496 | RANGE_PAT => &SyntaxInfo { name: "RANGE_PAT" }, |
497 | LITERAL_PAT => &SyntaxInfo { name: "LITERAL_PAT" }, | ||
496 | TUPLE_EXPR => &SyntaxInfo { name: "TUPLE_EXPR" }, | 498 | TUPLE_EXPR => &SyntaxInfo { name: "TUPLE_EXPR" }, |
497 | ARRAY_EXPR => &SyntaxInfo { name: "ARRAY_EXPR" }, | 499 | ARRAY_EXPR => &SyntaxInfo { name: "ARRAY_EXPR" }, |
498 | PAREN_EXPR => &SyntaxInfo { name: "PAREN_EXPR" }, | 500 | PAREN_EXPR => &SyntaxInfo { name: "PAREN_EXPR" }, |
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0055_literal_pattern.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0055_literal_pattern.txt index 71d62eaba..51c5ab7f2 100644 --- a/crates/ra_syntax/tests/data/parser/inline/ok/0055_literal_pattern.txt +++ b/crates/ra_syntax/tests/data/parser/inline/ok/0055_literal_pattern.txt | |||
@@ -22,9 +22,10 @@ SOURCE_FILE@[0; 113) | |||
22 | L_CURLY@[25; 26) | 22 | L_CURLY@[25; 26) |
23 | WHITESPACE@[26; 35) | 23 | WHITESPACE@[26; 35) |
24 | MATCH_ARM@[35; 43) | 24 | MATCH_ARM@[35; 43) |
25 | MINUS@[35; 36) | 25 | LITERAL_PAT@[35; 37) |
26 | LITERAL@[36; 37) | 26 | MINUS@[35; 36) |
27 | INT_NUMBER@[36; 37) "1" | 27 | LITERAL@[36; 37) |
28 | INT_NUMBER@[36; 37) "1" | ||
28 | WHITESPACE@[37; 38) | 29 | WHITESPACE@[37; 38) |
29 | FAT_ARROW@[38; 40) | 30 | FAT_ARROW@[38; 40) |
30 | WHITESPACE@[40; 41) | 31 | WHITESPACE@[40; 41) |
@@ -34,8 +35,9 @@ SOURCE_FILE@[0; 113) | |||
34 | COMMA@[43; 44) | 35 | COMMA@[43; 44) |
35 | WHITESPACE@[44; 53) | 36 | WHITESPACE@[44; 53) |
36 | MATCH_ARM@[53; 61) | 37 | MATCH_ARM@[53; 61) |
37 | LITERAL@[53; 55) | 38 | LITERAL_PAT@[53; 55) |
38 | INT_NUMBER@[53; 55) "92" | 39 | LITERAL@[53; 55) |
40 | INT_NUMBER@[53; 55) "92" | ||
39 | WHITESPACE@[55; 56) | 41 | WHITESPACE@[55; 56) |
40 | FAT_ARROW@[56; 58) | 42 | FAT_ARROW@[56; 58) |
41 | WHITESPACE@[58; 59) | 43 | WHITESPACE@[58; 59) |
@@ -45,8 +47,9 @@ SOURCE_FILE@[0; 113) | |||
45 | COMMA@[61; 62) | 47 | COMMA@[61; 62) |
46 | WHITESPACE@[62; 71) | 48 | WHITESPACE@[62; 71) |
47 | MATCH_ARM@[71; 80) | 49 | MATCH_ARM@[71; 80) |
48 | LITERAL@[71; 74) | 50 | LITERAL_PAT@[71; 74) |
49 | CHAR@[71; 74) | 51 | LITERAL@[71; 74) |
52 | CHAR@[71; 74) | ||
50 | WHITESPACE@[74; 75) | 53 | WHITESPACE@[74; 75) |
51 | FAT_ARROW@[75; 77) | 54 | FAT_ARROW@[75; 77) |
52 | WHITESPACE@[77; 78) | 55 | WHITESPACE@[77; 78) |
@@ -56,8 +59,9 @@ SOURCE_FILE@[0; 113) | |||
56 | COMMA@[80; 81) | 59 | COMMA@[80; 81) |
57 | WHITESPACE@[81; 90) | 60 | WHITESPACE@[81; 90) |
58 | MATCH_ARM@[90; 103) | 61 | MATCH_ARM@[90; 103) |
59 | LITERAL@[90; 97) | 62 | LITERAL_PAT@[90; 97) |
60 | STRING@[90; 97) | 63 | LITERAL@[90; 97) |
64 | STRING@[90; 97) | ||
61 | WHITESPACE@[97; 98) | 65 | WHITESPACE@[97; 98) |
62 | FAT_ARROW@[98; 100) | 66 | FAT_ARROW@[98; 100) |
63 | WHITESPACE@[100; 101) | 67 | WHITESPACE@[100; 101) |
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0058_range_pat.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0058_range_pat.txt index d47f38903..de54c49e6 100644 --- a/crates/ra_syntax/tests/data/parser/inline/ok/0058_range_pat.txt +++ b/crates/ra_syntax/tests/data/parser/inline/ok/0058_range_pat.txt | |||
@@ -22,13 +22,15 @@ SOURCE_FILE@[0; 112) | |||
22 | WHITESPACE@[26; 35) | 22 | WHITESPACE@[26; 35) |
23 | MATCH_ARM@[35; 50) | 23 | MATCH_ARM@[35; 50) |
24 | RANGE_PAT@[35; 44) | 24 | RANGE_PAT@[35; 44) |
25 | LITERAL@[35; 36) | 25 | LITERAL_PAT@[35; 36) |
26 | INT_NUMBER@[35; 36) "0" | 26 | LITERAL@[35; 36) |
27 | INT_NUMBER@[35; 36) "0" | ||
27 | WHITESPACE@[36; 37) | 28 | WHITESPACE@[36; 37) |
28 | DOTDOTDOT@[37; 40) | 29 | DOTDOTDOT@[37; 40) |
29 | WHITESPACE@[40; 41) | 30 | WHITESPACE@[40; 41) |
30 | LITERAL@[41; 44) | 31 | LITERAL_PAT@[41; 44) |
31 | INT_NUMBER@[41; 44) "100" | 32 | LITERAL@[41; 44) |
33 | INT_NUMBER@[41; 44) "100" | ||
32 | WHITESPACE@[44; 45) | 34 | WHITESPACE@[44; 45) |
33 | FAT_ARROW@[45; 47) | 35 | FAT_ARROW@[45; 47) |
34 | WHITESPACE@[47; 48) | 36 | WHITESPACE@[47; 48) |
@@ -39,13 +41,15 @@ SOURCE_FILE@[0; 112) | |||
39 | WHITESPACE@[51; 60) | 41 | WHITESPACE@[51; 60) |
40 | MATCH_ARM@[60; 77) | 42 | MATCH_ARM@[60; 77) |
41 | RANGE_PAT@[60; 71) | 43 | RANGE_PAT@[60; 71) |
42 | LITERAL@[60; 63) | 44 | LITERAL_PAT@[60; 63) |
43 | INT_NUMBER@[60; 63) "101" | 45 | LITERAL@[60; 63) |
46 | INT_NUMBER@[60; 63) "101" | ||
44 | WHITESPACE@[63; 64) | 47 | WHITESPACE@[63; 64) |
45 | DOTDOTEQ@[64; 67) | 48 | DOTDOTEQ@[64; 67) |
46 | WHITESPACE@[67; 68) | 49 | WHITESPACE@[67; 68) |
47 | LITERAL@[68; 71) | 50 | LITERAL_PAT@[68; 71) |
48 | INT_NUMBER@[68; 71) "200" | 51 | LITERAL@[68; 71) |
52 | INT_NUMBER@[68; 71) "200" | ||
49 | WHITESPACE@[71; 72) | 53 | WHITESPACE@[71; 72) |
50 | FAT_ARROW@[72; 74) | 54 | FAT_ARROW@[72; 74) |
51 | WHITESPACE@[74; 75) | 55 | WHITESPACE@[74; 75) |
@@ -56,13 +60,15 @@ SOURCE_FILE@[0; 112) | |||
56 | WHITESPACE@[78; 87) | 60 | WHITESPACE@[78; 87) |
57 | MATCH_ARM@[87; 102) | 61 | MATCH_ARM@[87; 102) |
58 | RANGE_PAT@[87; 97) | 62 | RANGE_PAT@[87; 97) |
59 | LITERAL@[87; 90) | 63 | LITERAL_PAT@[87; 90) |
60 | INT_NUMBER@[87; 90) "200" | 64 | LITERAL@[87; 90) |
65 | INT_NUMBER@[87; 90) "200" | ||
61 | WHITESPACE@[90; 91) | 66 | WHITESPACE@[90; 91) |
62 | DOTDOT@[91; 93) | 67 | DOTDOT@[91; 93) |
63 | WHITESPACE@[93; 94) | 68 | WHITESPACE@[93; 94) |
64 | LITERAL@[94; 97) | 69 | LITERAL_PAT@[94; 97) |
65 | INT_NUMBER@[94; 97) "301" | 70 | LITERAL@[94; 97) |
71 | INT_NUMBER@[94; 97) "301" | ||
66 | FAT_ARROW@[97; 99) | 72 | FAT_ARROW@[97; 99) |
67 | WHITESPACE@[99; 100) | 73 | WHITESPACE@[99; 100) |
68 | TUPLE_EXPR@[100; 102) | 74 | TUPLE_EXPR@[100; 102) |
diff --git a/crates/ra_syntax/tests/data/parser/ok/0035_weird_exprs.txt b/crates/ra_syntax/tests/data/parser/ok/0035_weird_exprs.txt index 20932a837..f3987c3b7 100644 --- a/crates/ra_syntax/tests/data/parser/ok/0035_weird_exprs.txt +++ b/crates/ra_syntax/tests/data/parser/ok/0035_weird_exprs.txt | |||
@@ -456,8 +456,9 @@ SOURCE_FILE@[0; 3813) | |||
456 | L_CURLY@[930; 931) | 456 | L_CURLY@[930; 931) |
457 | WHITESPACE@[931; 952) | 457 | WHITESPACE@[931; 952) |
458 | MATCH_ARM@[952; 1147) | 458 | MATCH_ARM@[952; 1147) |
459 | LITERAL@[952; 953) | 459 | LITERAL_PAT@[952; 953) |
460 | INT_NUMBER@[952; 953) "1" | 460 | LITERAL@[952; 953) |
461 | INT_NUMBER@[952; 953) "1" | ||
461 | WHITESPACE@[953; 954) | 462 | WHITESPACE@[953; 954) |
462 | FAT_ARROW@[954; 956) | 463 | FAT_ARROW@[954; 956) |
463 | WHITESPACE@[956; 957) | 464 | WHITESPACE@[956; 957) |
@@ -1080,8 +1081,9 @@ SOURCE_FILE@[0; 3813) | |||
1080 | L_CURLY@[1853; 1854) | 1081 | L_CURLY@[1853; 1854) |
1081 | WHITESPACE@[1854; 1855) | 1082 | WHITESPACE@[1854; 1855) |
1082 | MATCH_ARM@[1855; 1863) | 1083 | MATCH_ARM@[1855; 1863) |
1083 | LITERAL@[1855; 1856) | 1084 | LITERAL_PAT@[1855; 1856) |
1084 | INT_NUMBER@[1855; 1856) "1" | 1085 | LITERAL@[1855; 1856) |
1086 | INT_NUMBER@[1855; 1856) "1" | ||
1085 | WHITESPACE@[1856; 1857) | 1087 | WHITESPACE@[1856; 1857) |
1086 | FAT_ARROW@[1857; 1859) | 1088 | FAT_ARROW@[1857; 1859) |
1087 | WHITESPACE@[1859; 1860) | 1089 | WHITESPACE@[1859; 1860) |
diff --git a/crates/ra_vfs/Cargo.toml b/crates/ra_vfs/Cargo.toml index 383381d2a..01109a9a7 100644 --- a/crates/ra_vfs/Cargo.toml +++ b/crates/ra_vfs/Cargo.toml | |||
@@ -10,7 +10,7 @@ relative-path = "0.4.0" | |||
10 | rustc-hash = "1.0" | 10 | rustc-hash = "1.0" |
11 | crossbeam-channel = "0.3.5" | 11 | crossbeam-channel = "0.3.5" |
12 | log = "0.4.6" | 12 | log = "0.4.6" |
13 | notify = "4.0.7" | 13 | notify = "4.0.9" |
14 | drop_bomb = "0.1.0" | 14 | drop_bomb = "0.1.0" |
15 | parking_lot = "0.7.0" | 15 | parking_lot = "0.7.0" |
16 | 16 | ||
diff --git a/crates/ra_vfs/src/lib.rs b/crates/ra_vfs/src/lib.rs index 6b4eb6842..3805be570 100644 --- a/crates/ra_vfs/src/lib.rs +++ b/crates/ra_vfs/src/lib.rs | |||
@@ -94,6 +94,7 @@ impl Roots { | |||
94 | let mut roots = Arena::default(); | 94 | let mut roots = Arena::default(); |
95 | // A hack to make nesting work. | 95 | // A hack to make nesting work. |
96 | paths.sort_by_key(|it| Reverse(it.as_os_str().len())); | 96 | paths.sort_by_key(|it| Reverse(it.as_os_str().len())); |
97 | paths.dedup(); | ||
97 | for (i, path) in paths.iter().enumerate() { | 98 | for (i, path) in paths.iter().enumerate() { |
98 | let nested_roots = paths[..i] | 99 | let nested_roots = paths[..i] |
99 | .iter() | 100 | .iter() |
@@ -181,6 +182,10 @@ impl Vfs { | |||
181 | None | 182 | None |
182 | } | 183 | } |
183 | 184 | ||
185 | pub fn num_roots(&self) -> usize { | ||
186 | self.roots.len() | ||
187 | } | ||
188 | |||
184 | pub fn load(&mut self, path: &Path) -> Option<VfsFile> { | 189 | pub fn load(&mut self, path: &Path) -> Option<VfsFile> { |
185 | if let Some((root, rel_path, file)) = self.find_root(path) { | 190 | if let Some((root, rel_path, file)) = self.find_root(path) { |
186 | return if let Some(file) = file { | 191 | return if let Some(file) = file { |