diff options
Diffstat (limited to 'crates')
74 files changed, 1871 insertions, 639 deletions
diff --git a/crates/ra_arena/src/lib.rs b/crates/ra_arena/src/lib.rs index 3b7cb77b1..3ec8d3b60 100644 --- a/crates/ra_arena/src/lib.rs +++ b/crates/ra_arena/src/lib.rs | |||
@@ -79,7 +79,7 @@ impl<ID: ArenaId, T> Arena<ID, T> { | |||
79 | self.data.push(value); | 79 | self.data.push(value); |
80 | ID::from_raw(id) | 80 | ID::from_raw(id) |
81 | } | 81 | } |
82 | pub fn iter(&self) -> impl Iterator<Item = (ID, &T)> { | 82 | pub fn iter(&self) -> impl Iterator<Item = (ID, &T)> + ExactSizeIterator { |
83 | self.data.iter().enumerate().map(|(idx, value)| (ID::from_raw(RawId(idx as u32)), value)) | 83 | self.data.iter().enumerate().map(|(idx, value)| (ID::from_raw(RawId(idx as u32)), value)) |
84 | } | 84 | } |
85 | } | 85 | } |
diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs index a32e2f9b6..1158adbbc 100644 --- a/crates/ra_assists/src/auto_import.rs +++ b/crates/ra_assists/src/auto_import.rs | |||
@@ -71,6 +71,7 @@ fn compare_path_segment(a: &SmolStr, b: &ast::PathSegment) -> bool { | |||
71 | ast::PathSegmentKind::SelfKw => a == "self", | 71 | ast::PathSegmentKind::SelfKw => a == "self", |
72 | ast::PathSegmentKind::SuperKw => a == "super", | 72 | ast::PathSegmentKind::SuperKw => a == "super", |
73 | ast::PathSegmentKind::CrateKw => a == "crate", | 73 | ast::PathSegmentKind::CrateKw => a == "crate", |
74 | ast::PathSegmentKind::Type { .. } => false, // not allowed in imports | ||
74 | } | 75 | } |
75 | } else { | 76 | } else { |
76 | false | 77 | false |
diff --git a/crates/ra_batch/Cargo.toml b/crates/ra_batch/Cargo.toml index 0ee94c445..8e23826a4 100644 --- a/crates/ra_batch/Cargo.toml +++ b/crates/ra_batch/Cargo.toml | |||
@@ -9,6 +9,7 @@ log = "0.4.5" | |||
9 | rustc-hash = "1.0" | 9 | rustc-hash = "1.0" |
10 | 10 | ||
11 | ra_vfs = "0.2.0" | 11 | ra_vfs = "0.2.0" |
12 | ra_vfs_glob = { path = "../ra_vfs_glob" } | ||
12 | ra_db = { path = "../ra_db" } | 13 | ra_db = { path = "../ra_db" } |
13 | ra_ide_api = { path = "../ra_ide_api" } | 14 | ra_ide_api = { path = "../ra_ide_api" } |
14 | ra_hir = { path = "../ra_hir" } | 15 | ra_hir = { path = "../ra_hir" } |
diff --git a/crates/ra_batch/src/lib.rs b/crates/ra_batch/src/lib.rs index c25737aaa..0db751465 100644 --- a/crates/ra_batch/src/lib.rs +++ b/crates/ra_batch/src/lib.rs | |||
@@ -1,14 +1,12 @@ | |||
1 | mod vfs_filter; | ||
2 | |||
3 | use std::{collections::HashSet, error::Error, path::Path}; | 1 | use std::{collections::HashSet, error::Error, path::Path}; |
4 | 2 | ||
5 | use rustc_hash::FxHashMap; | 3 | use rustc_hash::FxHashMap; |
6 | 4 | ||
7 | use ra_db::{CrateGraph, FileId, SourceRootId}; | 5 | use ra_db::{CrateGraph, FileId, SourceRootId}; |
8 | use ra_ide_api::{AnalysisChange, AnalysisHost}; | 6 | use ra_ide_api::{AnalysisChange, AnalysisHost}; |
9 | use ra_project_model::{ProjectRoot, ProjectWorkspace}; | 7 | use ra_project_model::{PackageRoot, ProjectWorkspace}; |
10 | use ra_vfs::{Vfs, VfsChange}; | 8 | use ra_vfs::{RootEntry, Vfs, VfsChange}; |
11 | use vfs_filter::IncludeRustFiles; | 9 | use ra_vfs_glob::RustPackageFilterBuilder; |
12 | 10 | ||
13 | type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>; | 11 | type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>; |
14 | 12 | ||
@@ -19,11 +17,23 @@ fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId { | |||
19 | SourceRootId(r.0) | 17 | SourceRootId(r.0) |
20 | } | 18 | } |
21 | 19 | ||
22 | pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId, ProjectRoot>)> { | 20 | pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> { |
23 | let root = std::env::current_dir()?.join(root); | 21 | let root = std::env::current_dir()?.join(root); |
24 | let ws = ProjectWorkspace::discover(root.as_ref())?; | 22 | let ws = ProjectWorkspace::discover(root.as_ref())?; |
25 | let project_roots = ws.to_roots(); | 23 | let project_roots = ws.to_roots(); |
26 | let (mut vfs, roots) = Vfs::new(IncludeRustFiles::from_roots(project_roots.clone()).collect()); | 24 | let (mut vfs, roots) = Vfs::new( |
25 | project_roots | ||
26 | .iter() | ||
27 | .map(|pkg_root| { | ||
28 | RootEntry::new( | ||
29 | pkg_root.path().clone(), | ||
30 | RustPackageFilterBuilder::default() | ||
31 | .set_member(pkg_root.is_member()) | ||
32 | .into_vfs_filter(), | ||
33 | ) | ||
34 | }) | ||
35 | .collect(), | ||
36 | ); | ||
27 | let crate_graph = ws.to_crate_graph(&mut |path: &Path| { | 37 | let crate_graph = ws.to_crate_graph(&mut |path: &Path| { |
28 | let vfs_file = vfs.load(path); | 38 | let vfs_file = vfs.load(path); |
29 | log::debug!("vfs file {:?} -> {:?}", path, vfs_file); | 39 | log::debug!("vfs file {:?} -> {:?}", path, vfs_file); |
@@ -48,7 +58,7 @@ pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId, | |||
48 | } | 58 | } |
49 | 59 | ||
50 | pub fn load( | 60 | pub fn load( |
51 | source_roots: &FxHashMap<SourceRootId, ProjectRoot>, | 61 | source_roots: &FxHashMap<SourceRootId, PackageRoot>, |
52 | crate_graph: CrateGraph, | 62 | crate_graph: CrateGraph, |
53 | vfs: &mut Vfs, | 63 | vfs: &mut Vfs, |
54 | ) -> AnalysisHost { | 64 | ) -> AnalysisHost { |
diff --git a/crates/ra_batch/src/vfs_filter.rs b/crates/ra_batch/src/vfs_filter.rs deleted file mode 100644 index 2f0d8cb8b..000000000 --- a/crates/ra_batch/src/vfs_filter.rs +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | use ra_project_model::ProjectRoot; | ||
2 | use ra_vfs::{Filter, RelativePath, RootEntry}; | ||
3 | use std::path::PathBuf; | ||
4 | |||
5 | /// `IncludeRustFiles` is used to convert | ||
6 | /// from `ProjectRoot` to `RootEntry` for VFS | ||
7 | pub struct IncludeRustFiles { | ||
8 | root: ProjectRoot, | ||
9 | } | ||
10 | |||
11 | impl IncludeRustFiles { | ||
12 | pub fn from_roots<R>(roots: R) -> impl Iterator<Item = RootEntry> | ||
13 | where | ||
14 | R: IntoIterator<Item = ProjectRoot>, | ||
15 | { | ||
16 | roots.into_iter().map(IncludeRustFiles::from_root) | ||
17 | } | ||
18 | |||
19 | pub fn from_root(root: ProjectRoot) -> RootEntry { | ||
20 | IncludeRustFiles::from(root).into() | ||
21 | } | ||
22 | |||
23 | #[allow(unused)] | ||
24 | pub fn external(path: PathBuf) -> RootEntry { | ||
25 | IncludeRustFiles::from_root(ProjectRoot::new(path, false)) | ||
26 | } | ||
27 | |||
28 | pub fn member(path: PathBuf) -> RootEntry { | ||
29 | IncludeRustFiles::from_root(ProjectRoot::new(path, true)) | ||
30 | } | ||
31 | } | ||
32 | |||
33 | impl Filter for IncludeRustFiles { | ||
34 | fn include_dir(&self, dir_path: &RelativePath) -> bool { | ||
35 | self.root.include_dir(dir_path) | ||
36 | } | ||
37 | |||
38 | fn include_file(&self, file_path: &RelativePath) -> bool { | ||
39 | self.root.include_file(file_path) | ||
40 | } | ||
41 | } | ||
42 | |||
43 | impl From<ProjectRoot> for IncludeRustFiles { | ||
44 | fn from(v: ProjectRoot) -> IncludeRustFiles { | ||
45 | IncludeRustFiles { root: v } | ||
46 | } | ||
47 | } | ||
48 | |||
49 | impl From<IncludeRustFiles> for RootEntry { | ||
50 | fn from(v: IncludeRustFiles) -> RootEntry { | ||
51 | let path = v.root.path().clone(); | ||
52 | RootEntry::new(path, Box::new(v)) | ||
53 | } | ||
54 | } | ||
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs index 403aab352..7e7e6c073 100644 --- a/crates/ra_cli/src/analysis_stats.rs +++ b/crates/ra_cli/src/analysis_stats.rs | |||
@@ -52,6 +52,9 @@ pub fn run(verbose: bool, memory_usage: bool, path: &Path, only: Option<&str>) - | |||
52 | println!("Total modules found: {}", visited_modules.len()); | 52 | println!("Total modules found: {}", visited_modules.len()); |
53 | println!("Total declarations: {}", num_decls); | 53 | println!("Total declarations: {}", num_decls); |
54 | println!("Total functions: {}", funcs.len()); | 54 | println!("Total functions: {}", funcs.len()); |
55 | println!("Item Collection: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage()); | ||
56 | |||
57 | let inference_time = Instant::now(); | ||
55 | let bar = indicatif::ProgressBar::with_draw_target( | 58 | let bar = indicatif::ProgressBar::with_draw_target( |
56 | funcs.len() as u64, | 59 | funcs.len() as u64, |
57 | indicatif::ProgressDrawTarget::stderr_nohz(), | 60 | indicatif::ProgressDrawTarget::stderr_nohz(), |
@@ -112,7 +115,8 @@ pub fn run(verbose: bool, memory_usage: bool, path: &Path, only: Option<&str>) - | |||
112 | num_exprs_partially_unknown, | 115 | num_exprs_partially_unknown, |
113 | (num_exprs_partially_unknown * 100 / num_exprs) | 116 | (num_exprs_partially_unknown * 100 / num_exprs) |
114 | ); | 117 | ); |
115 | println!("Analysis: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage()); | 118 | println!("Inference: {:?}, {}", inference_time.elapsed(), ra_prof::memory_usage()); |
119 | println!("Total: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage()); | ||
116 | 120 | ||
117 | if memory_usage { | 121 | if memory_usage { |
118 | drop(db); | 122 | drop(db); |
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index 285b3c63a..1a2f1b47c 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml | |||
@@ -27,4 +27,4 @@ chalk-ir = { git = "https://github.com/rust-lang/chalk.git" } | |||
27 | lalrpop-intern = "0.15.1" | 27 | lalrpop-intern = "0.15.1" |
28 | 28 | ||
29 | [dev-dependencies] | 29 | [dev-dependencies] |
30 | insta = "0.9.0" | 30 | insta = "0.10.0" |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 779764590..89fc1d1a1 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -838,6 +838,10 @@ impl TypeAlias { | |||
838 | self.id.module(db) | 838 | self.id.module(db) |
839 | } | 839 | } |
840 | 840 | ||
841 | pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { | ||
842 | self.module(db).krate(db) | ||
843 | } | ||
844 | |||
841 | /// The containing impl block, if this is a method. | 845 | /// The containing impl block, if this is a method. |
842 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { | 846 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { |
843 | let module_impls = db.impls_in_module(self.module(db)); | 847 | let module_impls = db.impls_in_module(self.module(db)); |
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs index 0290483b3..f6240830f 100644 --- a/crates/ra_hir/src/diagnostics.rs +++ b/crates/ra_hir/src/diagnostics.rs | |||
@@ -3,7 +3,7 @@ use std::{any::Any, fmt}; | |||
3 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, TextRange}; | 3 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, TextRange}; |
4 | use relative_path::RelativePathBuf; | 4 | use relative_path::RelativePathBuf; |
5 | 5 | ||
6 | use crate::{HirDatabase, HirFileId, Name}; | 6 | use crate::{HirDatabase, HirFileId, Name, Source}; |
7 | 7 | ||
8 | /// Diagnostic defines hir API for errors and warnings. | 8 | /// Diagnostic defines hir API for errors and warnings. |
9 | /// | 9 | /// |
@@ -19,10 +19,9 @@ use crate::{HirDatabase, HirFileId, Name}; | |||
19 | /// instance of `Diagnostic` on demand. | 19 | /// instance of `Diagnostic` on demand. |
20 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { | 20 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { |
21 | fn message(&self) -> String; | 21 | fn message(&self) -> String; |
22 | fn file(&self) -> HirFileId; | 22 | fn source(&self) -> Source<SyntaxNodePtr>; |
23 | fn syntax_node_ptr(&self) -> SyntaxNodePtr; | ||
24 | fn highlight_range(&self) -> TextRange { | 23 | fn highlight_range(&self) -> TextRange { |
25 | self.syntax_node_ptr().range() | 24 | self.source().ast.range() |
26 | } | 25 | } |
27 | fn as_any(&self) -> &(dyn Any + Send + 'static); | 26 | fn as_any(&self) -> &(dyn Any + Send + 'static); |
28 | } | 27 | } |
@@ -34,8 +33,8 @@ pub trait AstDiagnostic { | |||
34 | 33 | ||
35 | impl dyn Diagnostic { | 34 | impl dyn Diagnostic { |
36 | pub fn syntax_node(&self, db: &impl HirDatabase) -> SyntaxNode { | 35 | pub fn syntax_node(&self, db: &impl HirDatabase) -> SyntaxNode { |
37 | let node = db.parse_or_expand(self.file()).unwrap(); | 36 | let node = db.parse_or_expand(self.source().file_id).unwrap(); |
38 | self.syntax_node_ptr().to_node(&node) | 37 | self.source().ast.to_node(&node) |
39 | } | 38 | } |
40 | 39 | ||
41 | pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> { | 40 | pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> { |
@@ -87,12 +86,11 @@ impl Diagnostic for NoSuchField { | |||
87 | fn message(&self) -> String { | 86 | fn message(&self) -> String { |
88 | "no such field".to_string() | 87 | "no such field".to_string() |
89 | } | 88 | } |
90 | fn file(&self) -> HirFileId { | 89 | |
91 | self.file | 90 | fn source(&self) -> Source<SyntaxNodePtr> { |
92 | } | 91 | Source { file_id: self.file, ast: self.field.into() } |
93 | fn syntax_node_ptr(&self) -> SyntaxNodePtr { | ||
94 | self.field.into() | ||
95 | } | 92 | } |
93 | |||
96 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 94 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
97 | self | 95 | self |
98 | } | 96 | } |
@@ -109,11 +107,8 @@ impl Diagnostic for UnresolvedModule { | |||
109 | fn message(&self) -> String { | 107 | fn message(&self) -> String { |
110 | "unresolved module".to_string() | 108 | "unresolved module".to_string() |
111 | } | 109 | } |
112 | fn file(&self) -> HirFileId { | 110 | fn source(&self) -> Source<SyntaxNodePtr> { |
113 | self.file | 111 | Source { file_id: self.file, ast: self.decl.into() } |
114 | } | ||
115 | fn syntax_node_ptr(&self) -> SyntaxNodePtr { | ||
116 | self.decl.into() | ||
117 | } | 112 | } |
118 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 113 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
119 | self | 114 | self |
@@ -131,11 +126,8 @@ impl Diagnostic for MissingFields { | |||
131 | fn message(&self) -> String { | 126 | fn message(&self) -> String { |
132 | "fill structure fields".to_string() | 127 | "fill structure fields".to_string() |
133 | } | 128 | } |
134 | fn file(&self) -> HirFileId { | 129 | fn source(&self) -> Source<SyntaxNodePtr> { |
135 | self.file | 130 | Source { file_id: self.file, ast: self.field_list.into() } |
136 | } | ||
137 | fn syntax_node_ptr(&self) -> SyntaxNodePtr { | ||
138 | self.field_list.into() | ||
139 | } | 131 | } |
140 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 132 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
141 | self | 133 | self |
@@ -146,8 +138,8 @@ impl AstDiagnostic for MissingFields { | |||
146 | type AST = ast::NamedFieldList; | 138 | type AST = ast::NamedFieldList; |
147 | 139 | ||
148 | fn ast(&self, db: &impl HirDatabase) -> Self::AST { | 140 | fn ast(&self, db: &impl HirDatabase) -> Self::AST { |
149 | let root = db.parse_or_expand(self.file()).unwrap(); | 141 | let root = db.parse_or_expand(self.source().file_id).unwrap(); |
150 | let node = self.syntax_node_ptr().to_node(&root); | 142 | let node = self.source().ast.to_node(&root); |
151 | ast::NamedFieldList::cast(node).unwrap() | 143 | ast::NamedFieldList::cast(node).unwrap() |
152 | } | 144 | } |
153 | } | 145 | } |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 4dcea19a9..f33676655 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -11,17 +11,16 @@ use ra_syntax::{ | |||
11 | }, | 11 | }, |
12 | AstNode, AstPtr, SyntaxNodePtr, | 12 | AstNode, AstPtr, SyntaxNodePtr, |
13 | }; | 13 | }; |
14 | use test_utils::tested_by; | ||
14 | 15 | ||
15 | use crate::{ | 16 | use crate::{ |
16 | name::{AsName, SELF_PARAM}, | 17 | name::{AsName, SELF_PARAM}, |
18 | path::GenericArgs, | ||
19 | ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, | ||
17 | type_ref::{Mutability, TypeRef}, | 20 | type_ref::{Mutability, TypeRef}, |
18 | DefWithBody, Either, HasSource, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, Name, | 21 | DefWithBody, Either, HasSource, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, Name, |
19 | Path, Resolver, | 22 | Path, Resolver, |
20 | }; | 23 | }; |
21 | use crate::{ | ||
22 | path::GenericArgs, | ||
23 | ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, | ||
24 | }; | ||
25 | 24 | ||
26 | pub use self::scope::ExprScopes; | 25 | pub use self::scope::ExprScopes; |
27 | 26 | ||
@@ -558,37 +557,40 @@ where | |||
558 | let syntax_ptr = SyntaxNodePtr::new(expr.syntax()); | 557 | let syntax_ptr = SyntaxNodePtr::new(expr.syntax()); |
559 | match expr.kind() { | 558 | match expr.kind() { |
560 | ast::ExprKind::IfExpr(e) => { | 559 | ast::ExprKind::IfExpr(e) => { |
561 | if let Some(pat) = e.condition().and_then(|c| c.pat()) { | 560 | let then_branch = self.collect_block_opt(e.then_branch()); |
562 | // if let -- desugar to match | 561 | |
563 | let pat = self.collect_pat(pat); | 562 | let else_branch = e.else_branch().map(|b| match b { |
564 | let match_expr = | 563 | ast::ElseBranch::Block(it) => self.collect_block(it), |
565 | self.collect_expr_opt(e.condition().expect("checked above").expr()); | 564 | ast::ElseBranch::IfExpr(elif) => { |
566 | let then_branch = self.collect_block_opt(e.then_branch()); | 565 | let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap(); |
567 | let else_branch = e | 566 | self.collect_expr(expr) |
568 | .else_branch() | 567 | } |
569 | .map(|b| match b { | 568 | }); |
570 | ast::ElseBranch::Block(it) => self.collect_block(it), | 569 | |
571 | ast::ElseBranch::IfExpr(elif) => self.collect_expr(elif.into()), | 570 | let condition = match e.condition() { |
572 | }) | 571 | None => self.exprs.alloc(Expr::Missing), |
573 | .unwrap_or_else(|| self.empty_block()); | 572 | Some(condition) => match condition.pat() { |
574 | let placeholder_pat = self.pats.alloc(Pat::Missing); | 573 | None => self.collect_expr_opt(condition.expr()), |
575 | let arms = vec![ | 574 | // if let -- desugar to match |
576 | MatchArm { pats: vec![pat], expr: then_branch, guard: None }, | 575 | Some(pat) => { |
577 | MatchArm { pats: vec![placeholder_pat], expr: else_branch, guard: None }, | 576 | let pat = self.collect_pat(pat); |
578 | ]; | 577 | let match_expr = self.collect_expr_opt(condition.expr()); |
579 | self.alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr) | 578 | let placeholder_pat = self.pats.alloc(Pat::Missing); |
580 | } else { | 579 | let arms = vec![ |
581 | let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr())); | 580 | MatchArm { pats: vec![pat], expr: then_branch, guard: None }, |
582 | let then_branch = self.collect_block_opt(e.then_branch()); | 581 | MatchArm { |
583 | let else_branch = e.else_branch().map(|b| match b { | 582 | pats: vec![placeholder_pat], |
584 | ast::ElseBranch::Block(it) => self.collect_block(it), | 583 | expr: else_branch.unwrap_or_else(|| self.empty_block()), |
585 | ast::ElseBranch::IfExpr(elif) => { | 584 | guard: None, |
586 | let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap(); | 585 | }, |
587 | self.collect_expr(expr) | 586 | ]; |
587 | return self | ||
588 | .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr); | ||
588 | } | 589 | } |
589 | }); | 590 | }, |
590 | self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr) | 591 | }; |
591 | } | 592 | |
593 | self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr) | ||
592 | } | 594 | } |
593 | ast::ExprKind::TryBlockExpr(e) => { | 595 | ast::ExprKind::TryBlockExpr(e) => { |
594 | let body = self.collect_block_opt(e.try_body()); | 596 | let body = self.collect_block_opt(e.try_body()); |
@@ -600,17 +602,30 @@ where | |||
600 | self.alloc_expr(Expr::Loop { body }, syntax_ptr) | 602 | self.alloc_expr(Expr::Loop { body }, syntax_ptr) |
601 | } | 603 | } |
602 | ast::ExprKind::WhileExpr(e) => { | 604 | ast::ExprKind::WhileExpr(e) => { |
603 | let condition = if let Some(condition) = e.condition() { | ||
604 | if condition.pat().is_none() { | ||
605 | self.collect_expr_opt(condition.expr()) | ||
606 | } else { | ||
607 | // FIXME handle while let | ||
608 | return self.alloc_expr(Expr::Missing, syntax_ptr); | ||
609 | } | ||
610 | } else { | ||
611 | self.exprs.alloc(Expr::Missing) | ||
612 | }; | ||
613 | let body = self.collect_block_opt(e.loop_body()); | 605 | let body = self.collect_block_opt(e.loop_body()); |
606 | |||
607 | let condition = match e.condition() { | ||
608 | None => self.exprs.alloc(Expr::Missing), | ||
609 | Some(condition) => match condition.pat() { | ||
610 | None => self.collect_expr_opt(condition.expr()), | ||
611 | // if let -- desugar to match | ||
612 | Some(pat) => { | ||
613 | tested_by!(infer_while_let); | ||
614 | let pat = self.collect_pat(pat); | ||
615 | let match_expr = self.collect_expr_opt(condition.expr()); | ||
616 | let placeholder_pat = self.pats.alloc(Pat::Missing); | ||
617 | let break_ = self.exprs.alloc(Expr::Break { expr: None }); | ||
618 | let arms = vec![ | ||
619 | MatchArm { pats: vec![pat], expr: body, guard: None }, | ||
620 | MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None }, | ||
621 | ]; | ||
622 | let match_expr = | ||
623 | self.exprs.alloc(Expr::Match { expr: match_expr, arms }); | ||
624 | return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr); | ||
625 | } | ||
626 | }, | ||
627 | }; | ||
628 | |||
614 | self.alloc_expr(Expr::While { condition, body }, syntax_ptr) | 629 | self.alloc_expr(Expr::While { condition, body }, syntax_ptr) |
615 | } | 630 | } |
616 | ast::ExprKind::ForExpr(e) => { | 631 | ast::ExprKind::ForExpr(e) => { |
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index 2d831f0d8..5b15eee90 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs | |||
@@ -10,4 +10,5 @@ test_utils::marks!( | |||
10 | std_prelude | 10 | std_prelude |
11 | match_ergonomics_ref | 11 | match_ergonomics_ref |
12 | trait_resolution_on_fn_type | 12 | trait_resolution_on_fn_type |
13 | infer_while_let | ||
13 | ); | 14 | ); |
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 06b732215..7da2dcdff 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -483,7 +483,7 @@ struct ModCollector<'a, D> { | |||
483 | module_id: CrateModuleId, | 483 | module_id: CrateModuleId, |
484 | file_id: HirFileId, | 484 | file_id: HirFileId, |
485 | raw_items: &'a raw::RawItems, | 485 | raw_items: &'a raw::RawItems, |
486 | parent_module: Option<&'a Name>, | 486 | parent_module: Option<ParentModule<'a>>, |
487 | } | 487 | } |
488 | 488 | ||
489 | impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> | 489 | impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> |
@@ -508,15 +508,16 @@ where | |||
508 | fn collect_module(&mut self, module: &raw::ModuleData) { | 508 | fn collect_module(&mut self, module: &raw::ModuleData) { |
509 | match module { | 509 | match module { |
510 | // inline module, just recurse | 510 | // inline module, just recurse |
511 | raw::ModuleData::Definition { name, items, ast_id } => { | 511 | raw::ModuleData::Definition { name, items, ast_id, attr_path } => { |
512 | let module_id = | 512 | let module_id = |
513 | self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None); | 513 | self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None); |
514 | let parent_module = ParentModule { name, attr_path: attr_path.as_ref() }; | ||
514 | ModCollector { | 515 | ModCollector { |
515 | def_collector: &mut *self.def_collector, | 516 | def_collector: &mut *self.def_collector, |
516 | module_id, | 517 | module_id, |
517 | file_id: self.file_id, | 518 | file_id: self.file_id, |
518 | raw_items: self.raw_items, | 519 | raw_items: self.raw_items, |
519 | parent_module: Some(name), | 520 | parent_module: Some(parent_module), |
520 | } | 521 | } |
521 | .collect(&*items); | 522 | .collect(&*items); |
522 | } | 523 | } |
@@ -530,7 +531,7 @@ where | |||
530 | name, | 531 | name, |
531 | is_root, | 532 | is_root, |
532 | attr_path.as_ref(), | 533 | attr_path.as_ref(), |
533 | self.parent_module, | 534 | self.parent_module.as_ref(), |
534 | ) { | 535 | ) { |
535 | Ok(file_id) => { | 536 | Ok(file_id) => { |
536 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); | 537 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); |
@@ -647,7 +648,7 @@ fn resolve_submodule( | |||
647 | name: &Name, | 648 | name: &Name, |
648 | is_root: bool, | 649 | is_root: bool, |
649 | attr_path: Option<&SmolStr>, | 650 | attr_path: Option<&SmolStr>, |
650 | parent_module: Option<&Name>, | 651 | parent_module: Option<&ParentModule>, |
651 | ) -> Result<FileId, RelativePathBuf> { | 652 | ) -> Result<FileId, RelativePathBuf> { |
652 | let file_id = file_id.original_file(db); | 653 | let file_id = file_id.original_file(db); |
653 | let source_root_id = db.file_source_root(file_id); | 654 | let source_root_id = db.file_source_root(file_id); |
@@ -657,20 +658,49 @@ fn resolve_submodule( | |||
657 | let mod_name = path.file_stem().unwrap_or("unknown"); | 658 | let mod_name = path.file_stem().unwrap_or("unknown"); |
658 | 659 | ||
659 | let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) { | 660 | let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) { |
660 | (Some(file_path), Some(parent_name)) => { | 661 | (Some(file_path), Some(parent_module)) => { |
661 | let file_path = normalize_attribute_path(file_path); | 662 | let file_path = normalize_attribute_path(file_path); |
662 | let path = dir_path.join(format!("{}/{}", parent_name, file_path)).normalize(); | 663 | match parent_module.attribute_path() { |
663 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath(path)) | 664 | Some(parent_module_attr_path) => { |
665 | let path = dir_path | ||
666 | .join(format!( | ||
667 | "{}/{}", | ||
668 | normalize_attribute_path(parent_module_attr_path), | ||
669 | file_path | ||
670 | )) | ||
671 | .normalize(); | ||
672 | ResolutionMode::InlineModuleWithAttributePath( | ||
673 | InsideInlineModuleMode::WithAttributePath(path), | ||
674 | ) | ||
675 | } | ||
676 | None => { | ||
677 | let path = | ||
678 | dir_path.join(format!("{}/{}", parent_module.name, file_path)).normalize(); | ||
679 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath( | ||
680 | path, | ||
681 | )) | ||
682 | } | ||
683 | } | ||
664 | } | 684 | } |
685 | (None, Some(parent_module)) => match parent_module.attribute_path() { | ||
686 | Some(parent_module_attr_path) => { | ||
687 | let path = dir_path.join(format!( | ||
688 | "{}/{}.rs", | ||
689 | normalize_attribute_path(parent_module_attr_path), | ||
690 | name | ||
691 | )); | ||
692 | ResolutionMode::InlineModuleWithAttributePath(InsideInlineModuleMode::File(path)) | ||
693 | } | ||
694 | None => { | ||
695 | let path = dir_path.join(format!("{}/{}.rs", parent_module.name, name)); | ||
696 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path)) | ||
697 | } | ||
698 | }, | ||
665 | (Some(file_path), None) => { | 699 | (Some(file_path), None) => { |
666 | let file_path = normalize_attribute_path(file_path); | 700 | let file_path = normalize_attribute_path(file_path); |
667 | let path = dir_path.join(file_path.as_ref()).normalize(); | 701 | let path = dir_path.join(file_path.as_ref()).normalize(); |
668 | ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path)) | 702 | ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path)) |
669 | } | 703 | } |
670 | (None, Some(parent_name)) => { | ||
671 | let path = dir_path.join(format!("{}/{}.rs", parent_name, name)); | ||
672 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path)) | ||
673 | } | ||
674 | _ => { | 704 | _ => { |
675 | let is_dir_owner = is_root || mod_name == "mod"; | 705 | let is_dir_owner = is_root || mod_name == "mod"; |
676 | if is_dir_owner { | 706 | if is_dir_owner { |
@@ -743,6 +773,7 @@ impl InsideInlineModuleMode { | |||
743 | enum ResolutionMode { | 773 | enum ResolutionMode { |
744 | OutOfLine(OutOfLineMode), | 774 | OutOfLine(OutOfLineMode), |
745 | InsideInlineModule(InsideInlineModuleMode), | 775 | InsideInlineModule(InsideInlineModuleMode), |
776 | InlineModuleWithAttributePath(InsideInlineModuleMode), | ||
746 | } | 777 | } |
747 | 778 | ||
748 | impl ResolutionMode { | 779 | impl ResolutionMode { |
@@ -752,6 +783,7 @@ impl ResolutionMode { | |||
752 | match self { | 783 | match self { |
753 | OutOfLine(mode) => mode.resolve(source_root), | 784 | OutOfLine(mode) => mode.resolve(source_root), |
754 | InsideInlineModule(mode) => mode.resolve(source_root), | 785 | InsideInlineModule(mode) => mode.resolve(source_root), |
786 | InlineModuleWithAttributePath(mode) => mode.resolve(source_root), | ||
755 | } | 787 | } |
756 | } | 788 | } |
757 | } | 789 | } |
@@ -773,6 +805,17 @@ fn resolve_find_result( | |||
773 | } | 805 | } |
774 | } | 806 | } |
775 | 807 | ||
808 | struct ParentModule<'a> { | ||
809 | name: &'a Name, | ||
810 | attr_path: Option<&'a SmolStr>, | ||
811 | } | ||
812 | |||
813 | impl<'a> ParentModule<'a> { | ||
814 | pub fn attribute_path(&self) -> Option<&SmolStr> { | ||
815 | self.attr_path.filter(|p| !p.is_empty()) | ||
816 | } | ||
817 | } | ||
818 | |||
776 | #[cfg(test)] | 819 | #[cfg(test)] |
777 | mod tests { | 820 | mod tests { |
778 | use ra_db::SourceDatabase; | 821 | use ra_db::SourceDatabase; |
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index 8517f3c43..584e15e29 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs | |||
@@ -130,8 +130,17 @@ impl_arena_id!(Module); | |||
130 | 130 | ||
131 | #[derive(Debug, PartialEq, Eq)] | 131 | #[derive(Debug, PartialEq, Eq)] |
132 | pub(super) enum ModuleData { | 132 | pub(super) enum ModuleData { |
133 | Declaration { name: Name, ast_id: FileAstId<ast::Module>, attr_path: Option<SmolStr> }, | 133 | Declaration { |
134 | Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, | 134 | name: Name, |
135 | ast_id: FileAstId<ast::Module>, | ||
136 | attr_path: Option<SmolStr>, | ||
137 | }, | ||
138 | Definition { | ||
139 | name: Name, | ||
140 | ast_id: FileAstId<ast::Module>, | ||
141 | items: Vec<RawItem>, | ||
142 | attr_path: Option<SmolStr>, | ||
143 | }, | ||
135 | } | 144 | } |
136 | 145 | ||
137 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 146 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -256,9 +265,9 @@ impl RawItemsCollector { | |||
256 | None => return, | 265 | None => return, |
257 | }; | 266 | }; |
258 | 267 | ||
259 | let attr_path = extract_mod_path_attribute(&module); | ||
260 | let ast_id = self.source_ast_id_map.ast_id(&module); | 268 | let ast_id = self.source_ast_id_map.ast_id(&module); |
261 | if module.has_semi() { | 269 | if module.has_semi() { |
270 | let attr_path = extract_mod_path_attribute(&module); | ||
262 | let item = | 271 | let item = |
263 | self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id, attr_path }); | 272 | self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id, attr_path }); |
264 | self.push_item(current_module, RawItem::Module(item)); | 273 | self.push_item(current_module, RawItem::Module(item)); |
@@ -266,10 +275,12 @@ impl RawItemsCollector { | |||
266 | } | 275 | } |
267 | 276 | ||
268 | if let Some(item_list) = module.item_list() { | 277 | if let Some(item_list) = module.item_list() { |
278 | let attr_path = extract_mod_path_attribute(&module); | ||
269 | let item = self.raw_items.modules.alloc(ModuleData::Definition { | 279 | let item = self.raw_items.modules.alloc(ModuleData::Definition { |
270 | name, | 280 | name, |
271 | ast_id, | 281 | ast_id, |
272 | items: Vec::new(), | 282 | items: Vec::new(), |
283 | attr_path, | ||
273 | }); | 284 | }); |
274 | self.process_module(Some(item), item_list); | 285 | self.process_module(Some(item), item_list); |
275 | self.push_item(current_module, RawItem::Module(item)); | 286 | self.push_item(current_module, RawItem::Module(item)); |
diff --git a/crates/ra_hir/src/nameres/tests/mods.rs b/crates/ra_hir/src/nameres/tests/mods.rs index 382728149..6dd18df1a 100644 --- a/crates/ra_hir/src/nameres/tests/mods.rs +++ b/crates/ra_hir/src/nameres/tests/mods.rs | |||
@@ -336,9 +336,7 @@ fn module_resolution_explicit_path_mod_rs_with_win_separator() { | |||
336 | "###); | 336 | "###); |
337 | } | 337 | } |
338 | 338 | ||
339 | // FIXME: issue #1529. not support out-of-line modules inside inline. | ||
340 | #[test] | 339 | #[test] |
341 | #[ignore] | ||
342 | fn module_resolution_decl_inside_inline_module_with_path_attribute() { | 340 | fn module_resolution_decl_inside_inline_module_with_path_attribute() { |
343 | let map = def_map_with_crate_graph( | 341 | let map = def_map_with_crate_graph( |
344 | r###" | 342 | r###" |
@@ -397,9 +395,7 @@ fn module_resolution_decl_inside_inline_module() { | |||
397 | "###); | 395 | "###); |
398 | } | 396 | } |
399 | 397 | ||
400 | // FIXME: issue #1529. not support out-of-line modules inside inline. | ||
401 | #[test] | 398 | #[test] |
402 | #[ignore] | ||
403 | fn module_resolution_decl_inside_inline_module_2_with_path_attribute() { | 399 | fn module_resolution_decl_inside_inline_module_2_with_path_attribute() { |
404 | let map = def_map_with_crate_graph( | 400 | let map = def_map_with_crate_graph( |
405 | r###" | 401 | r###" |
@@ -429,9 +425,7 @@ fn module_resolution_decl_inside_inline_module_2_with_path_attribute() { | |||
429 | "###); | 425 | "###); |
430 | } | 426 | } |
431 | 427 | ||
432 | // FIXME: issue #1529. not support out-of-line modules inside inline. | ||
433 | #[test] | 428 | #[test] |
434 | #[ignore] | ||
435 | fn module_resolution_decl_inside_inline_module_3() { | 429 | fn module_resolution_decl_inside_inline_module_3() { |
436 | let map = def_map_with_crate_graph( | 430 | let map = def_map_with_crate_graph( |
437 | r###" | 431 | r###" |
@@ -462,9 +456,7 @@ fn module_resolution_decl_inside_inline_module_3() { | |||
462 | "###); | 456 | "###); |
463 | } | 457 | } |
464 | 458 | ||
465 | // FIXME: issue #1529. not support out-of-line modules inside inline. | ||
466 | #[test] | 459 | #[test] |
467 | #[ignore] | ||
468 | fn module_resolution_decl_inside_inline_module_empty_path() { | 460 | fn module_resolution_decl_inside_inline_module_empty_path() { |
469 | let map = def_map_with_crate_graph( | 461 | let map = def_map_with_crate_graph( |
470 | r###" | 462 | r###" |
@@ -475,7 +467,7 @@ fn module_resolution_decl_inside_inline_module_empty_path() { | |||
475 | mod bar; | 467 | mod bar; |
476 | } | 468 | } |
477 | 469 | ||
478 | //- /users.rs | 470 | //- /foo/users.rs |
479 | pub struct Baz; | 471 | pub struct Baz; |
480 | "###, | 472 | "###, |
481 | crate_graph! { | 473 | crate_graph! { |
@@ -520,9 +512,7 @@ fn module_resolution_decl_empty_path() { | |||
520 | "###); | 512 | "###); |
521 | } | 513 | } |
522 | 514 | ||
523 | // FIXME: issue #1529. not support out-of-line modules inside inline. | ||
524 | #[test] | 515 | #[test] |
525 | #[ignore] | ||
526 | fn module_resolution_decl_inside_inline_module_relative_path() { | 516 | fn module_resolution_decl_inside_inline_module_relative_path() { |
527 | let map = def_map_with_crate_graph( | 517 | let map = def_map_with_crate_graph( |
528 | r###" | 518 | r###" |
@@ -660,9 +650,7 @@ fn module_resolution_decl_inside_inline_module_in_non_crate_root() { | |||
660 | "###); | 650 | "###); |
661 | } | 651 | } |
662 | 652 | ||
663 | // FIXME: issue #1529. not support out-of-line modules inside inline. | ||
664 | #[test] | 653 | #[test] |
665 | #[ignore] | ||
666 | fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { | 654 | fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { |
667 | let map = def_map_with_crate_graph( | 655 | let map = def_map_with_crate_graph( |
668 | r###" | 656 | r###" |
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 882db7681..5ee71e421 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -25,6 +25,12 @@ pub struct PathSegment { | |||
25 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 25 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
26 | pub struct GenericArgs { | 26 | pub struct GenericArgs { |
27 | pub args: Vec<GenericArg>, | 27 | pub args: Vec<GenericArg>, |
28 | /// This specifies whether the args contain a Self type as the first | ||
29 | /// element. This is the case for path segments like `<T as Trait>`, where | ||
30 | /// `T` is actually a type parameter for the path `Trait` specifying the | ||
31 | /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type | ||
32 | /// is left out. | ||
33 | pub has_self_type: bool, | ||
28 | // someday also bindings | 34 | // someday also bindings |
29 | } | 35 | } |
30 | 36 | ||
@@ -74,6 +80,28 @@ impl Path { | |||
74 | let segment = PathSegment { name: name.as_name(), args_and_bindings: args }; | 80 | let segment = PathSegment { name: name.as_name(), args_and_bindings: args }; |
75 | segments.push(segment); | 81 | segments.push(segment); |
76 | } | 82 | } |
83 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { | ||
84 | assert!(path.qualifier().is_none()); // this can only occur at the first segment | ||
85 | |||
86 | // FIXME: handle <T> syntax (type segments without trait) | ||
87 | |||
88 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo | ||
89 | let path = Path::from_ast(trait_ref?.path()?)?; | ||
90 | kind = path.kind; | ||
91 | let mut prefix_segments = path.segments; | ||
92 | prefix_segments.reverse(); | ||
93 | segments.extend(prefix_segments); | ||
94 | // Insert the type reference (T in the above example) as Self parameter for the trait | ||
95 | let self_type = TypeRef::from_ast(type_ref?); | ||
96 | let mut last_segment = segments.last_mut()?; | ||
97 | if last_segment.args_and_bindings.is_none() { | ||
98 | last_segment.args_and_bindings = Some(Arc::new(GenericArgs::empty())); | ||
99 | }; | ||
100 | let args = last_segment.args_and_bindings.as_mut().unwrap(); | ||
101 | let mut args_inner = Arc::make_mut(args); | ||
102 | args_inner.has_self_type = true; | ||
103 | args_inner.args.insert(0, GenericArg::Type(self_type)); | ||
104 | } | ||
77 | ast::PathSegmentKind::CrateKw => { | 105 | ast::PathSegmentKind::CrateKw => { |
78 | kind = PathKind::Crate; | 106 | kind = PathKind::Crate; |
79 | break; | 107 | break; |
@@ -144,11 +172,15 @@ impl GenericArgs { | |||
144 | } | 172 | } |
145 | // lifetimes and assoc type args ignored for now | 173 | // lifetimes and assoc type args ignored for now |
146 | if !args.is_empty() { | 174 | if !args.is_empty() { |
147 | Some(GenericArgs { args }) | 175 | Some(GenericArgs { args, has_self_type: false }) |
148 | } else { | 176 | } else { |
149 | None | 177 | None |
150 | } | 178 | } |
151 | } | 179 | } |
180 | |||
181 | pub(crate) fn empty() -> GenericArgs { | ||
182 | GenericArgs { args: Vec::new(), has_self_type: false } | ||
183 | } | ||
152 | } | 184 | } |
153 | 185 | ||
154 | impl From<Name> for Path { | 186 | impl From<Name> for Path { |
@@ -236,6 +268,10 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> { | |||
236 | } | 268 | } |
237 | Path { kind: PathKind::Super, segments: Vec::new() } | 269 | Path { kind: PathKind::Super, segments: Vec::new() } |
238 | } | 270 | } |
271 | ast::PathSegmentKind::Type { .. } => { | ||
272 | // not allowed in imports | ||
273 | return None; | ||
274 | } | ||
239 | }; | 275 | }; |
240 | Some(res) | 276 | Some(res) |
241 | } | 277 | } |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index c2c6921cb..e86716d74 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -18,14 +18,18 @@ use ra_syntax::{ | |||
18 | use rustc_hash::{FxHashMap, FxHashSet}; | 18 | use rustc_hash::{FxHashMap, FxHashSet}; |
19 | 19 | ||
20 | use crate::{ | 20 | use crate::{ |
21 | expr, | ||
22 | expr::{ | 21 | expr::{ |
22 | self, | ||
23 | scope::{ExprScopes, ScopeId}, | 23 | scope::{ExprScopes, ScopeId}, |
24 | BodySourceMap, | 24 | BodySourceMap, |
25 | }, | 25 | }, |
26 | ids::LocationCtx, | 26 | ids::LocationCtx, |
27 | name, | ||
28 | path::{PathKind, PathSegment}, | ||
29 | ty::method_resolution::implements_trait, | ||
27 | AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HirDatabase, HirFileId, | 30 | AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HirDatabase, HirFileId, |
28 | MacroDef, Module, Name, Path, PerNs, Resolver, Static, Struct, Trait, Ty, | 31 | MacroDef, Module, ModuleDef, Name, Path, PerNs, Resolution, Resolver, Static, Struct, Trait, |
32 | Ty, | ||
29 | }; | 33 | }; |
30 | 34 | ||
31 | /// Locates the module by `FileId`. Picks topmost module in the file. | 35 | /// Locates the module by `FileId`. Picks topmost module in the file. |
@@ -409,6 +413,33 @@ impl SourceAnalyzer { | |||
409 | crate::ty::autoderef(db, &self.resolver, canonical).map(|canonical| canonical.value) | 413 | crate::ty::autoderef(db, &self.resolver, canonical).map(|canonical| canonical.value) |
410 | } | 414 | } |
411 | 415 | ||
416 | /// Checks that particular type `ty` implements `std::future::Future`. | ||
417 | /// This function is used in `.await` syntax completion. | ||
418 | pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool { | ||
419 | let std_future_path = Path { | ||
420 | kind: PathKind::Abs, | ||
421 | segments: vec![ | ||
422 | PathSegment { name: name::STD, args_and_bindings: None }, | ||
423 | PathSegment { name: name::FUTURE_MOD, args_and_bindings: None }, | ||
424 | PathSegment { name: name::FUTURE_TYPE, args_and_bindings: None }, | ||
425 | ], | ||
426 | }; | ||
427 | |||
428 | let std_future_trait = | ||
429 | match self.resolver.resolve_path_segments(db, &std_future_path).into_fully_resolved() { | ||
430 | PerNs { types: Some(Resolution::Def(ModuleDef::Trait(trait_))), .. } => trait_, | ||
431 | _ => return false, | ||
432 | }; | ||
433 | |||
434 | let krate = match self.resolver.krate() { | ||
435 | Some(krate) => krate, | ||
436 | _ => return false, | ||
437 | }; | ||
438 | |||
439 | let canonical_ty = crate::ty::Canonical { value: ty, num_vars: 0 }; | ||
440 | implements_trait(&canonical_ty, db, &self.resolver, krate, std_future_trait) | ||
441 | } | ||
442 | |||
412 | #[cfg(test)] | 443 | #[cfg(test)] |
413 | pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> { | 444 | pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> { |
414 | self.body_source_map.clone().unwrap() | 445 | self.body_source_map.clone().unwrap() |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 82589e504..642dd02cb 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -94,6 +94,12 @@ pub enum TypeCtor { | |||
94 | 94 | ||
95 | /// A tuple type. For example, `(i32, bool)`. | 95 | /// A tuple type. For example, `(i32, bool)`. |
96 | Tuple { cardinality: u16 }, | 96 | Tuple { cardinality: u16 }, |
97 | |||
98 | /// Represents an associated item like `Iterator::Item`. This is used | ||
99 | /// when we have tried to normalize a projection like `T::Item` but | ||
100 | /// couldn't find a better representation. In that case, we generate | ||
101 | /// an **application type** like `(Iterator::Item)<T>`. | ||
102 | AssociatedType(TypeAlias), | ||
97 | } | 103 | } |
98 | 104 | ||
99 | /// A nominal type with (maybe 0) type parameters. This might be a primitive | 105 | /// A nominal type with (maybe 0) type parameters. This might be a primitive |
@@ -114,6 +120,12 @@ pub struct ProjectionTy { | |||
114 | pub parameters: Substs, | 120 | pub parameters: Substs, |
115 | } | 121 | } |
116 | 122 | ||
123 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
124 | pub struct UnselectedProjectionTy { | ||
125 | pub type_name: Name, | ||
126 | pub parameters: Substs, | ||
127 | } | ||
128 | |||
117 | /// A type. | 129 | /// A type. |
118 | /// | 130 | /// |
119 | /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents | 131 | /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents |
@@ -127,6 +139,18 @@ pub enum Ty { | |||
127 | /// several other things. | 139 | /// several other things. |
128 | Apply(ApplicationTy), | 140 | Apply(ApplicationTy), |
129 | 141 | ||
142 | /// A "projection" type corresponds to an (unnormalized) | ||
143 | /// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the | ||
144 | /// trait and all its parameters are fully known. | ||
145 | Projection(ProjectionTy), | ||
146 | |||
147 | /// This is a variant of a projection in which the trait is | ||
148 | /// **not** known. It corresponds to a case where people write | ||
149 | /// `T::Item` without specifying the trait. We would then try to | ||
150 | /// figure out the trait by looking at all the traits that are in | ||
151 | /// scope. | ||
152 | UnselectedProjection(UnselectedProjectionTy), | ||
153 | |||
130 | /// A type parameter; for example, `T` in `fn f<T>(x: T) {} | 154 | /// A type parameter; for example, `T` in `fn f<T>(x: T) {} |
131 | Param { | 155 | Param { |
132 | /// The index of the parameter (starting with parameters from the | 156 | /// The index of the parameter (starting with parameters from the |
@@ -352,6 +376,16 @@ impl Ty { | |||
352 | t.walk(f); | 376 | t.walk(f); |
353 | } | 377 | } |
354 | } | 378 | } |
379 | Ty::Projection(p_ty) => { | ||
380 | for t in p_ty.parameters.iter() { | ||
381 | t.walk(f); | ||
382 | } | ||
383 | } | ||
384 | Ty::UnselectedProjection(p_ty) => { | ||
385 | for t in p_ty.parameters.iter() { | ||
386 | t.walk(f); | ||
387 | } | ||
388 | } | ||
355 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | 389 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} |
356 | } | 390 | } |
357 | f(self); | 391 | f(self); |
@@ -362,6 +396,12 @@ impl Ty { | |||
362 | Ty::Apply(a_ty) => { | 396 | Ty::Apply(a_ty) => { |
363 | a_ty.parameters.walk_mut(f); | 397 | a_ty.parameters.walk_mut(f); |
364 | } | 398 | } |
399 | Ty::Projection(p_ty) => { | ||
400 | p_ty.parameters.walk_mut(f); | ||
401 | } | ||
402 | Ty::UnselectedProjection(p_ty) => { | ||
403 | p_ty.parameters.walk_mut(f); | ||
404 | } | ||
365 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | 405 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} |
366 | } | 406 | } |
367 | f(self); | 407 | f(self); |
@@ -572,15 +612,61 @@ impl HirDisplay for ApplicationTy { | |||
572 | write!(f, ">")?; | 612 | write!(f, ">")?; |
573 | } | 613 | } |
574 | } | 614 | } |
615 | TypeCtor::AssociatedType(type_alias) => { | ||
616 | let trait_name = type_alias | ||
617 | .parent_trait(f.db) | ||
618 | .and_then(|t| t.name(f.db)) | ||
619 | .unwrap_or_else(Name::missing); | ||
620 | let name = type_alias.name(f.db); | ||
621 | write!(f, "{}::{}", trait_name, name)?; | ||
622 | if self.parameters.len() > 0 { | ||
623 | write!(f, "<")?; | ||
624 | f.write_joined(&*self.parameters.0, ", ")?; | ||
625 | write!(f, ">")?; | ||
626 | } | ||
627 | } | ||
575 | } | 628 | } |
576 | Ok(()) | 629 | Ok(()) |
577 | } | 630 | } |
578 | } | 631 | } |
579 | 632 | ||
633 | impl HirDisplay for ProjectionTy { | ||
634 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
635 | let trait_name = self | ||
636 | .associated_ty | ||
637 | .parent_trait(f.db) | ||
638 | .and_then(|t| t.name(f.db)) | ||
639 | .unwrap_or_else(Name::missing); | ||
640 | write!(f, "<{} as {}", self.parameters[0].display(f.db), trait_name,)?; | ||
641 | if self.parameters.len() > 1 { | ||
642 | write!(f, "<")?; | ||
643 | f.write_joined(&self.parameters[1..], ", ")?; | ||
644 | write!(f, ">")?; | ||
645 | } | ||
646 | write!(f, ">::{}", self.associated_ty.name(f.db))?; | ||
647 | Ok(()) | ||
648 | } | ||
649 | } | ||
650 | |||
651 | impl HirDisplay for UnselectedProjectionTy { | ||
652 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
653 | write!(f, "{}", self.parameters[0].display(f.db))?; | ||
654 | if self.parameters.len() > 1 { | ||
655 | write!(f, "<")?; | ||
656 | f.write_joined(&self.parameters[1..], ", ")?; | ||
657 | write!(f, ">")?; | ||
658 | } | ||
659 | write!(f, "::{}", self.type_name)?; | ||
660 | Ok(()) | ||
661 | } | ||
662 | } | ||
663 | |||
580 | impl HirDisplay for Ty { | 664 | impl HirDisplay for Ty { |
581 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | 665 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { |
582 | match self { | 666 | match self { |
583 | Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, | 667 | Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, |
668 | Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, | ||
669 | Ty::UnselectedProjection(p_ty) => p_ty.hir_fmt(f)?, | ||
584 | Ty::Param { name, .. } => write!(f, "{}", name)?, | 670 | Ty::Param { name, .. } => write!(f, "{}", name)?, |
585 | Ty::Bound(idx) => write!(f, "?{}", idx)?, | 671 | Ty::Bound(idx) => write!(f, "?{}", idx)?, |
586 | Ty::Unknown => write!(f, "{{unknown}}")?, | 672 | Ty::Unknown => write!(f, "{{unknown}}")?, |
@@ -606,3 +692,17 @@ impl HirDisplay for TraitRef { | |||
606 | Ok(()) | 692 | Ok(()) |
607 | } | 693 | } |
608 | } | 694 | } |
695 | |||
696 | impl HirDisplay for Obligation { | ||
697 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
698 | match self { | ||
699 | Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db)), | ||
700 | Obligation::Projection(proj) => write!( | ||
701 | f, | ||
702 | "Normalize({} => {})", | ||
703 | proj.projection_ty.display(f.db), | ||
704 | proj.ty.display(f.db) | ||
705 | ), | ||
706 | } | ||
707 | } | ||
708 | } | ||
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 594c5bc79..675df4a22 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -245,7 +245,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
245 | &self.resolver, | 245 | &self.resolver, |
246 | type_ref, | 246 | type_ref, |
247 | ); | 247 | ); |
248 | self.insert_type_vars(ty) | 248 | let ty = self.insert_type_vars(ty); |
249 | self.normalize_associated_types_in(ty) | ||
249 | } | 250 | } |
250 | 251 | ||
251 | fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool { | 252 | fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool { |
@@ -411,6 +412,32 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
411 | ty | 412 | ty |
412 | } | 413 | } |
413 | 414 | ||
415 | /// Recurses through the given type, normalizing associated types mentioned | ||
416 | /// in it by replacing them by type variables and registering obligations to | ||
417 | /// resolve later. This should be done once for every type we get from some | ||
418 | /// type annotation (e.g. from a let type annotation, field type or function | ||
419 | /// call). `make_ty` handles this already, but e.g. for field types we need | ||
420 | /// to do it as well. | ||
421 | fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { | ||
422 | let ty = self.resolve_ty_as_possible(&mut vec![], ty); | ||
423 | ty.fold(&mut |ty| match ty { | ||
424 | Ty::Projection(proj_ty) => self.normalize_projection_ty(proj_ty), | ||
425 | Ty::UnselectedProjection(proj_ty) => { | ||
426 | // FIXME use Chalk's unselected projection support | ||
427 | Ty::UnselectedProjection(proj_ty) | ||
428 | } | ||
429 | _ => ty, | ||
430 | }) | ||
431 | } | ||
432 | |||
433 | fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { | ||
434 | let var = self.new_type_var(); | ||
435 | let predicate = ProjectionPredicate { projection_ty: proj_ty.clone(), ty: var.clone() }; | ||
436 | let obligation = Obligation::Projection(predicate); | ||
437 | self.obligations.push(obligation); | ||
438 | var | ||
439 | } | ||
440 | |||
414 | /// Resolves the type completely; type variables without known type are | 441 | /// Resolves the type completely; type variables without known type are |
415 | /// replaced by Ty::Unknown. | 442 | /// replaced by Ty::Unknown. |
416 | fn resolve_ty_completely(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { | 443 | fn resolve_ty_completely(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { |
@@ -549,6 +576,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
549 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); | 576 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); |
550 | let ty = ty.subst(&substs); | 577 | let ty = ty.subst(&substs); |
551 | let ty = self.insert_type_vars(ty); | 578 | let ty = self.insert_type_vars(ty); |
579 | let ty = self.normalize_associated_types_in(ty); | ||
552 | Some(ty) | 580 | Some(ty) |
553 | } | 581 | } |
554 | Resolution::LocalBinding(pat) => { | 582 | Resolution::LocalBinding(pat) => { |
@@ -670,6 +698,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
670 | .and_then(|d| d.field(self.db, &Name::tuple_field_name(i))) | 698 | .and_then(|d| d.field(self.db, &Name::tuple_field_name(i))) |
671 | .map_or(Ty::Unknown, |field| field.ty(self.db)) | 699 | .map_or(Ty::Unknown, |field| field.ty(self.db)) |
672 | .subst(&substs); | 700 | .subst(&substs); |
701 | let expected_ty = self.normalize_associated_types_in(expected_ty); | ||
673 | self.infer_pat(subpat, &expected_ty, default_bm); | 702 | self.infer_pat(subpat, &expected_ty, default_bm); |
674 | } | 703 | } |
675 | 704 | ||
@@ -697,6 +726,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
697 | let matching_field = def.and_then(|it| it.field(self.db, &subpat.name)); | 726 | let matching_field = def.and_then(|it| it.field(self.db, &subpat.name)); |
698 | let expected_ty = | 727 | let expected_ty = |
699 | matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs); | 728 | matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs); |
729 | let expected_ty = self.normalize_associated_types_in(expected_ty); | ||
700 | self.infer_pat(subpat.pat, &expected_ty, default_bm); | 730 | self.infer_pat(subpat.pat, &expected_ty, default_bm); |
701 | } | 731 | } |
702 | 732 | ||
@@ -927,9 +957,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
927 | self.unify(&expected_receiver_ty, &actual_receiver_ty); | 957 | self.unify(&expected_receiver_ty, &actual_receiver_ty); |
928 | 958 | ||
929 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); | 959 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); |
930 | for (arg, param) in args.iter().zip(param_iter) { | 960 | for (arg, param_ty) in args.iter().zip(param_iter) { |
931 | self.infer_expr(*arg, &Expectation::has_type(param)); | 961 | let param_ty = self.normalize_associated_types_in(param_ty); |
962 | self.infer_expr(*arg, &Expectation::has_type(param_ty)); | ||
932 | } | 963 | } |
964 | let ret_ty = self.normalize_associated_types_in(ret_ty); | ||
933 | ret_ty | 965 | ret_ty |
934 | } | 966 | } |
935 | 967 | ||
@@ -1020,9 +1052,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1020 | }; | 1052 | }; |
1021 | self.register_obligations_for_call(&callee_ty); | 1053 | self.register_obligations_for_call(&callee_ty); |
1022 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); | 1054 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); |
1023 | for (arg, param) in args.iter().zip(param_iter) { | 1055 | for (arg, param_ty) in args.iter().zip(param_iter) { |
1024 | self.infer_expr(*arg, &Expectation::has_type(param)); | 1056 | let param_ty = self.normalize_associated_types_in(param_ty); |
1057 | self.infer_expr(*arg, &Expectation::has_type(param_ty)); | ||
1025 | } | 1058 | } |
1059 | let ret_ty = self.normalize_associated_types_in(ret_ty); | ||
1026 | ret_ty | 1060 | ret_ty |
1027 | } | 1061 | } |
1028 | Expr::MethodCall { receiver, args, method_name, generic_args } => self | 1062 | Expr::MethodCall { receiver, args, method_name, generic_args } => self |
@@ -1120,7 +1154,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1120 | _ => None, | 1154 | _ => None, |
1121 | }) | 1155 | }) |
1122 | .unwrap_or(Ty::Unknown); | 1156 | .unwrap_or(Ty::Unknown); |
1123 | self.insert_type_vars(ty) | 1157 | let ty = self.insert_type_vars(ty); |
1158 | self.normalize_associated_types_in(ty) | ||
1124 | } | 1159 | } |
1125 | Expr::Await { expr } => { | 1160 | Expr::Await { expr } => { |
1126 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); | 1161 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 894ba0695..debedcbb8 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -8,7 +8,7 @@ | |||
8 | use std::iter; | 8 | use std::iter; |
9 | use std::sync::Arc; | 9 | use std::sync::Arc; |
10 | 10 | ||
11 | use super::{FnSig, GenericPredicate, Substs, TraitRef, Ty, TypeCtor}; | 11 | use super::{FnSig, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor}; |
12 | use crate::{ | 12 | use crate::{ |
13 | adt::VariantDef, | 13 | adt::VariantDef, |
14 | generics::HasGenericParams, | 14 | generics::HasGenericParams, |
@@ -64,7 +64,8 @@ impl Ty { | |||
64 | 64 | ||
65 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self { | 65 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self { |
66 | // Resolve the path (in type namespace) | 66 | // Resolve the path (in type namespace) |
67 | let resolution = resolver.resolve_path_without_assoc_items(db, path).take_types(); | 67 | let (resolution, remaining_index) = resolver.resolve_path_segments(db, path).into_inner(); |
68 | let resolution = resolution.take_types(); | ||
68 | 69 | ||
69 | let def = match resolution { | 70 | let def = match resolution { |
70 | Some(Resolution::Def(def)) => def, | 71 | Some(Resolution::Def(def)) => def, |
@@ -73,6 +74,10 @@ impl Ty { | |||
73 | panic!("path resolved to local binding in type ns"); | 74 | panic!("path resolved to local binding in type ns"); |
74 | } | 75 | } |
75 | Some(Resolution::GenericParam(idx)) => { | 76 | Some(Resolution::GenericParam(idx)) => { |
77 | if remaining_index.is_some() { | ||
78 | // e.g. T::Item | ||
79 | return Ty::Unknown; | ||
80 | } | ||
76 | return Ty::Param { | 81 | return Ty::Param { |
77 | idx, | 82 | idx, |
78 | // FIXME: maybe return name in resolution? | 83 | // FIXME: maybe return name in resolution? |
@@ -83,18 +88,54 @@ impl Ty { | |||
83 | }; | 88 | }; |
84 | } | 89 | } |
85 | Some(Resolution::SelfType(impl_block)) => { | 90 | Some(Resolution::SelfType(impl_block)) => { |
91 | if remaining_index.is_some() { | ||
92 | // e.g. Self::Item | ||
93 | return Ty::Unknown; | ||
94 | } | ||
86 | return impl_block.target_ty(db); | 95 | return impl_block.target_ty(db); |
87 | } | 96 | } |
88 | None => return Ty::Unknown, | 97 | None => { |
98 | // path did not resolve | ||
99 | return Ty::Unknown; | ||
100 | } | ||
89 | }; | 101 | }; |
90 | 102 | ||
91 | let typable: TypableDef = match def.into() { | 103 | if let ModuleDef::Trait(trait_) = def { |
92 | None => return Ty::Unknown, | 104 | let segment = match remaining_index { |
93 | Some(it) => it, | 105 | None => path.segments.last().expect("resolved path has at least one element"), |
94 | }; | 106 | Some(i) => &path.segments[i - 1], |
95 | let ty = db.type_for_def(typable, Namespace::Types); | 107 | }; |
96 | let substs = Ty::substs_from_path(db, resolver, path, typable); | 108 | let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None); |
97 | ty.subst(&substs) | 109 | if let Some(remaining_index) = remaining_index { |
110 | if remaining_index == path.segments.len() - 1 { | ||
111 | let segment = &path.segments[remaining_index]; | ||
112 | let associated_ty = | ||
113 | match trait_ref.trait_.associated_type_by_name(db, segment.name.clone()) { | ||
114 | Some(t) => t, | ||
115 | None => { | ||
116 | // associated type not found | ||
117 | return Ty::Unknown; | ||
118 | } | ||
119 | }; | ||
120 | // FIXME handle type parameters on the segment | ||
121 | Ty::Projection(ProjectionTy { associated_ty, parameters: trait_ref.substs }) | ||
122 | } else { | ||
123 | // FIXME more than one segment remaining, is this possible? | ||
124 | Ty::Unknown | ||
125 | } | ||
126 | } else { | ||
127 | // FIXME dyn Trait without the dyn | ||
128 | Ty::Unknown | ||
129 | } | ||
130 | } else { | ||
131 | let typable: TypableDef = match def.into() { | ||
132 | None => return Ty::Unknown, | ||
133 | Some(it) => it, | ||
134 | }; | ||
135 | let ty = db.type_for_def(typable, Namespace::Types); | ||
136 | let substs = Ty::substs_from_path(db, resolver, path, typable); | ||
137 | ty.subst(&substs) | ||
138 | } | ||
98 | } | 139 | } |
99 | 140 | ||
100 | pub(super) fn substs_from_path_segment( | 141 | pub(super) fn substs_from_path_segment( |
@@ -219,14 +260,25 @@ impl TraitRef { | |||
219 | Resolution::Def(ModuleDef::Trait(tr)) => tr, | 260 | Resolution::Def(ModuleDef::Trait(tr)) => tr, |
220 | _ => return None, | 261 | _ => return None, |
221 | }; | 262 | }; |
222 | let mut substs = Self::substs_from_path(db, resolver, path, resolved); | 263 | let segment = path.segments.last().expect("path should have at least one segment"); |
264 | Some(TraitRef::from_resolved_path(db, resolver, resolved, segment, explicit_self_ty)) | ||
265 | } | ||
266 | |||
267 | fn from_resolved_path( | ||
268 | db: &impl HirDatabase, | ||
269 | resolver: &Resolver, | ||
270 | resolved: Trait, | ||
271 | segment: &PathSegment, | ||
272 | explicit_self_ty: Option<Ty>, | ||
273 | ) -> Self { | ||
274 | let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved); | ||
223 | if let Some(self_ty) = explicit_self_ty { | 275 | if let Some(self_ty) = explicit_self_ty { |
224 | // FIXME this could be nicer | 276 | // FIXME this could be nicer |
225 | let mut substs_vec = substs.0.to_vec(); | 277 | let mut substs_vec = substs.0.to_vec(); |
226 | substs_vec[0] = self_ty; | 278 | substs_vec[0] = self_ty; |
227 | substs.0 = substs_vec.into(); | 279 | substs.0 = substs_vec.into(); |
228 | } | 280 | } |
229 | Some(TraitRef { trait_: resolved, substs }) | 281 | TraitRef { trait_: resolved, substs } |
230 | } | 282 | } |
231 | 283 | ||
232 | pub(crate) fn from_hir( | 284 | pub(crate) fn from_hir( |
@@ -245,11 +297,12 @@ impl TraitRef { | |||
245 | fn substs_from_path( | 297 | fn substs_from_path( |
246 | db: &impl HirDatabase, | 298 | db: &impl HirDatabase, |
247 | resolver: &Resolver, | 299 | resolver: &Resolver, |
248 | path: &Path, | 300 | segment: &PathSegment, |
249 | resolved: Trait, | 301 | resolved: Trait, |
250 | ) -> Substs { | 302 | ) -> Substs { |
251 | let segment = path.segments.last().expect("path should have at least one segment"); | 303 | let has_self_param = |
252 | substs_from_path_segment(db, resolver, segment, Some(resolved.into()), true) | 304 | segment.args_and_bindings.as_ref().map(|a| a.has_self_type).unwrap_or(false); |
305 | substs_from_path_segment(db, resolver, segment, Some(resolved.into()), !has_self_param) | ||
253 | } | 306 | } |
254 | 307 | ||
255 | pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef { | 308 | pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef { |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index d421bf9ef..88d012a74 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -255,6 +255,20 @@ fn iterate_inherent_methods<T>( | |||
255 | None | 255 | None |
256 | } | 256 | } |
257 | 257 | ||
258 | pub(crate) fn implements_trait( | ||
259 | ty: &Canonical<Ty>, | ||
260 | db: &impl HirDatabase, | ||
261 | resolver: &Resolver, | ||
262 | krate: Crate, | ||
263 | trait_: Trait, | ||
264 | ) -> bool { | ||
265 | let env = lower::trait_env(db, resolver); | ||
266 | let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone()); | ||
267 | let solution = db.trait_solve(krate, goal); | ||
268 | |||
269 | solution.is_some() | ||
270 | } | ||
271 | |||
258 | impl Ty { | 272 | impl Ty { |
259 | // This would be nicer if it just returned an iterator, but that runs into | 273 | // This would be nicer if it just returned an iterator, but that runs into |
260 | // lifetime problems, because we need to borrow temp `CrateImplBlocks`. | 274 | // lifetime problems, because we need to borrow temp `CrateImplBlocks`. |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 36dea17a3..28727bb18 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -145,6 +145,26 @@ mod collections { | |||
145 | } | 145 | } |
146 | 146 | ||
147 | #[test] | 147 | #[test] |
148 | fn infer_while_let() { | ||
149 | covers!(infer_while_let); | ||
150 | let (db, pos) = MockDatabase::with_position( | ||
151 | r#" | ||
152 | //- /main.rs | ||
153 | enum Option<T> { Some(T), None } | ||
154 | |||
155 | fn test() { | ||
156 | let foo: Option<f32> = None; | ||
157 | while let Option::Some(x) = foo { | ||
158 | <|>x | ||
159 | } | ||
160 | } | ||
161 | |||
162 | "#, | ||
163 | ); | ||
164 | assert_eq!("f32", type_at_pos(&db, pos)); | ||
165 | } | ||
166 | |||
167 | #[test] | ||
148 | fn infer_basics() { | 168 | fn infer_basics() { |
149 | assert_snapshot_matches!( | 169 | assert_snapshot_matches!( |
150 | infer(r#" | 170 | infer(r#" |
@@ -2488,15 +2508,55 @@ struct S; | |||
2488 | impl Iterable for S { type Item = u32; } | 2508 | impl Iterable for S { type Item = u32; } |
2489 | fn test<T: Iterable>() { | 2509 | fn test<T: Iterable>() { |
2490 | let x: <S as Iterable>::Item = 1; | 2510 | let x: <S as Iterable>::Item = 1; |
2491 | let y: T::Item = no_matter; | 2511 | let y: <T as Iterable>::Item = no_matter; |
2512 | let z: T::Item = no_matter; | ||
2513 | } | ||
2514 | "#), | ||
2515 | @r###" | ||
2516 | ⋮ | ||
2517 | ⋮[108; 227) '{ ...ter; }': () | ||
2518 | ⋮[118; 119) 'x': u32 | ||
2519 | ⋮[145; 146) '1': u32 | ||
2520 | ⋮[156; 157) 'y': {unknown} | ||
2521 | ⋮[183; 192) 'no_matter': {unknown} | ||
2522 | ⋮[202; 203) 'z': {unknown} | ||
2523 | ⋮[215; 224) 'no_matter': {unknown} | ||
2524 | "### | ||
2525 | ); | ||
2526 | } | ||
2527 | |||
2528 | #[test] | ||
2529 | fn infer_return_associated_type() { | ||
2530 | assert_snapshot_matches!( | ||
2531 | infer(r#" | ||
2532 | trait Iterable { | ||
2533 | type Item; | ||
2534 | } | ||
2535 | struct S; | ||
2536 | impl Iterable for S { type Item = u32; } | ||
2537 | fn foo1<T: Iterable>(t: T) -> T::Item {} | ||
2538 | fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {} | ||
2539 | fn test() { | ||
2540 | let x = foo1(S); | ||
2541 | let y = foo2(S); | ||
2492 | } | 2542 | } |
2493 | "#), | 2543 | "#), |
2494 | @r###" | 2544 | @r###" |
2495 | [108; 181) '{ ...ter; }': () | 2545 | ⋮ |
2496 | [118; 119) 'x': i32 | 2546 | ⋮[106; 107) 't': T |
2497 | [145; 146) '1': i32 | 2547 | ⋮[123; 125) '{}': () |
2498 | [156; 157) 'y': {unknown} | 2548 | ⋮[147; 148) 't': T |
2499 | [169; 178) 'no_matter': {unknown}"### | 2549 | ⋮[178; 180) '{}': () |
2550 | ⋮[191; 236) '{ ...(S); }': () | ||
2551 | ⋮[201; 202) 'x': {unknown} | ||
2552 | ⋮[205; 209) 'foo1': fn foo1<S>(T) -> {unknown} | ||
2553 | ⋮[205; 212) 'foo1(S)': {unknown} | ||
2554 | ⋮[210; 211) 'S': S | ||
2555 | ⋮[222; 223) 'y': u32 | ||
2556 | ⋮[226; 230) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item | ||
2557 | ⋮[226; 233) 'foo2(S)': u32 | ||
2558 | ⋮[231; 232) 'S': S | ||
2559 | "### | ||
2500 | ); | 2560 | ); |
2501 | } | 2561 | } |
2502 | 2562 | ||
@@ -3121,6 +3181,55 @@ fn test<T: Trait>(t: T) { (*t)<|>; } | |||
3121 | assert_eq!(t, "i128"); | 3181 | assert_eq!(t, "i128"); |
3122 | } | 3182 | } |
3123 | 3183 | ||
3184 | #[test] | ||
3185 | fn associated_type_placeholder() { | ||
3186 | let t = type_at( | ||
3187 | r#" | ||
3188 | //- /main.rs | ||
3189 | pub trait ApplyL { | ||
3190 | type Out; | ||
3191 | } | ||
3192 | |||
3193 | pub struct RefMutL<T>; | ||
3194 | |||
3195 | impl<T> ApplyL for RefMutL<T> { | ||
3196 | type Out = <T as ApplyL>::Out; | ||
3197 | } | ||
3198 | |||
3199 | fn test<T: ApplyL>() { | ||
3200 | let y: <RefMutL<T> as ApplyL>::Out = no_matter; | ||
3201 | y<|>; | ||
3202 | } | ||
3203 | "#, | ||
3204 | ); | ||
3205 | // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types]. | ||
3206 | // FIXME: fix type parameter names going missing when going through Chalk | ||
3207 | assert_eq!(t, "ApplyL::Out<[missing name]>"); | ||
3208 | } | ||
3209 | |||
3210 | #[test] | ||
3211 | fn associated_type_placeholder_2() { | ||
3212 | let t = type_at( | ||
3213 | r#" | ||
3214 | //- /main.rs | ||
3215 | pub trait ApplyL { | ||
3216 | type Out; | ||
3217 | } | ||
3218 | fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out; | ||
3219 | |||
3220 | fn test<T: ApplyL>(t: T) { | ||
3221 | let y = foo(t); | ||
3222 | y<|>; | ||
3223 | } | ||
3224 | "#, | ||
3225 | ); | ||
3226 | // FIXME here Chalk doesn't normalize the type to a placeholder. I think we | ||
3227 | // need to add a rule like Normalize(<T as ApplyL>::Out -> ApplyL::Out<T>) | ||
3228 | // to the trait env ourselves here; probably Chalk can't do this by itself. | ||
3229 | // assert_eq!(t, "ApplyL::Out<[missing name]>"); | ||
3230 | assert_eq!(t, "{unknown}"); | ||
3231 | } | ||
3232 | |||
3124 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 3233 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
3125 | let file = db.parse(pos.file_id).ok().unwrap(); | 3234 | let file = db.parse(pos.file_id).ok().unwrap(); |
3126 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 3235 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index 0769e6e17..fde5d8a47 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -7,7 +7,7 @@ use parking_lot::Mutex; | |||
7 | use ra_prof::profile; | 7 | use ra_prof::profile; |
8 | use rustc_hash::FxHashSet; | 8 | use rustc_hash::FxHashSet; |
9 | 9 | ||
10 | use super::{Canonical, GenericPredicate, ProjectionTy, TraitRef, Ty}; | 10 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty}; |
11 | use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; | 11 | use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; |
12 | 12 | ||
13 | use self::chalk::{from_chalk, ToChalk}; | 13 | use self::chalk::{from_chalk, ToChalk}; |
@@ -61,7 +61,6 @@ fn solve( | |||
61 | ) -> Option<chalk_solve::Solution> { | 61 | ) -> Option<chalk_solve::Solution> { |
62 | let context = ChalkContext { db, krate }; | 62 | let context = ChalkContext { db, krate }; |
63 | let solver = db.trait_solver(krate); | 63 | let solver = db.trait_solver(krate); |
64 | debug!("solve goal: {:?}", goal); | ||
65 | let solution = solver.lock().solve(&context, goal); | 64 | let solution = solver.lock().solve(&context, goal); |
66 | debug!("solve({:?}) => {:?}", goal, solution); | 65 | debug!("solve({:?}) => {:?}", goal, solution); |
67 | solution | 66 | solution |
@@ -120,10 +119,11 @@ pub struct ProjectionPredicate { | |||
120 | pub(crate) fn trait_solve_query( | 119 | pub(crate) fn trait_solve_query( |
121 | db: &impl HirDatabase, | 120 | db: &impl HirDatabase, |
122 | krate: Crate, | 121 | krate: Crate, |
123 | trait_ref: Canonical<InEnvironment<Obligation>>, | 122 | goal: Canonical<InEnvironment<Obligation>>, |
124 | ) -> Option<Solution> { | 123 | ) -> Option<Solution> { |
125 | let _p = profile("trait_solve_query"); | 124 | let _p = profile("trait_solve_query"); |
126 | let canonical = trait_ref.to_chalk(db).cast(); | 125 | debug!("trait_solve_query({})", goal.value.value.display(db)); |
126 | let canonical = goal.to_chalk(db).cast(); | ||
127 | // We currently don't deal with universes (I think / hope they're not yet | 127 | // We currently don't deal with universes (I think / hope they're not yet |
128 | // relevant for our use cases?) | 128 | // relevant for our use cases?) |
129 | let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; | 129 | let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 9e7ae0724..6df7094c5 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -45,11 +45,33 @@ impl ToChalk for Ty { | |||
45 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty { | 45 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty { |
46 | match self { | 46 | match self { |
47 | Ty::Apply(apply_ty) => { | 47 | Ty::Apply(apply_ty) => { |
48 | let struct_id = apply_ty.ctor.to_chalk(db); | 48 | let name = match apply_ty.ctor { |
49 | let name = TypeName::TypeKindId(struct_id.into()); | 49 | TypeCtor::AssociatedType(type_alias) => { |
50 | let type_id = type_alias.to_chalk(db); | ||
51 | TypeName::AssociatedType(type_id) | ||
52 | } | ||
53 | _ => { | ||
54 | // other TypeCtors get interned and turned into a chalk StructId | ||
55 | let struct_id = apply_ty.ctor.to_chalk(db); | ||
56 | TypeName::TypeKindId(struct_id.into()) | ||
57 | } | ||
58 | }; | ||
50 | let parameters = apply_ty.parameters.to_chalk(db); | 59 | let parameters = apply_ty.parameters.to_chalk(db); |
51 | chalk_ir::ApplicationTy { name, parameters }.cast() | 60 | chalk_ir::ApplicationTy { name, parameters }.cast() |
52 | } | 61 | } |
62 | Ty::Projection(proj_ty) => { | ||
63 | let associated_ty_id = proj_ty.associated_ty.to_chalk(db); | ||
64 | let parameters = proj_ty.parameters.to_chalk(db); | ||
65 | chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast() | ||
66 | } | ||
67 | Ty::UnselectedProjection(proj_ty) => { | ||
68 | let type_name = lalrpop_intern::intern(&proj_ty.type_name.to_string()); | ||
69 | let parameters = proj_ty.parameters.to_chalk(db); | ||
70 | chalk_ir::Ty::UnselectedProjection(chalk_ir::UnselectedProjectionTy { | ||
71 | type_name, | ||
72 | parameters, | ||
73 | }) | ||
74 | } | ||
53 | Ty::Param { idx, .. } => { | 75 | Ty::Param { idx, .. } => { |
54 | PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty() | 76 | PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty() |
55 | } | 77 | } |
@@ -66,15 +88,21 @@ impl ToChalk for Ty { | |||
66 | fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { | 88 | fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { |
67 | match chalk { | 89 | match chalk { |
68 | chalk_ir::Ty::Apply(apply_ty) => { | 90 | chalk_ir::Ty::Apply(apply_ty) => { |
91 | // FIXME this is kind of hacky due to the fact that | ||
92 | // TypeName::Placeholder is a Ty::Param on our side | ||
69 | match apply_ty.name { | 93 | match apply_ty.name { |
70 | TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => { | 94 | TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => { |
71 | let ctor = from_chalk(db, struct_id); | 95 | let ctor = from_chalk(db, struct_id); |
72 | let parameters = from_chalk(db, apply_ty.parameters); | 96 | let parameters = from_chalk(db, apply_ty.parameters); |
73 | Ty::Apply(ApplicationTy { ctor, parameters }) | 97 | Ty::Apply(ApplicationTy { ctor, parameters }) |
74 | } | 98 | } |
99 | TypeName::AssociatedType(type_id) => { | ||
100 | let ctor = TypeCtor::AssociatedType(from_chalk(db, type_id)); | ||
101 | let parameters = from_chalk(db, apply_ty.parameters); | ||
102 | Ty::Apply(ApplicationTy { ctor, parameters }) | ||
103 | } | ||
75 | // FIXME handle TypeKindId::Trait/Type here | 104 | // FIXME handle TypeKindId::Trait/Type here |
76 | TypeName::TypeKindId(_) => unimplemented!(), | 105 | TypeName::TypeKindId(_) => unimplemented!(), |
77 | TypeName::AssociatedType(_) => unimplemented!(), | ||
78 | TypeName::Placeholder(idx) => { | 106 | TypeName::Placeholder(idx) => { |
79 | assert_eq!(idx.ui, UniverseIndex::ROOT); | 107 | assert_eq!(idx.ui, UniverseIndex::ROOT); |
80 | Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() } | 108 | Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() } |
@@ -389,11 +417,12 @@ where | |||
389 | &self, | 417 | &self, |
390 | projection: &'p chalk_ir::ProjectionTy, | 418 | projection: &'p chalk_ir::ProjectionTy, |
391 | ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) { | 419 | ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) { |
392 | debug!("split_projection {:?}", projection); | 420 | let proj_ty: ProjectionTy = from_chalk(self.db, projection.clone()); |
393 | unimplemented!() | 421 | debug!("split_projection {:?} = {}", projection, proj_ty.display(self.db)); |
422 | // we don't support GATs, so I think this should always be correct currently | ||
423 | (self.db.associated_ty_data(projection.associated_ty_id), &projection.parameters, &[]) | ||
394 | } | 424 | } |
395 | fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause> { | 425 | fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause> { |
396 | debug!("custom_clauses"); | ||
397 | vec![] | 426 | vec![] |
398 | } | 427 | } |
399 | fn all_structs(&self) -> Vec<chalk_ir::StructId> { | 428 | fn all_structs(&self) -> Vec<chalk_ir::StructId> { |
@@ -529,6 +558,16 @@ pub(crate) fn struct_datum_query( | |||
529 | adt.krate(db) != Some(krate), | 558 | adt.krate(db) != Some(krate), |
530 | ) | 559 | ) |
531 | } | 560 | } |
561 | TypeCtor::AssociatedType(type_alias) => { | ||
562 | let generic_params = type_alias.generic_params(db); | ||
563 | let bound_vars = Substs::bound_vars(&generic_params); | ||
564 | let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); | ||
565 | ( | ||
566 | generic_params.count_params_including_parent(), | ||
567 | where_clauses, | ||
568 | type_alias.krate(db) != Some(krate), | ||
569 | ) | ||
570 | } | ||
532 | }; | 571 | }; |
533 | let flags = chalk_rust_ir::StructFlags { | 572 | let flags = chalk_rust_ir::StructFlags { |
534 | upstream, | 573 | upstream, |
diff --git a/crates/ra_ide_api/Cargo.toml b/crates/ra_ide_api/Cargo.toml index dd11ec0f6..a7dc0b63a 100644 --- a/crates/ra_ide_api/Cargo.toml +++ b/crates/ra_ide_api/Cargo.toml | |||
@@ -27,7 +27,7 @@ test_utils = { path = "../test_utils" } | |||
27 | ra_assists = { path = "../ra_assists" } | 27 | ra_assists = { path = "../ra_assists" } |
28 | 28 | ||
29 | [dev-dependencies] | 29 | [dev-dependencies] |
30 | insta = "0.9.0" | 30 | insta = "0.10.0" |
31 | 31 | ||
32 | [dev-dependencies.proptest] | 32 | [dev-dependencies.proptest] |
33 | version = "0.9.0" | 33 | version = "0.9.0" |
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index 536ba36df..d43ff2eec 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs | |||
@@ -1,19 +1,36 @@ | |||
1 | use hir::{AdtDef, Ty, TypeCtor}; | 1 | use hir::{AdtDef, Ty, TypeCtor}; |
2 | 2 | ||
3 | use crate::completion::{CompletionContext, Completions}; | 3 | use crate::completion::completion_item::CompletionKind; |
4 | use crate::{ | ||
5 | completion::{completion_context::CompletionContext, completion_item::Completions}, | ||
6 | CompletionItem, | ||
7 | }; | ||
4 | use rustc_hash::FxHashSet; | 8 | use rustc_hash::FxHashSet; |
5 | 9 | ||
6 | /// Complete dot accesses, i.e. fields or methods (currently only fields). | 10 | /// Complete dot accesses, i.e. fields or methods (and .await syntax). |
7 | pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | 11 | pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { |
8 | let receiver_ty = | 12 | let dot_receiver = match &ctx.dot_receiver { |
9 | match ctx.dot_receiver.as_ref().and_then(|it| ctx.analyzer.type_of(ctx.db, it)) { | 13 | Some(expr) => expr, |
10 | Some(it) => it, | 14 | _ => return, |
11 | None => return, | 15 | }; |
12 | }; | 16 | |
17 | let receiver_ty = match ctx.analyzer.type_of(ctx.db, &dot_receiver) { | ||
18 | Some(ty) => ty, | ||
19 | _ => return, | ||
20 | }; | ||
21 | |||
13 | if !ctx.is_call { | 22 | if !ctx.is_call { |
14 | complete_fields(acc, ctx, receiver_ty.clone()); | 23 | complete_fields(acc, ctx, receiver_ty.clone()); |
15 | } | 24 | } |
16 | complete_methods(acc, ctx, receiver_ty); | 25 | complete_methods(acc, ctx, receiver_ty.clone()); |
26 | |||
27 | // Suggest .await syntax for types that implement Future trait | ||
28 | if ctx.analyzer.impls_future(ctx.db, receiver_ty) { | ||
29 | CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") | ||
30 | .detail("expr.await") | ||
31 | .insert_text("await") | ||
32 | .add_to(acc); | ||
33 | } | ||
17 | } | 34 | } |
18 | 35 | ||
19 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { | 36 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { |
@@ -406,4 +423,36 @@ mod tests { | |||
406 | "### | 423 | "### |
407 | ); | 424 | ); |
408 | } | 425 | } |
426 | |||
427 | #[test] | ||
428 | fn test_completion_await_impls_future() { | ||
429 | assert_debug_snapshot_matches!( | ||
430 | do_completion( | ||
431 | r###" | ||
432 | //- /main.rs | ||
433 | use std::future::*; | ||
434 | struct A {} | ||
435 | impl Future for A {} | ||
436 | fn foo(a: A) { | ||
437 | a.<|> | ||
438 | } | ||
439 | |||
440 | //- /std/lib.rs | ||
441 | pub mod future { | ||
442 | pub trait Future {} | ||
443 | } | ||
444 | "###, CompletionKind::Keyword), | ||
445 | @r###" | ||
446 | ⋮[ | ||
447 | ⋮ CompletionItem { | ||
448 | ⋮ label: "await", | ||
449 | ⋮ source_range: [74; 74), | ||
450 | ⋮ delete: [74; 74), | ||
451 | ⋮ insert: "await", | ||
452 | ⋮ detail: "expr.await", | ||
453 | ⋮ }, | ||
454 | ⋮] | ||
455 | "### | ||
456 | ) | ||
457 | } | ||
409 | } | 458 | } |
diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs index 028dc3d4f..98b840b26 100644 --- a/crates/ra_ide_api/src/diagnostics.rs +++ b/crates/ra_ide_api/src/diagnostics.rs | |||
@@ -48,7 +48,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic> | |||
48 | }) | 48 | }) |
49 | }) | 49 | }) |
50 | .on::<hir::diagnostics::UnresolvedModule, _>(|d| { | 50 | .on::<hir::diagnostics::UnresolvedModule, _>(|d| { |
51 | let source_root = db.file_source_root(d.file().original_file(db)); | 51 | let source_root = db.file_source_root(d.source().file_id.original_file(db)); |
52 | let create_file = FileSystemEdit::CreateFile { source_root, path: d.candidate.clone() }; | 52 | let create_file = FileSystemEdit::CreateFile { source_root, path: d.candidate.clone() }; |
53 | let fix = SourceChange::file_system_edit("create module", create_file); | 53 | let fix = SourceChange::file_system_edit("create module", create_file); |
54 | res.borrow_mut().push(Diagnostic { | 54 | res.borrow_mut().push(Diagnostic { |
diff --git a/crates/ra_ide_api/src/inlay_hints.rs b/crates/ra_ide_api/src/inlay_hints.rs index a524e014f..0b3c96d26 100644 --- a/crates/ra_ide_api/src/inlay_hints.rs +++ b/crates/ra_ide_api/src/inlay_hints.rs | |||
@@ -9,14 +9,9 @@ use ra_syntax::{ | |||
9 | SmolStr, SyntaxKind, SyntaxNode, TextRange, | 9 | SmolStr, SyntaxKind, SyntaxNode, TextRange, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | #[derive(Debug, PartialEq, Eq, Clone)] | 12 | #[derive(Debug, PartialEq, Eq)] |
13 | pub enum InlayKind { | 13 | pub enum InlayKind { |
14 | LetBindingType, | 14 | TypeHint, |
15 | ClosureParameterType, | ||
16 | ForExpressionBindingType, | ||
17 | IfExpressionType, | ||
18 | WhileLetExpressionType, | ||
19 | MatchArmType, | ||
20 | } | 15 | } |
21 | 16 | ||
22 | #[derive(Debug)] | 17 | #[derive(Debug)] |
@@ -46,7 +41,7 @@ fn get_inlay_hints( | |||
46 | } | 41 | } |
47 | let pat = let_statement.pat()?; | 42 | let pat = let_statement.pat()?; |
48 | let analyzer = SourceAnalyzer::new(db, file_id, let_statement.syntax(), None); | 43 | let analyzer = SourceAnalyzer::new(db, file_id, let_statement.syntax(), None); |
49 | Some(get_pat_hints(db, &analyzer, pat, InlayKind::LetBindingType, false)) | 44 | Some(get_pat_type_hints(db, &analyzer, pat, false)) |
50 | }) | 45 | }) |
51 | .visit(|closure_parameter: LambdaExpr| { | 46 | .visit(|closure_parameter: LambdaExpr| { |
52 | let analyzer = SourceAnalyzer::new(db, file_id, closure_parameter.syntax(), None); | 47 | let analyzer = SourceAnalyzer::new(db, file_id, closure_parameter.syntax(), None); |
@@ -55,15 +50,7 @@ fn get_inlay_hints( | |||
55 | .params() | 50 | .params() |
56 | .filter(|closure_param| closure_param.ascribed_type().is_none()) | 51 | .filter(|closure_param| closure_param.ascribed_type().is_none()) |
57 | .filter_map(|closure_param| closure_param.pat()) | 52 | .filter_map(|closure_param| closure_param.pat()) |
58 | .map(|root_pat| { | 53 | .map(|root_pat| get_pat_type_hints(db, &analyzer, root_pat, false)) |
59 | get_pat_hints( | ||
60 | db, | ||
61 | &analyzer, | ||
62 | root_pat, | ||
63 | InlayKind::ClosureParameterType, | ||
64 | false, | ||
65 | ) | ||
66 | }) | ||
67 | .flatten() | 54 | .flatten() |
68 | .collect() | 55 | .collect() |
69 | }) | 56 | }) |
@@ -71,17 +58,17 @@ fn get_inlay_hints( | |||
71 | .visit(|for_expression: ForExpr| { | 58 | .visit(|for_expression: ForExpr| { |
72 | let pat = for_expression.pat()?; | 59 | let pat = for_expression.pat()?; |
73 | let analyzer = SourceAnalyzer::new(db, file_id, for_expression.syntax(), None); | 60 | let analyzer = SourceAnalyzer::new(db, file_id, for_expression.syntax(), None); |
74 | Some(get_pat_hints(db, &analyzer, pat, InlayKind::ForExpressionBindingType, false)) | 61 | Some(get_pat_type_hints(db, &analyzer, pat, false)) |
75 | }) | 62 | }) |
76 | .visit(|if_expr: IfExpr| { | 63 | .visit(|if_expr: IfExpr| { |
77 | let pat = if_expr.condition()?.pat()?; | 64 | let pat = if_expr.condition()?.pat()?; |
78 | let analyzer = SourceAnalyzer::new(db, file_id, if_expr.syntax(), None); | 65 | let analyzer = SourceAnalyzer::new(db, file_id, if_expr.syntax(), None); |
79 | Some(get_pat_hints(db, &analyzer, pat, InlayKind::IfExpressionType, true)) | 66 | Some(get_pat_type_hints(db, &analyzer, pat, true)) |
80 | }) | 67 | }) |
81 | .visit(|while_expr: WhileExpr| { | 68 | .visit(|while_expr: WhileExpr| { |
82 | let pat = while_expr.condition()?.pat()?; | 69 | let pat = while_expr.condition()?.pat()?; |
83 | let analyzer = SourceAnalyzer::new(db, file_id, while_expr.syntax(), None); | 70 | let analyzer = SourceAnalyzer::new(db, file_id, while_expr.syntax(), None); |
84 | Some(get_pat_hints(db, &analyzer, pat, InlayKind::WhileLetExpressionType, true)) | 71 | Some(get_pat_type_hints(db, &analyzer, pat, true)) |
85 | }) | 72 | }) |
86 | .visit(|match_arm_list: MatchArmList| { | 73 | .visit(|match_arm_list: MatchArmList| { |
87 | let analyzer = SourceAnalyzer::new(db, file_id, match_arm_list.syntax(), None); | 74 | let analyzer = SourceAnalyzer::new(db, file_id, match_arm_list.syntax(), None); |
@@ -90,9 +77,7 @@ fn get_inlay_hints( | |||
90 | .arms() | 77 | .arms() |
91 | .map(|match_arm| match_arm.pats()) | 78 | .map(|match_arm| match_arm.pats()) |
92 | .flatten() | 79 | .flatten() |
93 | .map(|root_pat| { | 80 | .map(|root_pat| get_pat_type_hints(db, &analyzer, root_pat, true)) |
94 | get_pat_hints(db, &analyzer, root_pat, InlayKind::MatchArmType, true) | ||
95 | }) | ||
96 | .flatten() | 81 | .flatten() |
97 | .collect(), | 82 | .collect(), |
98 | ) | 83 | ) |
@@ -100,11 +85,10 @@ fn get_inlay_hints( | |||
100 | .accept(&node)? | 85 | .accept(&node)? |
101 | } | 86 | } |
102 | 87 | ||
103 | fn get_pat_hints( | 88 | fn get_pat_type_hints( |
104 | db: &RootDatabase, | 89 | db: &RootDatabase, |
105 | analyzer: &SourceAnalyzer, | 90 | analyzer: &SourceAnalyzer, |
106 | root_pat: Pat, | 91 | root_pat: Pat, |
107 | kind: InlayKind, | ||
108 | skip_root_pat_hint: bool, | 92 | skip_root_pat_hint: bool, |
109 | ) -> Vec<InlayHint> { | 93 | ) -> Vec<InlayHint> { |
110 | let original_pat = &root_pat.clone(); | 94 | let original_pat = &root_pat.clone(); |
@@ -118,7 +102,7 @@ fn get_pat_hints( | |||
118 | }) | 102 | }) |
119 | .map(|(range, pat_type)| InlayHint { | 103 | .map(|(range, pat_type)| InlayHint { |
120 | range, | 104 | range, |
121 | kind: kind.clone(), | 105 | kind: InlayKind::TypeHint, |
122 | label: pat_type.display(db).to_string().into(), | 106 | label: pat_type.display(db).to_string().into(), |
123 | }) | 107 | }) |
124 | .collect() | 108 | .collect() |
@@ -232,52 +216,52 @@ fn main() { | |||
232 | assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[ | 216 | assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[ |
233 | InlayHint { | 217 | InlayHint { |
234 | range: [193; 197), | 218 | range: [193; 197), |
235 | kind: LetBindingType, | 219 | kind: TypeHint, |
236 | label: "i32", | 220 | label: "i32", |
237 | }, | 221 | }, |
238 | InlayHint { | 222 | InlayHint { |
239 | range: [236; 244), | 223 | range: [236; 244), |
240 | kind: LetBindingType, | 224 | kind: TypeHint, |
241 | label: "i32", | 225 | label: "i32", |
242 | }, | 226 | }, |
243 | InlayHint { | 227 | InlayHint { |
244 | range: [275; 279), | 228 | range: [275; 279), |
245 | kind: LetBindingType, | 229 | kind: TypeHint, |
246 | label: "&str", | 230 | label: "&str", |
247 | }, | 231 | }, |
248 | InlayHint { | 232 | InlayHint { |
249 | range: [539; 543), | 233 | range: [539; 543), |
250 | kind: LetBindingType, | 234 | kind: TypeHint, |
251 | label: "(i32, char)", | 235 | label: "(i32, char)", |
252 | }, | 236 | }, |
253 | InlayHint { | 237 | InlayHint { |
254 | range: [566; 567), | 238 | range: [566; 567), |
255 | kind: LetBindingType, | 239 | kind: TypeHint, |
256 | label: "i32", | 240 | label: "i32", |
257 | }, | 241 | }, |
258 | InlayHint { | 242 | InlayHint { |
259 | range: [570; 571), | 243 | range: [570; 571), |
260 | kind: LetBindingType, | 244 | kind: TypeHint, |
261 | label: "i32", | 245 | label: "i32", |
262 | }, | 246 | }, |
263 | InlayHint { | 247 | InlayHint { |
264 | range: [573; 574), | 248 | range: [573; 574), |
265 | kind: LetBindingType, | 249 | kind: TypeHint, |
266 | label: "i32", | 250 | label: "i32", |
267 | }, | 251 | }, |
268 | InlayHint { | 252 | InlayHint { |
269 | range: [584; 585), | 253 | range: [584; 585), |
270 | kind: LetBindingType, | 254 | kind: TypeHint, |
271 | label: "i32", | 255 | label: "i32", |
272 | }, | 256 | }, |
273 | InlayHint { | 257 | InlayHint { |
274 | range: [577; 578), | 258 | range: [577; 578), |
275 | kind: LetBindingType, | 259 | kind: TypeHint, |
276 | label: "f64", | 260 | label: "f64", |
277 | }, | 261 | }, |
278 | InlayHint { | 262 | InlayHint { |
279 | range: [580; 581), | 263 | range: [580; 581), |
280 | kind: LetBindingType, | 264 | kind: TypeHint, |
281 | label: "f64", | 265 | label: "f64", |
282 | }, | 266 | }, |
283 | ]"# | 267 | ]"# |
@@ -299,12 +283,12 @@ fn main() { | |||
299 | assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[ | 283 | assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[ |
300 | InlayHint { | 284 | InlayHint { |
301 | range: [21; 30), | 285 | range: [21; 30), |
302 | kind: LetBindingType, | 286 | kind: TypeHint, |
303 | label: "i32", | 287 | label: "i32", |
304 | }, | 288 | }, |
305 | InlayHint { | 289 | InlayHint { |
306 | range: [57; 66), | 290 | range: [57; 66), |
307 | kind: ClosureParameterType, | 291 | kind: TypeHint, |
308 | label: "i32", | 292 | label: "i32", |
309 | }, | 293 | }, |
310 | ]"# | 294 | ]"# |
@@ -326,12 +310,12 @@ fn main() { | |||
326 | assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[ | 310 | assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[ |
327 | InlayHint { | 311 | InlayHint { |
328 | range: [21; 30), | 312 | range: [21; 30), |
329 | kind: LetBindingType, | 313 | kind: TypeHint, |
330 | label: "i32", | 314 | label: "i32", |
331 | }, | 315 | }, |
332 | InlayHint { | 316 | InlayHint { |
333 | range: [44; 53), | 317 | range: [44; 53), |
334 | kind: ForExpressionBindingType, | 318 | kind: TypeHint, |
335 | label: "i32", | 319 | label: "i32", |
336 | }, | 320 | }, |
337 | ]"# | 321 | ]"# |
@@ -364,7 +348,7 @@ fn main() { | |||
364 | if let CustomOption::Some(Test { a: CustomOption::Some(x), b: y }) = &test {}; | 348 | if let CustomOption::Some(Test { a: CustomOption::Some(x), b: y }) = &test {}; |
365 | if let CustomOption::Some(Test { a: CustomOption::None, b: y }) = &test {}; | 349 | if let CustomOption::Some(Test { a: CustomOption::None, b: y }) = &test {}; |
366 | if let CustomOption::Some(Test { b: y, .. }) = &test {}; | 350 | if let CustomOption::Some(Test { b: y, .. }) = &test {}; |
367 | 351 | ||
368 | if test == CustomOption::None {} | 352 | if test == CustomOption::None {} |
369 | }"#, | 353 | }"#, |
370 | ); | 354 | ); |
@@ -372,27 +356,27 @@ fn main() { | |||
372 | assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[ | 356 | assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[ |
373 | InlayHint { | 357 | InlayHint { |
374 | range: [166; 170), | 358 | range: [166; 170), |
375 | kind: LetBindingType, | 359 | kind: TypeHint, |
376 | label: "CustomOption<Test>", | 360 | label: "CustomOption<Test>", |
377 | }, | 361 | }, |
378 | InlayHint { | 362 | InlayHint { |
379 | range: [334; 338), | 363 | range: [334; 338), |
380 | kind: IfExpressionType, | 364 | kind: TypeHint, |
381 | label: "&Test", | 365 | label: "&Test", |
382 | }, | 366 | }, |
383 | InlayHint { | 367 | InlayHint { |
384 | range: [389; 390), | 368 | range: [389; 390), |
385 | kind: IfExpressionType, | 369 | kind: TypeHint, |
386 | label: "&CustomOption<u32>", | 370 | label: "&CustomOption<u32>", |
387 | }, | 371 | }, |
388 | InlayHint { | 372 | InlayHint { |
389 | range: [392; 393), | 373 | range: [392; 393), |
390 | kind: IfExpressionType, | 374 | kind: TypeHint, |
391 | label: "&u8", | 375 | label: "&u8", |
392 | }, | 376 | }, |
393 | InlayHint { | 377 | InlayHint { |
394 | range: [531; 532), | 378 | range: [531; 532), |
395 | kind: IfExpressionType, | 379 | kind: TypeHint, |
396 | label: "&u32", | 380 | label: "&u32", |
397 | }, | 381 | }, |
398 | ]"# | 382 | ]"# |
@@ -425,18 +409,40 @@ fn main() { | |||
425 | while let CustomOption::Some(Test { a: CustomOption::Some(x), b: y }) = &test {}; | 409 | while let CustomOption::Some(Test { a: CustomOption::Some(x), b: y }) = &test {}; |
426 | while let CustomOption::Some(Test { a: CustomOption::None, b: y }) = &test {}; | 410 | while let CustomOption::Some(Test { a: CustomOption::None, b: y }) = &test {}; |
427 | while let CustomOption::Some(Test { b: y, .. }) = &test {}; | 411 | while let CustomOption::Some(Test { b: y, .. }) = &test {}; |
428 | 412 | ||
429 | while test == CustomOption::None {} | 413 | while test == CustomOption::None {} |
430 | }"#, | 414 | }"#, |
431 | ); | 415 | ); |
432 | 416 | ||
433 | assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[ | 417 | assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r###" |
434 | InlayHint { | 418 | ⋮[ |
435 | range: [166; 170), | 419 | ⋮ InlayHint { |
436 | kind: LetBindingType, | 420 | ⋮ range: [166; 170), |
437 | label: "CustomOption<Test>", | 421 | ⋮ kind: TypeHint, |
438 | }, | 422 | ⋮ label: "CustomOption<Test>", |
439 | ]"# | 423 | ⋮ }, |
424 | ⋮ InlayHint { | ||
425 | ⋮ range: [343; 347), | ||
426 | ⋮ kind: TypeHint, | ||
427 | ⋮ label: "&Test", | ||
428 | ⋮ }, | ||
429 | ⋮ InlayHint { | ||
430 | ⋮ range: [401; 402), | ||
431 | ⋮ kind: TypeHint, | ||
432 | ⋮ label: "&CustomOption<u32>", | ||
433 | ⋮ }, | ||
434 | ⋮ InlayHint { | ||
435 | ⋮ range: [404; 405), | ||
436 | ⋮ kind: TypeHint, | ||
437 | ⋮ label: "&u8", | ||
438 | ⋮ }, | ||
439 | ⋮ InlayHint { | ||
440 | ⋮ range: [549; 550), | ||
441 | ⋮ kind: TypeHint, | ||
442 | ⋮ label: "&u32", | ||
443 | ⋮ }, | ||
444 | ⋮] | ||
445 | "### | ||
440 | ); | 446 | ); |
441 | } | 447 | } |
442 | 448 | ||
@@ -445,7 +451,7 @@ fn main() { | |||
445 | let (analysis, file_id) = single_file( | 451 | let (analysis, file_id) = single_file( |
446 | r#" | 452 | r#" |
447 | #[derive(PartialEq)] | 453 | #[derive(PartialEq)] |
448 | enum CustomOption<T> { | 454 | enum CustomOption<T> { |
449 | None, | 455 | None, |
450 | Some(T), | 456 | Some(T), |
451 | } | 457 | } |
@@ -473,23 +479,23 @@ fn main() { | |||
473 | 479 | ||
474 | assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[ | 480 | assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[ |
475 | InlayHint { | 481 | InlayHint { |
476 | range: [312; 316), | 482 | range: [311; 315), |
477 | kind: MatchArmType, | 483 | kind: TypeHint, |
478 | label: "Test", | 484 | label: "Test", |
479 | }, | 485 | }, |
480 | InlayHint { | 486 | InlayHint { |
481 | range: [359; 360), | 487 | range: [358; 359), |
482 | kind: MatchArmType, | 488 | kind: TypeHint, |
483 | label: "CustomOption<u32>", | 489 | label: "CustomOption<u32>", |
484 | }, | 490 | }, |
485 | InlayHint { | 491 | InlayHint { |
486 | range: [362; 363), | 492 | range: [361; 362), |
487 | kind: MatchArmType, | 493 | kind: TypeHint, |
488 | label: "u8", | 494 | label: "u8", |
489 | }, | 495 | }, |
490 | InlayHint { | 496 | InlayHint { |
491 | range: [485; 486), | 497 | range: [484; 485), |
492 | kind: MatchArmType, | 498 | kind: TypeHint, |
493 | label: "u32", | 499 | label: "u32", |
494 | }, | 500 | }, |
495 | ]"# | 501 | ]"# |
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index cec360667..c282d6db8 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml | |||
@@ -25,6 +25,7 @@ ra_ide_api = { path = "../ra_ide_api" } | |||
25 | gen_lsp_server = { path = "../gen_lsp_server" } | 25 | gen_lsp_server = { path = "../gen_lsp_server" } |
26 | ra_project_model = { path = "../ra_project_model" } | 26 | ra_project_model = { path = "../ra_project_model" } |
27 | ra_prof = { path = "../ra_prof" } | 27 | ra_prof = { path = "../ra_prof" } |
28 | ra_vfs_glob = { path = "../ra_vfs_glob" } | ||
28 | 29 | ||
29 | [dev-dependencies] | 30 | [dev-dependencies] |
30 | tempfile = "3" | 31 | tempfile = "3" |
diff --git a/crates/ra_lsp_server/src/init.rs b/crates/ra_lsp_server/src/config.rs index b894b449d..6dcdc695a 100644 --- a/crates/ra_lsp_server/src/init.rs +++ b/crates/ra_lsp_server/src/config.rs | |||
@@ -1,9 +1,9 @@ | |||
1 | use serde::{Deserialize, Deserializer}; | 1 | use serde::{Deserialize, Deserializer}; |
2 | 2 | ||
3 | /// Client provided initialization options | 3 | /// Client provided initialization options |
4 | #[derive(Deserialize, Clone, Copy, Debug, PartialEq, Eq)] | 4 | #[derive(Deserialize, Clone, Debug, PartialEq, Eq)] |
5 | #[serde(rename_all = "camelCase", default)] | 5 | #[serde(rename_all = "camelCase", default)] |
6 | pub struct InitializationOptions { | 6 | pub struct ServerConfig { |
7 | /// Whether the client supports our custom highlighting publishing decorations. | 7 | /// Whether the client supports our custom highlighting publishing decorations. |
8 | /// This is different to the highlightingOn setting, which is whether the user | 8 | /// This is different to the highlightingOn setting, which is whether the user |
9 | /// wants our custom highlighting to be used. | 9 | /// wants our custom highlighting to be used. |
@@ -18,14 +18,17 @@ pub struct InitializationOptions { | |||
18 | #[serde(deserialize_with = "nullable_bool_true")] | 18 | #[serde(deserialize_with = "nullable_bool_true")] |
19 | pub show_workspace_loaded: bool, | 19 | pub show_workspace_loaded: bool, |
20 | 20 | ||
21 | pub exclude_globs: Vec<String>, | ||
22 | |||
21 | pub lru_capacity: Option<usize>, | 23 | pub lru_capacity: Option<usize>, |
22 | } | 24 | } |
23 | 25 | ||
24 | impl Default for InitializationOptions { | 26 | impl Default for ServerConfig { |
25 | fn default() -> InitializationOptions { | 27 | fn default() -> ServerConfig { |
26 | InitializationOptions { | 28 | ServerConfig { |
27 | publish_decorations: false, | 29 | publish_decorations: false, |
28 | show_workspace_loaded: true, | 30 | show_workspace_loaded: true, |
31 | exclude_globs: Vec::new(), | ||
29 | lru_capacity: None, | 32 | lru_capacity: None, |
30 | } | 33 | } |
31 | } | 34 | } |
@@ -56,7 +59,7 @@ mod test { | |||
56 | #[test] | 59 | #[test] |
57 | fn deserialize_init_options_defaults() { | 60 | fn deserialize_init_options_defaults() { |
58 | // check that null == default for both fields | 61 | // check that null == default for both fields |
59 | let default = InitializationOptions::default(); | 62 | let default = ServerConfig::default(); |
60 | assert_eq!(default, serde_json::from_str(r#"{}"#).unwrap()); | 63 | assert_eq!(default, serde_json::from_str(r#"{}"#).unwrap()); |
61 | assert_eq!( | 64 | assert_eq!( |
62 | default, | 65 | default, |
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index 59c5e1582..df8ea6e0d 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs | |||
@@ -1,13 +1,13 @@ | |||
1 | use lsp_types::{ | 1 | use lsp_types::{ |
2 | self, CreateFile, DocumentChangeOperation, DocumentChanges, Documentation, Location, | 2 | self, CreateFile, DiagnosticSeverity, DocumentChangeOperation, DocumentChanges, Documentation, |
3 | LocationLink, MarkupContent, MarkupKind, Position, Range, RenameFile, ResourceOp, SymbolKind, | 3 | Location, LocationLink, MarkupContent, MarkupKind, Position, Range, RenameFile, ResourceOp, |
4 | TextDocumentEdit, TextDocumentIdentifier, TextDocumentItem, TextDocumentPositionParams, Url, | 4 | SymbolKind, TextDocumentEdit, TextDocumentIdentifier, TextDocumentItem, |
5 | VersionedTextDocumentIdentifier, WorkspaceEdit, | 5 | TextDocumentPositionParams, Url, VersionedTextDocumentIdentifier, WorkspaceEdit, |
6 | }; | 6 | }; |
7 | use ra_ide_api::{ | 7 | use ra_ide_api::{ |
8 | translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition, | 8 | translate_offset_with_edit, CompletionItem, CompletionItemKind, FileId, FilePosition, |
9 | FileRange, FileSystemEdit, InsertTextFormat, LineCol, LineIndex, NavigationTarget, RangeInfo, | 9 | FileRange, FileSystemEdit, InsertTextFormat, LineCol, LineIndex, NavigationTarget, RangeInfo, |
10 | SourceChange, SourceFileEdit, | 10 | Severity, SourceChange, SourceFileEdit, |
11 | }; | 11 | }; |
12 | use ra_syntax::{SyntaxKind, TextRange, TextUnit}; | 12 | use ra_syntax::{SyntaxKind, TextRange, TextUnit}; |
13 | use ra_text_edit::{AtomTextEdit, TextEdit}; | 13 | use ra_text_edit::{AtomTextEdit, TextEdit}; |
@@ -79,6 +79,16 @@ impl Conv for CompletionItemKind { | |||
79 | } | 79 | } |
80 | } | 80 | } |
81 | 81 | ||
82 | impl Conv for Severity { | ||
83 | type Output = DiagnosticSeverity; | ||
84 | fn conv(self) -> DiagnosticSeverity { | ||
85 | match self { | ||
86 | Severity::Error => DiagnosticSeverity::Error, | ||
87 | Severity::WeakWarning => DiagnosticSeverity::Hint, | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | |||
82 | impl ConvWith for CompletionItem { | 92 | impl ConvWith for CompletionItem { |
83 | type Ctx = LineIndex; | 93 | type Ctx = LineIndex; |
84 | type Output = ::lsp_types::CompletionItem; | 94 | type Output = ::lsp_types::CompletionItem; |
diff --git a/crates/ra_lsp_server/src/lib.rs b/crates/ra_lsp_server/src/lib.rs index 56a263aa5..795f86383 100644 --- a/crates/ra_lsp_server/src/lib.rs +++ b/crates/ra_lsp_server/src/lib.rs | |||
@@ -4,13 +4,11 @@ mod conv; | |||
4 | mod main_loop; | 4 | mod main_loop; |
5 | mod markdown; | 5 | mod markdown; |
6 | mod project_model; | 6 | mod project_model; |
7 | mod vfs_filter; | ||
8 | pub mod req; | 7 | pub mod req; |
9 | pub mod init; | 8 | pub mod config; |
10 | mod world; | 9 | mod world; |
11 | 10 | ||
12 | pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; | 11 | pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; |
13 | pub use crate::{ | 12 | pub use crate::{ |
14 | caps::server_capabilities, init::InitializationOptions, main_loop::main_loop, | 13 | caps::server_capabilities, config::ServerConfig, main_loop::main_loop, main_loop::LspError, |
15 | main_loop::LspError, | ||
16 | }; | 14 | }; |
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs index c1f8243be..1a2ab1bc2 100644 --- a/crates/ra_lsp_server/src/main.rs +++ b/crates/ra_lsp_server/src/main.rs | |||
@@ -2,7 +2,7 @@ use flexi_logger::{Duplicate, Logger}; | |||
2 | use gen_lsp_server::{run_server, stdio_transport}; | 2 | use gen_lsp_server::{run_server, stdio_transport}; |
3 | use serde::Deserialize; | 3 | use serde::Deserialize; |
4 | 4 | ||
5 | use ra_lsp_server::{InitializationOptions, Result}; | 5 | use ra_lsp_server::{Result, ServerConfig}; |
6 | use ra_prof; | 6 | use ra_prof; |
7 | 7 | ||
8 | fn main() -> Result<()> { | 8 | fn main() -> Result<()> { |
@@ -48,7 +48,7 @@ fn main_inner() -> Result<()> { | |||
48 | 48 | ||
49 | let opts = params | 49 | let opts = params |
50 | .initialization_options | 50 | .initialization_options |
51 | .and_then(|v| InitializationOptions::deserialize(v).ok()) | 51 | .and_then(|v| ServerConfig::deserialize(v).ok()) |
52 | .unwrap_or_default(); | 52 | .unwrap_or_default(); |
53 | 53 | ||
54 | ra_lsp_server::main_loop(workspace_roots, params.capabilities, opts, r, s) | 54 | ra_lsp_server::main_loop(workspace_roots, params.capabilities, opts, r, s) |
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 8e830c8b8..b9c99a223 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs | |||
@@ -23,7 +23,7 @@ use crate::{ | |||
23 | project_model::workspace_loader, | 23 | project_model::workspace_loader, |
24 | req, | 24 | req, |
25 | world::{Options, WorldSnapshot, WorldState}, | 25 | world::{Options, WorldSnapshot, WorldState}, |
26 | InitializationOptions, Result, | 26 | Result, ServerConfig, |
27 | }; | 27 | }; |
28 | 28 | ||
29 | const THREADPOOL_SIZE: usize = 8; | 29 | const THREADPOOL_SIZE: usize = 8; |
@@ -52,10 +52,11 @@ impl Error for LspError {} | |||
52 | pub fn main_loop( | 52 | pub fn main_loop( |
53 | ws_roots: Vec<PathBuf>, | 53 | ws_roots: Vec<PathBuf>, |
54 | client_caps: ClientCapabilities, | 54 | client_caps: ClientCapabilities, |
55 | options: InitializationOptions, | 55 | config: ServerConfig, |
56 | msg_receiver: &Receiver<RawMessage>, | 56 | msg_receiver: &Receiver<RawMessage>, |
57 | msg_sender: &Sender<RawMessage>, | 57 | msg_sender: &Sender<RawMessage>, |
58 | ) -> Result<()> { | 58 | ) -> Result<()> { |
59 | log::debug!("server_config: {:?}", config); | ||
59 | // FIXME: support dynamic workspace loading. | 60 | // FIXME: support dynamic workspace loading. |
60 | let workspaces = { | 61 | let workspaces = { |
61 | let ws_worker = workspace_loader(); | 62 | let ws_worker = workspace_loader(); |
@@ -77,14 +78,19 @@ pub fn main_loop( | |||
77 | } | 78 | } |
78 | loaded_workspaces | 79 | loaded_workspaces |
79 | }; | 80 | }; |
80 | 81 | let globs = config | |
82 | .exclude_globs | ||
83 | .iter() | ||
84 | .map(|glob| ra_vfs_glob::Glob::new(glob)) | ||
85 | .collect::<std::result::Result<Vec<_>, _>>()?; | ||
81 | let mut state = WorldState::new( | 86 | let mut state = WorldState::new( |
82 | ws_roots, | 87 | ws_roots, |
83 | workspaces, | 88 | workspaces, |
84 | options.lru_capacity, | 89 | config.lru_capacity, |
90 | &globs, | ||
85 | Options { | 91 | Options { |
86 | publish_decorations: options.publish_decorations, | 92 | publish_decorations: config.publish_decorations, |
87 | show_workspace_loaded: options.show_workspace_loaded, | 93 | show_workspace_loaded: config.show_workspace_loaded, |
88 | supports_location_link: client_caps | 94 | supports_location_link: client_caps |
89 | .text_document | 95 | .text_document |
90 | .and_then(|it| it.definition) | 96 | .and_then(|it| it.definition) |
@@ -269,7 +275,7 @@ fn main_loop_inner( | |||
269 | && pending_libraries.is_empty() | 275 | && pending_libraries.is_empty() |
270 | && in_flight_libraries == 0 | 276 | && in_flight_libraries == 0 |
271 | { | 277 | { |
272 | let n_packages: usize = state.workspaces.iter().map(|it| it.count()).sum(); | 278 | let n_packages: usize = state.workspaces.iter().map(|it| it.n_packages()).sum(); |
273 | if state.options.show_workspace_loaded { | 279 | if state.options.show_workspace_loaded { |
274 | let msg = format!("workspace loaded, {} rust packages", n_packages); | 280 | let msg = format!("workspace loaded, {} rust packages", n_packages); |
275 | show_message(req::MessageType::Info, msg, msg_sender); | 281 | show_message(req::MessageType::Info, msg, msg_sender); |
@@ -340,7 +346,6 @@ fn on_request( | |||
340 | })? | 346 | })? |
341 | .on::<req::AnalyzerStatus>(handlers::handle_analyzer_status)? | 347 | .on::<req::AnalyzerStatus>(handlers::handle_analyzer_status)? |
342 | .on::<req::SyntaxTree>(handlers::handle_syntax_tree)? | 348 | .on::<req::SyntaxTree>(handlers::handle_syntax_tree)? |
343 | .on::<req::ExtendSelection>(handlers::handle_extend_selection)? | ||
344 | .on::<req::OnTypeFormatting>(handlers::handle_on_type_formatting)? | 349 | .on::<req::OnTypeFormatting>(handlers::handle_on_type_formatting)? |
345 | .on::<req::DocumentSymbolRequest>(handlers::handle_document_symbol)? | 350 | .on::<req::DocumentSymbolRequest>(handlers::handle_document_symbol)? |
346 | .on::<req::WorkspaceSymbol>(handlers::handle_workspace_symbol)? | 351 | .on::<req::WorkspaceSymbol>(handlers::handle_workspace_symbol)? |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index c2a44ffa0..a3d3f167c 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -3,13 +3,13 @@ use std::{fmt::Write as _, io::Write as _}; | |||
3 | use gen_lsp_server::ErrorCode; | 3 | use gen_lsp_server::ErrorCode; |
4 | use lsp_types::{ | 4 | use lsp_types::{ |
5 | CodeAction, CodeActionResponse, CodeLens, Command, CompletionItem, Diagnostic, | 5 | CodeAction, CodeActionResponse, CodeLens, Command, CompletionItem, Diagnostic, |
6 | DiagnosticSeverity, DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, | 6 | DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeKind, |
7 | FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, | 7 | FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind, Position, |
8 | MarkupKind, Position, PrepareRenameResponse, Range, RenameParams, SymbolInformation, | 8 | PrepareRenameResponse, Range, RenameParams, SymbolInformation, TextDocumentIdentifier, |
9 | TextDocumentIdentifier, TextEdit, WorkspaceEdit, | 9 | TextEdit, WorkspaceEdit, |
10 | }; | 10 | }; |
11 | use ra_ide_api::{ | 11 | use ra_ide_api::{ |
12 | AssistId, Cancelable, FileId, FilePosition, FileRange, FoldKind, Query, RunnableKind, Severity, | 12 | AssistId, FileId, FilePosition, FileRange, FoldKind, Query, Runnable, RunnableKind, |
13 | }; | 13 | }; |
14 | use ra_prof::profile; | 14 | use ra_prof::profile; |
15 | use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; | 15 | use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; |
@@ -45,27 +45,6 @@ pub fn handle_syntax_tree(world: WorldSnapshot, params: req::SyntaxTreeParams) - | |||
45 | Ok(res) | 45 | Ok(res) |
46 | } | 46 | } |
47 | 47 | ||
48 | // FIXME: drop this API | ||
49 | pub fn handle_extend_selection( | ||
50 | world: WorldSnapshot, | ||
51 | params: req::ExtendSelectionParams, | ||
52 | ) -> Result<req::ExtendSelectionResult> { | ||
53 | log::error!( | ||
54 | "extend selection is deprecated and will be removed soon, | ||
55 | use the new selection range API in LSP", | ||
56 | ); | ||
57 | let file_id = params.text_document.try_conv_with(&world)?; | ||
58 | let line_index = world.analysis().file_line_index(file_id)?; | ||
59 | let selections = params | ||
60 | .selections | ||
61 | .into_iter() | ||
62 | .map_conv_with(&line_index) | ||
63 | .map(|range| FileRange { file_id, range }) | ||
64 | .map(|frange| world.analysis().extend_selection(frange).map(|it| it.conv_with(&line_index))) | ||
65 | .collect::<Cancelable<Vec<_>>>()?; | ||
66 | Ok(req::ExtendSelectionResult { selections }) | ||
67 | } | ||
68 | |||
69 | pub fn handle_selection_range( | 48 | pub fn handle_selection_range( |
70 | world: WorldSnapshot, | 49 | world: WorldSnapshot, |
71 | params: req::SelectionRangeParams, | 50 | params: req::SelectionRangeParams, |
@@ -325,27 +304,7 @@ pub fn handle_runnables( | |||
325 | continue; | 304 | continue; |
326 | } | 305 | } |
327 | } | 306 | } |
328 | 307 | res.push(to_lsp_runnable(&world, file_id, runnable)?); | |
329 | let args = runnable_args(&world, file_id, &runnable.kind)?; | ||
330 | |||
331 | let r = req::Runnable { | ||
332 | range: runnable.range.conv_with(&line_index), | ||
333 | label: match &runnable.kind { | ||
334 | RunnableKind::Test { name } => format!("test {}", name), | ||
335 | RunnableKind::TestMod { path } => format!("test-mod {}", path), | ||
336 | RunnableKind::Bench { name } => format!("bench {}", name), | ||
337 | RunnableKind::Bin => "run binary".to_string(), | ||
338 | }, | ||
339 | bin: "cargo".to_string(), | ||
340 | args, | ||
341 | env: { | ||
342 | let mut m = FxHashMap::default(); | ||
343 | m.insert("RUST_BACKTRACE".to_string(), "short".to_string()); | ||
344 | m | ||
345 | }, | ||
346 | cwd: workspace_root.map(|root| root.to_string_lossy().to_string()), | ||
347 | }; | ||
348 | res.push(r); | ||
349 | } | 308 | } |
350 | let mut check_args = vec!["check".to_string()]; | 309 | let mut check_args = vec!["check".to_string()]; |
351 | let label; | 310 | let label; |
@@ -693,42 +652,27 @@ pub fn handle_code_lens( | |||
693 | let line_index = world.analysis().file_line_index(file_id)?; | 652 | let line_index = world.analysis().file_line_index(file_id)?; |
694 | 653 | ||
695 | let mut lenses: Vec<CodeLens> = Default::default(); | 654 | let mut lenses: Vec<CodeLens> = Default::default(); |
696 | let workspace_root = world.workspace_root_for(file_id); | ||
697 | 655 | ||
698 | // Gather runnables | 656 | // Gather runnables |
699 | for runnable in world.analysis().runnables(file_id)? { | 657 | for runnable in world.analysis().runnables(file_id)? { |
700 | let title = match &runnable.kind { | 658 | let title = match &runnable.kind { |
701 | RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => Some("▶️Run Test"), | 659 | RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => "▶️Run Test", |
702 | RunnableKind::Bench { .. } => Some("Run Bench"), | 660 | RunnableKind::Bench { .. } => "Run Bench", |
703 | RunnableKind::Bin => Some("️Run"), | 661 | RunnableKind::Bin => "Run", |
662 | } | ||
663 | .to_string(); | ||
664 | let r = to_lsp_runnable(&world, file_id, runnable)?; | ||
665 | let lens = CodeLens { | ||
666 | range: r.range, | ||
667 | command: Some(Command { | ||
668 | title, | ||
669 | command: "rust-analyzer.runSingle".into(), | ||
670 | arguments: Some(vec![to_value(r).unwrap()]), | ||
671 | }), | ||
672 | data: None, | ||
704 | }; | 673 | }; |
705 | 674 | ||
706 | if let Some(title) = title { | 675 | lenses.push(lens); |
707 | let args = runnable_args(&world, file_id, &runnable.kind)?; | ||
708 | let range = runnable.range.conv_with(&line_index); | ||
709 | |||
710 | // This represents the actual command that will be run. | ||
711 | let r: req::Runnable = req::Runnable { | ||
712 | range, | ||
713 | label: Default::default(), | ||
714 | bin: "cargo".into(), | ||
715 | args, | ||
716 | env: Default::default(), | ||
717 | cwd: workspace_root.map(|root| root.to_string_lossy().to_string()), | ||
718 | }; | ||
719 | |||
720 | let lens = CodeLens { | ||
721 | range, | ||
722 | command: Some(Command { | ||
723 | title: title.into(), | ||
724 | command: "rust-analyzer.runSingle".into(), | ||
725 | arguments: Some(vec![to_value(r).unwrap()]), | ||
726 | }), | ||
727 | data: None, | ||
728 | }; | ||
729 | |||
730 | lenses.push(lens); | ||
731 | } | ||
732 | } | 676 | } |
733 | 677 | ||
734 | // Handle impls | 678 | // Handle impls |
@@ -838,7 +782,7 @@ pub fn publish_diagnostics( | |||
838 | .into_iter() | 782 | .into_iter() |
839 | .map(|d| Diagnostic { | 783 | .map(|d| Diagnostic { |
840 | range: d.range.conv_with(&line_index), | 784 | range: d.range.conv_with(&line_index), |
841 | severity: Some(to_diagnostic_severity(d.severity)), | 785 | severity: Some(d.severity.conv()), |
842 | code: None, | 786 | code: None, |
843 | source: Some("rust-analyzer".to_string()), | 787 | source: Some("rust-analyzer".to_string()), |
844 | message: d.message, | 788 | message: d.message, |
@@ -856,6 +800,32 @@ pub fn publish_decorations( | |||
856 | Ok(req::PublishDecorationsParams { uri, decorations: highlight(&world, file_id)? }) | 800 | Ok(req::PublishDecorationsParams { uri, decorations: highlight(&world, file_id)? }) |
857 | } | 801 | } |
858 | 802 | ||
803 | fn to_lsp_runnable( | ||
804 | world: &WorldSnapshot, | ||
805 | file_id: FileId, | ||
806 | runnable: Runnable, | ||
807 | ) -> Result<req::Runnable> { | ||
808 | let args = runnable_args(world, file_id, &runnable.kind)?; | ||
809 | let line_index = world.analysis().file_line_index(file_id)?; | ||
810 | let label = match &runnable.kind { | ||
811 | RunnableKind::Test { name } => format!("test {}", name), | ||
812 | RunnableKind::TestMod { path } => format!("test-mod {}", path), | ||
813 | RunnableKind::Bench { name } => format!("bench {}", name), | ||
814 | RunnableKind::Bin => "run binary".to_string(), | ||
815 | }; | ||
816 | Ok(req::Runnable { | ||
817 | range: runnable.range.conv_with(&line_index), | ||
818 | label, | ||
819 | bin: "cargo".to_string(), | ||
820 | args, | ||
821 | env: { | ||
822 | let mut m = FxHashMap::default(); | ||
823 | m.insert("RUST_BACKTRACE".to_string(), "short".to_string()); | ||
824 | m | ||
825 | }, | ||
826 | cwd: world.workspace_root_for(file_id).map(|root| root.to_string_lossy().to_string()), | ||
827 | }) | ||
828 | } | ||
859 | fn highlight(world: &WorldSnapshot, file_id: FileId) -> Result<Vec<Decoration>> { | 829 | fn highlight(world: &WorldSnapshot, file_id: FileId) -> Result<Vec<Decoration>> { |
860 | let line_index = world.analysis().file_line_index(file_id)?; | 830 | let line_index = world.analysis().file_line_index(file_id)?; |
861 | let res = world | 831 | let res = world |
@@ -871,15 +841,6 @@ fn highlight(world: &WorldSnapshot, file_id: FileId) -> Result<Vec<Decoration>> | |||
871 | Ok(res) | 841 | Ok(res) |
872 | } | 842 | } |
873 | 843 | ||
874 | fn to_diagnostic_severity(severity: Severity) -> DiagnosticSeverity { | ||
875 | use ra_ide_api::Severity::*; | ||
876 | |||
877 | match severity { | ||
878 | Error => DiagnosticSeverity::Error, | ||
879 | WeakWarning => DiagnosticSeverity::Hint, | ||
880 | } | ||
881 | } | ||
882 | |||
883 | pub fn handle_inlay_hints( | 844 | pub fn handle_inlay_hints( |
884 | world: WorldSnapshot, | 845 | world: WorldSnapshot, |
885 | params: InlayHintsParams, | 846 | params: InlayHintsParams, |
@@ -894,14 +855,7 @@ pub fn handle_inlay_hints( | |||
894 | label: api_type.label.to_string(), | 855 | label: api_type.label.to_string(), |
895 | range: api_type.range.conv_with(&line_index), | 856 | range: api_type.range.conv_with(&line_index), |
896 | kind: match api_type.kind { | 857 | kind: match api_type.kind { |
897 | ra_ide_api::InlayKind::LetBindingType => InlayKind::LetBindingType, | 858 | ra_ide_api::InlayKind::TypeHint => InlayKind::TypeHint, |
898 | ra_ide_api::InlayKind::ClosureParameterType => InlayKind::ClosureParameterType, | ||
899 | ra_ide_api::InlayKind::ForExpressionBindingType => { | ||
900 | InlayKind::ForExpressionBindingType | ||
901 | } | ||
902 | ra_ide_api::InlayKind::IfExpressionType => InlayKind::IfExpressionType, | ||
903 | ra_ide_api::InlayKind::WhileLetExpressionType => InlayKind::WhileLetExpressionType, | ||
904 | ra_ide_api::InlayKind::MatchArmType => InlayKind::MatchArmType, | ||
905 | }, | 859 | }, |
906 | }) | 860 | }) |
907 | .collect()) | 861 | .collect()) |
diff --git a/crates/ra_lsp_server/src/markdown.rs b/crates/ra_lsp_server/src/markdown.rs index 947ef77cd..c1eb0236a 100644 --- a/crates/ra_lsp_server/src/markdown.rs +++ b/crates/ra_lsp_server/src/markdown.rs | |||
@@ -54,4 +54,21 @@ mod tests { | |||
54 | let comment = "this\nis\nultiline"; | 54 | let comment = "this\nis\nultiline"; |
55 | assert_eq!(format_docs(comment), comment); | 55 | assert_eq!(format_docs(comment), comment); |
56 | } | 56 | } |
57 | |||
58 | #[test] | ||
59 | fn test_code_blocks_in_comments_marked_as_rust() { | ||
60 | let comment = r#"```rust | ||
61 | fn main(){} | ||
62 | ``` | ||
63 | Some comment. | ||
64 | ``` | ||
65 | let a = 1; | ||
66 | ```"#; | ||
67 | |||
68 | assert_eq!( | ||
69 | format_docs(comment), | ||
70 | "```rust\nfn main(){}\n```\nSome comment.\n```rust\nlet a = 1;\n```" | ||
71 | ); | ||
72 | } | ||
73 | |||
57 | } | 74 | } |
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs index 570438643..b2f3c509d 100644 --- a/crates/ra_lsp_server/src/req.rs +++ b/crates/ra_lsp_server/src/req.rs | |||
@@ -43,27 +43,6 @@ pub struct SyntaxTreeParams { | |||
43 | pub range: Option<Range>, | 43 | pub range: Option<Range>, |
44 | } | 44 | } |
45 | 45 | ||
46 | pub enum ExtendSelection {} | ||
47 | |||
48 | impl Request for ExtendSelection { | ||
49 | type Params = ExtendSelectionParams; | ||
50 | type Result = ExtendSelectionResult; | ||
51 | const METHOD: &'static str = "rust-analyzer/extendSelection"; | ||
52 | } | ||
53 | |||
54 | #[derive(Deserialize, Debug)] | ||
55 | #[serde(rename_all = "camelCase")] | ||
56 | pub struct ExtendSelectionParams { | ||
57 | pub text_document: TextDocumentIdentifier, | ||
58 | pub selections: Vec<Range>, | ||
59 | } | ||
60 | |||
61 | #[derive(Serialize, Debug)] | ||
62 | #[serde(rename_all = "camelCase")] | ||
63 | pub struct ExtendSelectionResult { | ||
64 | pub selections: Vec<Range>, | ||
65 | } | ||
66 | |||
67 | pub enum SelectionRangeRequest {} | 46 | pub enum SelectionRangeRequest {} |
68 | 47 | ||
69 | impl Request for SelectionRangeRequest { | 48 | impl Request for SelectionRangeRequest { |
@@ -213,12 +192,7 @@ pub struct InlayHintsParams { | |||
213 | 192 | ||
214 | #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] | 193 | #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] |
215 | pub enum InlayKind { | 194 | pub enum InlayKind { |
216 | LetBindingType, | 195 | TypeHint, |
217 | ClosureParameterType, | ||
218 | ForExpressionBindingType, | ||
219 | IfExpressionType, | ||
220 | WhileLetExpressionType, | ||
221 | MatchArmType, | ||
222 | } | 196 | } |
223 | 197 | ||
224 | #[derive(Debug, Deserialize, Serialize)] | 198 | #[derive(Debug, Deserialize, Serialize)] |
diff --git a/crates/ra_lsp_server/src/vfs_filter.rs b/crates/ra_lsp_server/src/vfs_filter.rs deleted file mode 100644 index e16a57da5..000000000 --- a/crates/ra_lsp_server/src/vfs_filter.rs +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | use ra_project_model::ProjectRoot; | ||
2 | use ra_vfs::{Filter, RelativePath, RootEntry}; | ||
3 | use std::path::PathBuf; | ||
4 | |||
5 | /// `IncludeRustFiles` is used to convert | ||
6 | /// from `ProjectRoot` to `RootEntry` for VFS | ||
7 | pub struct IncludeRustFiles { | ||
8 | root: ProjectRoot, | ||
9 | } | ||
10 | |||
11 | impl IncludeRustFiles { | ||
12 | pub fn from_roots<R>(roots: R) -> impl Iterator<Item = RootEntry> | ||
13 | where | ||
14 | R: IntoIterator<Item = ProjectRoot>, | ||
15 | { | ||
16 | roots.into_iter().map(IncludeRustFiles::from_root) | ||
17 | } | ||
18 | |||
19 | pub fn from_root(root: ProjectRoot) -> RootEntry { | ||
20 | IncludeRustFiles::from(root).into() | ||
21 | } | ||
22 | |||
23 | #[allow(unused)] | ||
24 | pub fn external(path: PathBuf) -> RootEntry { | ||
25 | IncludeRustFiles::from_root(ProjectRoot::new(path, false)) | ||
26 | } | ||
27 | |||
28 | pub fn member(path: PathBuf) -> RootEntry { | ||
29 | IncludeRustFiles::from_root(ProjectRoot::new(path, true)) | ||
30 | } | ||
31 | } | ||
32 | |||
33 | impl Filter for IncludeRustFiles { | ||
34 | fn include_dir(&self, dir_path: &RelativePath) -> bool { | ||
35 | self.root.include_dir(dir_path) | ||
36 | } | ||
37 | |||
38 | fn include_file(&self, file_path: &RelativePath) -> bool { | ||
39 | self.root.include_file(file_path) | ||
40 | } | ||
41 | } | ||
42 | |||
43 | impl std::convert::From<ProjectRoot> for IncludeRustFiles { | ||
44 | fn from(v: ProjectRoot) -> IncludeRustFiles { | ||
45 | IncludeRustFiles { root: v } | ||
46 | } | ||
47 | } | ||
48 | |||
49 | impl std::convert::From<IncludeRustFiles> for RootEntry { | ||
50 | fn from(v: IncludeRustFiles) -> RootEntry { | ||
51 | let path = v.root.path().clone(); | ||
52 | RootEntry::new(path, Box::new(v)) | ||
53 | } | ||
54 | } | ||
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs index 1d7755910..9990ef62e 100644 --- a/crates/ra_lsp_server/src/world.rs +++ b/crates/ra_lsp_server/src/world.rs | |||
@@ -9,13 +9,13 @@ use parking_lot::RwLock; | |||
9 | use ra_ide_api::{ | 9 | use ra_ide_api::{ |
10 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, | 10 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, |
11 | }; | 11 | }; |
12 | use ra_vfs::{Vfs, VfsChange, VfsFile, VfsRoot}; | 12 | use ra_vfs::{RootEntry, Vfs, VfsChange, VfsFile, VfsRoot}; |
13 | use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; | ||
13 | use relative_path::RelativePathBuf; | 14 | use relative_path::RelativePathBuf; |
14 | 15 | ||
15 | use crate::{ | 16 | use crate::{ |
16 | main_loop::pending_requests::{CompletedRequest, LatestRequests}, | 17 | main_loop::pending_requests::{CompletedRequest, LatestRequests}, |
17 | project_model::ProjectWorkspace, | 18 | project_model::ProjectWorkspace, |
18 | vfs_filter::IncludeRustFiles, | ||
19 | LspError, Result, | 19 | LspError, Result, |
20 | }; | 20 | }; |
21 | 21 | ||
@@ -56,14 +56,28 @@ impl WorldState { | |||
56 | folder_roots: Vec<PathBuf>, | 56 | folder_roots: Vec<PathBuf>, |
57 | workspaces: Vec<ProjectWorkspace>, | 57 | workspaces: Vec<ProjectWorkspace>, |
58 | lru_capacity: Option<usize>, | 58 | lru_capacity: Option<usize>, |
59 | exclude_globs: &[Glob], | ||
59 | options: Options, | 60 | options: Options, |
60 | ) -> WorldState { | 61 | ) -> WorldState { |
61 | let mut change = AnalysisChange::new(); | 62 | let mut change = AnalysisChange::new(); |
62 | 63 | ||
63 | let mut roots = Vec::new(); | 64 | let mut roots = Vec::new(); |
64 | roots.extend(folder_roots.iter().cloned().map(IncludeRustFiles::member)); | 65 | roots.extend(folder_roots.iter().map(|path| { |
66 | let mut filter = RustPackageFilterBuilder::default().set_member(true); | ||
67 | for glob in exclude_globs.iter() { | ||
68 | filter = filter.exclude(glob.clone()); | ||
69 | } | ||
70 | RootEntry::new(path.clone(), filter.into_vfs_filter()) | ||
71 | })); | ||
65 | for ws in workspaces.iter() { | 72 | for ws in workspaces.iter() { |
66 | roots.extend(IncludeRustFiles::from_roots(ws.to_roots())); | 73 | roots.extend(ws.to_roots().into_iter().map(|pkg_root| { |
74 | let mut filter = | ||
75 | RustPackageFilterBuilder::default().set_member(pkg_root.is_member()); | ||
76 | for glob in exclude_globs.iter() { | ||
77 | filter = filter.exclude(glob.clone()); | ||
78 | } | ||
79 | RootEntry::new(pkg_root.path().clone(), filter.into_vfs_filter()) | ||
80 | })); | ||
67 | } | 81 | } |
68 | 82 | ||
69 | let (mut vfs, vfs_roots) = Vfs::new(roots); | 83 | let (mut vfs, vfs_roots) = Vfs::new(roots); |
@@ -211,7 +225,7 @@ impl WorldSnapshot { | |||
211 | } else { | 225 | } else { |
212 | res.push_str("workspaces:\n"); | 226 | res.push_str("workspaces:\n"); |
213 | for w in self.workspaces.iter() { | 227 | for w in self.workspaces.iter() { |
214 | res += &format!("{} packages loaded\n", w.count()); | 228 | res += &format!("{} packages loaded\n", w.n_packages()); |
215 | } | 229 | } |
216 | } | 230 | } |
217 | res.push_str("\nanalysis:\n"); | 231 | res.push_str("\nanalysis:\n"); |
diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs index 5dddbbe17..ba8ee8b06 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/support.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs | |||
@@ -22,7 +22,7 @@ use tempfile::TempDir; | |||
22 | use test_utils::{find_mismatch, parse_fixture}; | 22 | use test_utils::{find_mismatch, parse_fixture}; |
23 | use thread_worker::Worker; | 23 | use thread_worker::Worker; |
24 | 24 | ||
25 | use ra_lsp_server::{main_loop, req, InitializationOptions}; | 25 | use ra_lsp_server::{main_loop, req, ServerConfig}; |
26 | 26 | ||
27 | pub struct Project<'a> { | 27 | pub struct Project<'a> { |
28 | fixture: &'a str, | 28 | fixture: &'a str, |
@@ -107,7 +107,7 @@ impl Server { | |||
107 | window: None, | 107 | window: None, |
108 | experimental: None, | 108 | experimental: None, |
109 | }, | 109 | }, |
110 | InitializationOptions::default(), | 110 | ServerConfig::default(), |
111 | &msg_receiver, | 111 | &msg_receiver, |
112 | &msg_sender, | 112 | &msg_sender, |
113 | ) | 113 | ) |
diff --git a/crates/ra_mbe/src/subtree_source.rs b/crates/ra_mbe/src/subtree_source.rs index 6603ff34d..9d6d0133f 100644 --- a/crates/ra_mbe/src/subtree_source.rs +++ b/crates/ra_mbe/src/subtree_source.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use ra_parser::{Token, TokenSource}; | 1 | use ra_parser::{Token, TokenSource}; |
2 | use ra_syntax::{classify_literal, SmolStr, SyntaxKind, SyntaxKind::*, T}; | 2 | use ra_syntax::{classify_literal, SmolStr, SyntaxKind, SyntaxKind::*, T}; |
3 | use std::cell::{Cell, RefCell}; | 3 | use std::cell::{Cell, Ref, RefCell}; |
4 | use tt::buffer::{Cursor, TokenBuffer}; | 4 | use tt::buffer::{Cursor, TokenBuffer}; |
5 | 5 | ||
6 | #[derive(Debug, Clone, Eq, PartialEq)] | 6 | #[derive(Debug, Clone, Eq, PartialEq)] |
@@ -20,8 +20,8 @@ impl<'a> SubtreeTokenSource<'a> { | |||
20 | // Helper function used in test | 20 | // Helper function used in test |
21 | #[cfg(test)] | 21 | #[cfg(test)] |
22 | pub fn text(&self) -> SmolStr { | 22 | pub fn text(&self) -> SmolStr { |
23 | match self.get(self.curr.1) { | 23 | match *self.get(self.curr.1) { |
24 | Some(tt) => tt.text, | 24 | Some(ref tt) => tt.text.clone(), |
25 | _ => SmolStr::new(""), | 25 | _ => SmolStr::new(""), |
26 | } | 26 | } |
27 | } | 27 | } |
@@ -41,44 +41,46 @@ impl<'a> SubtreeTokenSource<'a> { | |||
41 | } | 41 | } |
42 | 42 | ||
43 | fn mk_token(&self, pos: usize) -> Token { | 43 | fn mk_token(&self, pos: usize) -> Token { |
44 | match self.get(pos) { | 44 | match *self.get(pos) { |
45 | Some(tt) => Token { kind: tt.kind, is_jointed_to_next: tt.is_joint_to_next }, | 45 | Some(ref tt) => Token { kind: tt.kind, is_jointed_to_next: tt.is_joint_to_next }, |
46 | None => Token { kind: EOF, is_jointed_to_next: false }, | 46 | None => Token { kind: EOF, is_jointed_to_next: false }, |
47 | } | 47 | } |
48 | } | 48 | } |
49 | 49 | ||
50 | fn get(&self, pos: usize) -> Option<TtToken> { | 50 | fn get(&self, pos: usize) -> Ref<Option<TtToken>> { |
51 | let mut cached = self.cached.borrow_mut(); | 51 | if pos < self.cached.borrow().len() { |
52 | if pos < cached.len() { | 52 | return Ref::map(self.cached.borrow(), |c| &c[pos]); |
53 | return cached[pos].clone(); | ||
54 | } | 53 | } |
55 | 54 | ||
56 | while pos >= cached.len() { | 55 | { |
57 | let cursor = self.cached_cursor.get(); | 56 | let mut cached = self.cached.borrow_mut(); |
58 | if cursor.eof() { | 57 | while pos >= cached.len() { |
59 | cached.push(None); | 58 | let cursor = self.cached_cursor.get(); |
60 | continue; | 59 | if cursor.eof() { |
61 | } | 60 | cached.push(None); |
62 | 61 | continue; | |
63 | match cursor.token_tree() { | ||
64 | Some(tt::TokenTree::Leaf(leaf)) => { | ||
65 | cached.push(Some(convert_leaf(&leaf))); | ||
66 | self.cached_cursor.set(cursor.bump()); | ||
67 | } | ||
68 | Some(tt::TokenTree::Subtree(subtree)) => { | ||
69 | self.cached_cursor.set(cursor.subtree().unwrap()); | ||
70 | cached.push(Some(convert_delim(subtree.delimiter, false))); | ||
71 | } | 62 | } |
72 | None => { | 63 | |
73 | if let Some(subtree) = cursor.end() { | 64 | match cursor.token_tree() { |
74 | cached.push(Some(convert_delim(subtree.delimiter, true))); | 65 | Some(tt::TokenTree::Leaf(leaf)) => { |
66 | cached.push(Some(convert_leaf(&leaf))); | ||
75 | self.cached_cursor.set(cursor.bump()); | 67 | self.cached_cursor.set(cursor.bump()); |
76 | } | 68 | } |
69 | Some(tt::TokenTree::Subtree(subtree)) => { | ||
70 | self.cached_cursor.set(cursor.subtree().unwrap()); | ||
71 | cached.push(Some(convert_delim(subtree.delimiter, false))); | ||
72 | } | ||
73 | None => { | ||
74 | if let Some(subtree) = cursor.end() { | ||
75 | cached.push(Some(convert_delim(subtree.delimiter, true))); | ||
76 | self.cached_cursor.set(cursor.bump()); | ||
77 | } | ||
78 | } | ||
77 | } | 79 | } |
78 | } | 80 | } |
79 | } | 81 | } |
80 | 82 | ||
81 | cached[pos].clone() | 83 | Ref::map(self.cached.borrow(), |c| &c[pos]) |
82 | } | 84 | } |
83 | } | 85 | } |
84 | 86 | ||
@@ -103,8 +105,8 @@ impl<'a> TokenSource for SubtreeTokenSource<'a> { | |||
103 | 105 | ||
104 | /// Is the current token a specified keyword? | 106 | /// Is the current token a specified keyword? |
105 | fn is_keyword(&self, kw: &str) -> bool { | 107 | fn is_keyword(&self, kw: &str) -> bool { |
106 | match self.get(self.curr.1) { | 108 | match *self.get(self.curr.1) { |
107 | Some(t) => t.text == *kw, | 109 | Some(ref t) => t.text == *kw, |
108 | _ => false, | 110 | _ => false, |
109 | } | 111 | } |
110 | } | 112 | } |
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs index 658034097..beedac457 100644 --- a/crates/ra_parser/src/grammar.rs +++ b/crates/ra_parser/src/grammar.rs | |||
@@ -287,6 +287,16 @@ fn name_ref(p: &mut Parser) { | |||
287 | } | 287 | } |
288 | } | 288 | } |
289 | 289 | ||
290 | fn name_ref_or_index(p: &mut Parser) { | ||
291 | if p.at(IDENT) || p.at(INT_NUMBER) { | ||
292 | let m = p.start(); | ||
293 | p.bump(); | ||
294 | m.complete(p, NAME_REF); | ||
295 | } else { | ||
296 | p.err_and_bump("expected identifier"); | ||
297 | } | ||
298 | } | ||
299 | |||
290 | fn error_block(p: &mut Parser, message: &str) { | 300 | fn error_block(p: &mut Parser, message: &str) { |
291 | assert!(p.at(T!['{'])); | 301 | assert!(p.at(T!['{'])); |
292 | let m = p.start(); | 302 | let m = p.start(); |
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index b60a2f68c..742076c1a 100644 --- a/crates/ra_parser/src/grammar/expressions.rs +++ b/crates/ra_parser/src/grammar/expressions.rs | |||
@@ -489,10 +489,8 @@ fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker { | |||
489 | assert!(p.at(T![.])); | 489 | assert!(p.at(T![.])); |
490 | let m = lhs.precede(p); | 490 | let m = lhs.precede(p); |
491 | p.bump(); | 491 | p.bump(); |
492 | if p.at(IDENT) { | 492 | if p.at(IDENT) || p.at(INT_NUMBER) { |
493 | name_ref(p) | 493 | name_ref_or_index(p) |
494 | } else if p.at(INT_NUMBER) { | ||
495 | p.bump(); | ||
496 | } else if p.at(FLOAT_NUMBER) { | 494 | } else if p.at(FLOAT_NUMBER) { |
497 | // FIXME: How to recover and instead parse INT + T![.]? | 495 | // FIXME: How to recover and instead parse INT + T![.]? |
498 | p.bump(); | 496 | p.bump(); |
@@ -577,6 +575,7 @@ fn path_expr(p: &mut Parser, r: Restrictions) -> (CompletedMarker, BlockLike) { | |||
577 | // S {}; | 575 | // S {}; |
578 | // S { x, y: 32, }; | 576 | // S { x, y: 32, }; |
579 | // S { x, y: 32, ..Default::default() }; | 577 | // S { x, y: 32, ..Default::default() }; |
578 | // TupleStruct { 0: 1 }; | ||
580 | // } | 579 | // } |
581 | pub(crate) fn named_field_list(p: &mut Parser) { | 580 | pub(crate) fn named_field_list(p: &mut Parser) { |
582 | assert!(p.at(T!['{'])); | 581 | assert!(p.at(T!['{'])); |
@@ -588,10 +587,10 @@ pub(crate) fn named_field_list(p: &mut Parser) { | |||
588 | // fn main() { | 587 | // fn main() { |
589 | // S { #[cfg(test)] field: 1 } | 588 | // S { #[cfg(test)] field: 1 } |
590 | // } | 589 | // } |
591 | IDENT | T![#] => { | 590 | IDENT | INT_NUMBER | T![#] => { |
592 | let m = p.start(); | 591 | let m = p.start(); |
593 | attributes::outer_attributes(p); | 592 | attributes::outer_attributes(p); |
594 | name_ref(p); | 593 | name_ref_or_index(p); |
595 | if p.eat(T![:]) { | 594 | if p.eat(T![:]) { |
596 | expr(p); | 595 | expr(p); |
597 | } | 596 | } |
diff --git a/crates/ra_parser/src/grammar/params.rs b/crates/ra_parser/src/grammar/params.rs index 723b56343..0b09f1874 100644 --- a/crates/ra_parser/src/grammar/params.rs +++ b/crates/ra_parser/src/grammar/params.rs | |||
@@ -41,9 +41,20 @@ fn list_(p: &mut Parser, flavor: Flavor) { | |||
41 | let m = p.start(); | 41 | let m = p.start(); |
42 | p.bump(); | 42 | p.bump(); |
43 | if flavor.type_required() { | 43 | if flavor.type_required() { |
44 | // test self_param_outer_attr | ||
45 | // fn f(#[must_use] self) {} | ||
46 | attributes::outer_attributes(p); | ||
44 | opt_self_param(p); | 47 | opt_self_param(p); |
45 | } | 48 | } |
46 | while !p.at(EOF) && !p.at(ket) && !(flavor.type_required() && p.at(T![...])) { | 49 | while !p.at(EOF) && !p.at(ket) { |
50 | // test param_outer_arg | ||
51 | // fn f(#[attr1] pat: Type) {} | ||
52 | attributes::outer_attributes(p); | ||
53 | |||
54 | if flavor.type_required() && p.at(T![...]) { | ||
55 | break; | ||
56 | } | ||
57 | |||
47 | if !p.at_ts(VALUE_PARAMETER_FIRST) { | 58 | if !p.at_ts(VALUE_PARAMETER_FIRST) { |
48 | p.error("expected value parameter"); | 59 | p.error("expected value parameter"); |
49 | break; | 60 | break; |
diff --git a/crates/ra_parser/src/grammar/type_args.rs b/crates/ra_parser/src/grammar/type_args.rs index f391b63db..3db08b280 100644 --- a/crates/ra_parser/src/grammar/type_args.rs +++ b/crates/ra_parser/src/grammar/type_args.rs | |||
@@ -35,6 +35,13 @@ fn type_arg(p: &mut Parser) { | |||
35 | p.bump(); | 35 | p.bump(); |
36 | m.complete(p, LIFETIME_ARG); | 36 | m.complete(p, LIFETIME_ARG); |
37 | } | 37 | } |
38 | // test associated_type_bounds | ||
39 | // fn print_all<T: Iterator<Item: Display>>(printables: T) {} | ||
40 | IDENT if p.nth(1) == T![:] => { | ||
41 | name_ref(p); | ||
42 | type_params::bounds(p); | ||
43 | m.complete(p, ASSOC_TYPE_ARG); | ||
44 | } | ||
38 | IDENT if p.nth(1) == T![=] => { | 45 | IDENT if p.nth(1) == T![=] => { |
39 | name_ref(p); | 46 | name_ref(p); |
40 | p.bump(); | 47 | p.bump(); |
diff --git a/crates/ra_parser/src/parser.rs b/crates/ra_parser/src/parser.rs index 159ed50df..393586561 100644 --- a/crates/ra_parser/src/parser.rs +++ b/crates/ra_parser/src/parser.rs | |||
@@ -6,7 +6,7 @@ use crate::{ | |||
6 | event::Event, | 6 | event::Event, |
7 | ParseError, | 7 | ParseError, |
8 | SyntaxKind::{self, EOF, ERROR, TOMBSTONE}, | 8 | SyntaxKind::{self, EOF, ERROR, TOMBSTONE}, |
9 | TokenSet, TokenSource, T, | 9 | Token, TokenSet, TokenSource, T, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | /// `Parser` struct provides the low-level API for | 12 | /// `Parser` struct provides the low-level API for |
@@ -87,8 +87,9 @@ impl<'t> Parser<'t> { | |||
87 | let mut i = 0; | 87 | let mut i = 0; |
88 | 88 | ||
89 | loop { | 89 | loop { |
90 | let mut kind = self.token_source.lookahead_nth(i).kind; | 90 | let token = self.token_source.lookahead_nth(i); |
91 | if let Some((composited, step)) = self.is_composite(kind, i) { | 91 | let mut kind = token.kind; |
92 | if let Some((composited, step)) = self.is_composite(token, i) { | ||
92 | kind = composited; | 93 | kind = composited; |
93 | i += step; | 94 | i += step; |
94 | } else { | 95 | } else { |
@@ -250,32 +251,47 @@ impl<'t> Parser<'t> { | |||
250 | } | 251 | } |
251 | 252 | ||
252 | /// helper function for check if it is composite. | 253 | /// helper function for check if it is composite. |
253 | fn is_composite(&self, kind: SyntaxKind, n: usize) -> Option<(SyntaxKind, usize)> { | 254 | fn is_composite(&self, first: Token, n: usize) -> Option<(SyntaxKind, usize)> { |
254 | // We assume the dollars will not occuried between | 255 | // We assume the dollars will not occuried between |
255 | // mult-byte tokens | 256 | // mult-byte tokens |
256 | 257 | ||
257 | let first = self.token_source.lookahead_nth(n); | 258 | let jn1 = first.is_jointed_to_next; |
259 | if !jn1 && first.kind != T![-] { | ||
260 | return None; | ||
261 | } | ||
262 | |||
258 | let second = self.token_source.lookahead_nth(n + 1); | 263 | let second = self.token_source.lookahead_nth(n + 1); |
264 | if first.kind == T![-] && second.kind == T![>] { | ||
265 | return Some((T![->], 2)); | ||
266 | } | ||
267 | if !jn1 { | ||
268 | return None; | ||
269 | } | ||
270 | |||
271 | match (first.kind, second.kind) { | ||
272 | (T![:], T![:]) => return Some((T![::], 2)), | ||
273 | (T![=], T![=]) => return Some((T![==], 2)), | ||
274 | (T![=], T![>]) => return Some((T![=>], 2)), | ||
275 | (T![!], T![=]) => return Some((T![!=], 2)), | ||
276 | _ => {} | ||
277 | } | ||
278 | |||
279 | if first.kind != T![.] || second.kind != T![.] { | ||
280 | return None; | ||
281 | } | ||
282 | |||
259 | let third = self.token_source.lookahead_nth(n + 2); | 283 | let third = self.token_source.lookahead_nth(n + 2); |
260 | 284 | ||
261 | let jn1 = first.is_jointed_to_next; | ||
262 | let la2 = second.kind; | ||
263 | let jn2 = second.is_jointed_to_next; | 285 | let jn2 = second.is_jointed_to_next; |
264 | let la3 = third.kind; | 286 | let la3 = third.kind; |
265 | 287 | ||
266 | match kind { | 288 | if jn2 && la3 == T![.] { |
267 | T![.] if jn1 && la2 == T![.] && jn2 && la3 == T![.] => Some((T![...], 3)), | 289 | return Some((T![...], 3)); |
268 | T![.] if jn1 && la2 == T![.] && la3 == T![=] => Some((T![..=], 3)), | 290 | } |
269 | T![.] if jn1 && la2 == T![.] => Some((T![..], 2)), | 291 | if la3 == T![=] { |
270 | 292 | return Some((T![..=], 3)); | |
271 | T![:] if jn1 && la2 == T![:] => Some((T![::], 2)), | ||
272 | T![=] if jn1 && la2 == T![=] => Some((T![==], 2)), | ||
273 | T![=] if jn1 && la2 == T![>] => Some((T![=>], 2)), | ||
274 | |||
275 | T![!] if jn1 && la2 == T![=] => Some((T![!=], 2)), | ||
276 | T![-] if la2 == T![>] => Some((T![->], 2)), | ||
277 | _ => None, | ||
278 | } | 293 | } |
294 | return Some((T![..], 2)); | ||
279 | } | 295 | } |
280 | 296 | ||
281 | fn eat_dollars(&mut self) { | 297 | fn eat_dollars(&mut self) { |
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml index 3545d23c9..4fd6c75ef 100644 --- a/crates/ra_project_model/Cargo.toml +++ b/crates/ra_project_model/Cargo.toml | |||
@@ -7,7 +7,6 @@ authors = ["rust-analyzer developers"] | |||
7 | [dependencies] | 7 | [dependencies] |
8 | log = "0.4.5" | 8 | log = "0.4.5" |
9 | rustc-hash = "1.0" | 9 | rustc-hash = "1.0" |
10 | relative-path = "0.4.0" | ||
11 | 10 | ||
12 | cargo_metadata = "0.8.0" | 11 | cargo_metadata = "0.8.0" |
13 | 12 | ||
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 2b06e9e37..712d8818f 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs | |||
@@ -167,7 +167,7 @@ impl CargoWorkspace { | |||
167 | Ok(CargoWorkspace { packages, targets, workspace_root: meta.workspace_root }) | 167 | Ok(CargoWorkspace { packages, targets, workspace_root: meta.workspace_root }) |
168 | } | 168 | } |
169 | 169 | ||
170 | pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + 'a { | 170 | pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a { |
171 | self.packages.iter().map(|(id, _pkg)| id) | 171 | self.packages.iter().map(|(id, _pkg)| id) |
172 | } | 172 | } |
173 | 173 | ||
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 08e5c1c32..55b94b911 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs | |||
@@ -9,14 +9,10 @@ use std::{ | |||
9 | path::{Path, PathBuf}, | 9 | path::{Path, PathBuf}, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use rustc_hash::FxHashMap; | ||
13 | |||
14 | use ra_db::{CrateGraph, Edition, FileId}; | 12 | use ra_db::{CrateGraph, Edition, FileId}; |
15 | 13 | use rustc_hash::FxHashMap; | |
16 | use serde_json::from_reader; | 14 | use serde_json::from_reader; |
17 | 15 | ||
18 | use relative_path::RelativePath; | ||
19 | |||
20 | pub use crate::{ | 16 | pub use crate::{ |
21 | cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, | 17 | cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, |
22 | json_project::JsonProject, | 18 | json_project::JsonProject, |
@@ -34,20 +30,20 @@ pub enum ProjectWorkspace { | |||
34 | Json { project: JsonProject }, | 30 | Json { project: JsonProject }, |
35 | } | 31 | } |
36 | 32 | ||
37 | /// `ProjectRoot` describes a workspace root folder. | 33 | /// `PackageRoot` describes a package root folder. |
38 | /// Which may be an external dependency, or a member of | 34 | /// Which may be an external dependency, or a member of |
39 | /// the current workspace. | 35 | /// the current workspace. |
40 | #[derive(Clone)] | 36 | #[derive(Clone)] |
41 | pub struct ProjectRoot { | 37 | pub struct PackageRoot { |
42 | /// Path to the root folder | 38 | /// Path to the root folder |
43 | path: PathBuf, | 39 | path: PathBuf, |
44 | /// Is a member of the current workspace | 40 | /// Is a member of the current workspace |
45 | is_member: bool, | 41 | is_member: bool, |
46 | } | 42 | } |
47 | 43 | ||
48 | impl ProjectRoot { | 44 | impl PackageRoot { |
49 | pub fn new(path: PathBuf, is_member: bool) -> ProjectRoot { | 45 | pub fn new(path: PathBuf, is_member: bool) -> PackageRoot { |
50 | ProjectRoot { path, is_member } | 46 | PackageRoot { path, is_member } |
51 | } | 47 | } |
52 | 48 | ||
53 | pub fn path(&self) -> &PathBuf { | 49 | pub fn path(&self) -> &PathBuf { |
@@ -57,28 +53,6 @@ impl ProjectRoot { | |||
57 | pub fn is_member(&self) -> bool { | 53 | pub fn is_member(&self) -> bool { |
58 | self.is_member | 54 | self.is_member |
59 | } | 55 | } |
60 | |||
61 | pub fn include_dir(&self, dir_path: &RelativePath) -> bool { | ||
62 | const COMMON_IGNORED_DIRS: &[&str] = &["node_modules", "target", ".git"]; | ||
63 | const EXTERNAL_IGNORED_DIRS: &[&str] = &["examples", "tests", "benches"]; | ||
64 | |||
65 | let is_ignored = if self.is_member { | ||
66 | dir_path.components().any(|c| COMMON_IGNORED_DIRS.contains(&c.as_str())) | ||
67 | } else { | ||
68 | dir_path.components().any(|c| { | ||
69 | let path = c.as_str(); | ||
70 | COMMON_IGNORED_DIRS.contains(&path) || EXTERNAL_IGNORED_DIRS.contains(&path) | ||
71 | }) | ||
72 | }; | ||
73 | |||
74 | let hidden = dir_path.components().any(|c| c.as_str().starts_with('.')); | ||
75 | |||
76 | !is_ignored && !hidden | ||
77 | } | ||
78 | |||
79 | pub fn include_file(&self, file_path: &RelativePath) -> bool { | ||
80 | file_path.extension() == Some("rs") | ||
81 | } | ||
82 | } | 56 | } |
83 | 57 | ||
84 | impl ProjectWorkspace { | 58 | impl ProjectWorkspace { |
@@ -99,38 +73,39 @@ impl ProjectWorkspace { | |||
99 | } | 73 | } |
100 | } | 74 | } |
101 | 75 | ||
102 | /// Returns the roots for the current ProjectWorkspace | 76 | /// Returns the roots for the current `ProjectWorkspace` |
103 | /// The return type contains the path and whether or not | 77 | /// The return type contains the path and whether or not |
104 | /// the root is a member of the current workspace | 78 | /// the root is a member of the current workspace |
105 | pub fn to_roots(&self) -> Vec<ProjectRoot> { | 79 | pub fn to_roots(&self) -> Vec<PackageRoot> { |
106 | match self { | 80 | match self { |
107 | ProjectWorkspace::Json { project } => { | 81 | ProjectWorkspace::Json { project } => { |
108 | let mut roots = Vec::with_capacity(project.roots.len()); | 82 | let mut roots = Vec::with_capacity(project.roots.len()); |
109 | for root in &project.roots { | 83 | for root in &project.roots { |
110 | roots.push(ProjectRoot::new(root.path.clone(), true)); | 84 | roots.push(PackageRoot::new(root.path.clone(), true)); |
111 | } | 85 | } |
112 | roots | 86 | roots |
113 | } | 87 | } |
114 | ProjectWorkspace::Cargo { cargo, sysroot } => { | 88 | ProjectWorkspace::Cargo { cargo, sysroot } => { |
115 | let mut roots = | 89 | let mut roots = Vec::with_capacity(cargo.packages().len() + sysroot.crates().len()); |
116 | Vec::with_capacity(cargo.packages().count() + sysroot.crates().count()); | ||
117 | for pkg in cargo.packages() { | 90 | for pkg in cargo.packages() { |
118 | let root = pkg.root(&cargo).to_path_buf(); | 91 | let root = pkg.root(&cargo).to_path_buf(); |
119 | let member = pkg.is_member(&cargo); | 92 | let member = pkg.is_member(&cargo); |
120 | roots.push(ProjectRoot::new(root, member)); | 93 | roots.push(PackageRoot::new(root, member)); |
121 | } | 94 | } |
122 | for krate in sysroot.crates() { | 95 | for krate in sysroot.crates() { |
123 | roots.push(ProjectRoot::new(krate.root_dir(&sysroot).to_path_buf(), false)) | 96 | roots.push(PackageRoot::new(krate.root_dir(&sysroot).to_path_buf(), false)) |
124 | } | 97 | } |
125 | roots | 98 | roots |
126 | } | 99 | } |
127 | } | 100 | } |
128 | } | 101 | } |
129 | 102 | ||
130 | pub fn count(&self) -> usize { | 103 | pub fn n_packages(&self) -> usize { |
131 | match self { | 104 | match self { |
132 | ProjectWorkspace::Json { project } => project.crates.len(), | 105 | ProjectWorkspace::Json { project } => project.crates.len(), |
133 | ProjectWorkspace::Cargo { cargo, .. } => cargo.packages().count(), | 106 | ProjectWorkspace::Cargo { cargo, sysroot } => { |
107 | cargo.packages().len() + sysroot.crates().len() | ||
108 | } | ||
134 | } | 109 | } |
135 | } | 110 | } |
136 | 111 | ||
diff --git a/crates/ra_project_model/src/sysroot.rs b/crates/ra_project_model/src/sysroot.rs index 4f6e880dd..3f34d51cc 100644 --- a/crates/ra_project_model/src/sysroot.rs +++ b/crates/ra_project_model/src/sysroot.rs | |||
@@ -28,7 +28,7 @@ impl Sysroot { | |||
28 | self.by_name("std") | 28 | self.by_name("std") |
29 | } | 29 | } |
30 | 30 | ||
31 | pub fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + 'a { | 31 | pub fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + 'a { |
32 | self.crates.iter().map(|(id, _data)| id) | 32 | self.crates.iter().map(|(id, _data)| id) |
33 | } | 33 | } |
34 | 34 | ||
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml index bc1c88070..5f8585878 100644 --- a/crates/ra_syntax/Cargo.toml +++ b/crates/ra_syntax/Cargo.toml | |||
@@ -8,7 +8,6 @@ description = "Comment and whitespace preserving parser for the Rust langauge" | |||
8 | repository = "https://github.com/rust-analyzer/rust-analyzer" | 8 | repository = "https://github.com/rust-analyzer/rust-analyzer" |
9 | 9 | ||
10 | [dependencies] | 10 | [dependencies] |
11 | unicode-xid = "0.1.0" | ||
12 | itertools = "0.8.0" | 11 | itertools = "0.8.0" |
13 | rowan = "0.6.1" | 12 | rowan = "0.6.1" |
14 | ra_rustc_lexer = { version = "0.1.0-pre.2" } | 13 | ra_rustc_lexer = { version = "0.1.0-pre.2" } |
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index c5746d98d..6f0489617 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -139,6 +139,52 @@ fn test_doc_comment_preserves_newlines() { | |||
139 | } | 139 | } |
140 | 140 | ||
141 | #[test] | 141 | #[test] |
142 | fn test_doc_comment_single_line_block_strips_suffix() { | ||
143 | let file = SourceFile::parse( | ||
144 | r#" | ||
145 | /** this is mod foo*/ | ||
146 | mod foo {} | ||
147 | "#, | ||
148 | ) | ||
149 | .ok() | ||
150 | .unwrap(); | ||
151 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); | ||
152 | assert_eq!("this is mod foo", module.doc_comment_text().unwrap()); | ||
153 | } | ||
154 | |||
155 | #[test] | ||
156 | fn test_doc_comment_single_line_block_strips_suffix_whitespace() { | ||
157 | let file = SourceFile::parse( | ||
158 | r#" | ||
159 | /** this is mod foo */ | ||
160 | mod foo {} | ||
161 | "#, | ||
162 | ) | ||
163 | .ok() | ||
164 | .unwrap(); | ||
165 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); | ||
166 | assert_eq!("this is mod foo", module.doc_comment_text().unwrap()); | ||
167 | } | ||
168 | |||
169 | #[test] | ||
170 | fn test_doc_comment_multi_line_block_strips_suffix() { | ||
171 | let file = SourceFile::parse( | ||
172 | r#" | ||
173 | /** | ||
174 | this | ||
175 | is | ||
176 | mod foo | ||
177 | */ | ||
178 | mod foo {} | ||
179 | "#, | ||
180 | ) | ||
181 | .ok() | ||
182 | .unwrap(); | ||
183 | let module = file.syntax().descendants().find_map(Module::cast).unwrap(); | ||
184 | assert_eq!(" this\n is\n mod foo", module.doc_comment_text().unwrap()); | ||
185 | } | ||
186 | |||
187 | #[test] | ||
142 | fn test_where_predicates() { | 188 | fn test_where_predicates() { |
143 | fn assert_bound(text: &str, bound: Option<TypeBound>) { | 189 | fn assert_bound(text: &str, bound: Option<TypeBound>) { |
144 | assert_eq!(text, bound.unwrap().syntax().text().to_string()); | 190 | assert_eq!(text, bound.unwrap().syntax().text().to_string()); |
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index d4873b39a..2a59cf653 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -91,6 +91,7 @@ impl ast::Attr { | |||
91 | #[derive(Debug, Clone, PartialEq, Eq)] | 91 | #[derive(Debug, Clone, PartialEq, Eq)] |
92 | pub enum PathSegmentKind { | 92 | pub enum PathSegmentKind { |
93 | Name(ast::NameRef), | 93 | Name(ast::NameRef), |
94 | Type { type_ref: Option<ast::TypeRef>, trait_ref: Option<ast::PathType> }, | ||
94 | SelfKw, | 95 | SelfKw, |
95 | SuperKw, | 96 | SuperKw, |
96 | CrateKw, | 97 | CrateKw, |
@@ -112,6 +113,15 @@ impl ast::PathSegment { | |||
112 | T![self] => PathSegmentKind::SelfKw, | 113 | T![self] => PathSegmentKind::SelfKw, |
113 | T![super] => PathSegmentKind::SuperKw, | 114 | T![super] => PathSegmentKind::SuperKw, |
114 | T![crate] => PathSegmentKind::CrateKw, | 115 | T![crate] => PathSegmentKind::CrateKw, |
116 | T![<] => { | ||
117 | // <T> or <T as Trait> | ||
118 | // T is any TypeRef, Trait has to be a PathType | ||
119 | let mut type_refs = | ||
120 | self.syntax().children().filter(|node| ast::TypeRef::can_cast(node.kind())); | ||
121 | let type_ref = type_refs.next().and_then(ast::TypeRef::cast); | ||
122 | let trait_ref = type_refs.next().and_then(ast::PathType::cast); | ||
123 | PathSegmentKind::Type { type_ref, trait_ref } | ||
124 | } | ||
115 | _ => return None, | 125 | _ => return None, |
116 | } | 126 | } |
117 | }; | 127 | }; |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index da8cf4ae8..f322e1d84 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -2013,6 +2013,7 @@ impl AstNode for Param { | |||
2013 | 2013 | ||
2014 | 2014 | ||
2015 | impl ast::TypeAscriptionOwner for Param {} | 2015 | impl ast::TypeAscriptionOwner for Param {} |
2016 | impl ast::AttrsOwner for Param {} | ||
2016 | impl Param { | 2017 | impl Param { |
2017 | pub fn pat(&self) -> Option<Pat> { | 2018 | pub fn pat(&self) -> Option<Pat> { |
2018 | super::child_opt(self) | 2019 | super::child_opt(self) |
@@ -2667,6 +2668,7 @@ impl AstNode for SelfParam { | |||
2667 | 2668 | ||
2668 | 2669 | ||
2669 | impl ast::TypeAscriptionOwner for SelfParam {} | 2670 | impl ast::TypeAscriptionOwner for SelfParam {} |
2671 | impl ast::AttrsOwner for SelfParam {} | ||
2670 | impl SelfParam {} | 2672 | impl SelfParam {} |
2671 | 2673 | ||
2672 | // SlicePat | 2674 | // SlicePat |
diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs index 6ed1b5213..1b9a2b20c 100644 --- a/crates/ra_syntax/src/ast/traits.rs +++ b/crates/ra_syntax/src/ast/traits.rs | |||
@@ -115,8 +115,8 @@ pub trait DocCommentsOwner: AstNode { | |||
115 | } | 115 | } |
116 | 116 | ||
117 | /// Returns the textual content of a doc comment block as a single string. | 117 | /// Returns the textual content of a doc comment block as a single string. |
118 | /// That is, strips leading `///` (+ optional 1 character of whitespace) | 118 | /// That is, strips leading `///` (+ optional 1 character of whitespace), |
119 | /// and joins lines. | 119 | /// trailing `*/`, trailing whitespace and then joins the lines. |
120 | fn doc_comment_text(&self) -> Option<String> { | 120 | fn doc_comment_text(&self) -> Option<String> { |
121 | let mut has_comments = false; | 121 | let mut has_comments = false; |
122 | let docs = self | 122 | let docs = self |
@@ -136,7 +136,13 @@ pub trait DocCommentsOwner: AstNode { | |||
136 | prefix_len | 136 | prefix_len |
137 | }; | 137 | }; |
138 | 138 | ||
139 | line[pos..].to_owned() | 139 | let end = if comment.kind().shape.is_block() && line.ends_with("*/") { |
140 | line.len() - 2 | ||
141 | } else { | ||
142 | line.len() | ||
143 | }; | ||
144 | |||
145 | line[pos..end].trim_end().to_owned() | ||
140 | }) | 146 | }) |
141 | .join("\n"); | 147 | .join("\n"); |
142 | 148 | ||
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 817dedfbf..f2c20573e 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -642,12 +642,14 @@ Grammar( | |||
642 | "SelfParam": ( | 642 | "SelfParam": ( |
643 | traits: [ | 643 | traits: [ |
644 | "TypeAscriptionOwner", | 644 | "TypeAscriptionOwner", |
645 | "AttrsOwner", | ||
645 | ] | 646 | ] |
646 | ), | 647 | ), |
647 | "Param": ( | 648 | "Param": ( |
648 | options: [ "Pat" ], | 649 | options: [ "Pat" ], |
649 | traits: [ | 650 | traits: [ |
650 | "TypeAscriptionOwner", | 651 | "TypeAscriptionOwner", |
652 | "AttrsOwner", | ||
651 | ] | 653 | ] |
652 | ), | 654 | ), |
653 | "UseItem": ( | 655 | "UseItem": ( |
diff --git a/crates/ra_syntax/src/parsing/lexer.rs b/crates/ra_syntax/src/parsing/lexer.rs index 2a4343b0a..06822ea91 100644 --- a/crates/ra_syntax/src/parsing/lexer.rs +++ b/crates/ra_syntax/src/parsing/lexer.rs | |||
@@ -12,6 +12,19 @@ pub struct Token { | |||
12 | pub len: TextUnit, | 12 | pub len: TextUnit, |
13 | } | 13 | } |
14 | 14 | ||
15 | fn match_literal_kind(kind: ra_rustc_lexer::LiteralKind) -> SyntaxKind { | ||
16 | match kind { | ||
17 | ra_rustc_lexer::LiteralKind::Int { .. } => INT_NUMBER, | ||
18 | ra_rustc_lexer::LiteralKind::Float { .. } => FLOAT_NUMBER, | ||
19 | ra_rustc_lexer::LiteralKind::Char { .. } => CHAR, | ||
20 | ra_rustc_lexer::LiteralKind::Byte { .. } => BYTE, | ||
21 | ra_rustc_lexer::LiteralKind::Str { .. } => STRING, | ||
22 | ra_rustc_lexer::LiteralKind::ByteStr { .. } => BYTE_STRING, | ||
23 | ra_rustc_lexer::LiteralKind::RawStr { .. } => RAW_STRING, | ||
24 | ra_rustc_lexer::LiteralKind::RawByteStr { .. } => RAW_BYTE_STRING, | ||
25 | } | ||
26 | } | ||
27 | |||
15 | /// Break a string up into its component tokens | 28 | /// Break a string up into its component tokens |
16 | pub fn tokenize(text: &str) -> Vec<Token> { | 29 | pub fn tokenize(text: &str) -> Vec<Token> { |
17 | if text.is_empty() { | 30 | if text.is_empty() { |
@@ -53,16 +66,7 @@ pub fn tokenize(text: &str) -> Vec<Token> { | |||
53 | } | 66 | } |
54 | } | 67 | } |
55 | ra_rustc_lexer::TokenKind::RawIdent => IDENT, | 68 | ra_rustc_lexer::TokenKind::RawIdent => IDENT, |
56 | ra_rustc_lexer::TokenKind::Literal { kind, .. } => match kind { | 69 | ra_rustc_lexer::TokenKind::Literal { kind, .. } => match_literal_kind(kind), |
57 | ra_rustc_lexer::LiteralKind::Int { .. } => INT_NUMBER, | ||
58 | ra_rustc_lexer::LiteralKind::Float { .. } => FLOAT_NUMBER, | ||
59 | ra_rustc_lexer::LiteralKind::Char { .. } => CHAR, | ||
60 | ra_rustc_lexer::LiteralKind::Byte { .. } => BYTE, | ||
61 | ra_rustc_lexer::LiteralKind::Str { .. } => STRING, | ||
62 | ra_rustc_lexer::LiteralKind::ByteStr { .. } => BYTE_STRING, | ||
63 | ra_rustc_lexer::LiteralKind::RawStr { .. } => RAW_STRING, | ||
64 | ra_rustc_lexer::LiteralKind::RawByteStr { .. } => RAW_BYTE_STRING, | ||
65 | }, | ||
66 | ra_rustc_lexer::TokenKind::Lifetime { .. } => LIFETIME, | 70 | ra_rustc_lexer::TokenKind::Lifetime { .. } => LIFETIME, |
67 | ra_rustc_lexer::TokenKind::Semi => SEMI, | 71 | ra_rustc_lexer::TokenKind::Semi => SEMI, |
68 | ra_rustc_lexer::TokenKind::Comma => COMMA, | 72 | ra_rustc_lexer::TokenKind::Comma => COMMA, |
@@ -131,16 +135,7 @@ pub fn classify_literal(text: &str) -> Option<Token> { | |||
131 | return None; | 135 | return None; |
132 | } | 136 | } |
133 | let kind = match t.kind { | 137 | let kind = match t.kind { |
134 | ra_rustc_lexer::TokenKind::Literal { kind, .. } => match kind { | 138 | ra_rustc_lexer::TokenKind::Literal { kind, .. } => match_literal_kind(kind), |
135 | ra_rustc_lexer::LiteralKind::Int { .. } => INT_NUMBER, | ||
136 | ra_rustc_lexer::LiteralKind::Float { .. } => FLOAT_NUMBER, | ||
137 | ra_rustc_lexer::LiteralKind::Char { .. } => CHAR, | ||
138 | ra_rustc_lexer::LiteralKind::Byte { .. } => BYTE, | ||
139 | ra_rustc_lexer::LiteralKind::Str { .. } => STRING, | ||
140 | ra_rustc_lexer::LiteralKind::ByteStr { .. } => BYTE_STRING, | ||
141 | ra_rustc_lexer::LiteralKind::RawStr { .. } => RAW_STRING, | ||
142 | ra_rustc_lexer::LiteralKind::RawByteStr { .. } => RAW_BYTE_STRING, | ||
143 | }, | ||
144 | _ => return None, | 139 | _ => return None, |
145 | }; | 140 | }; |
146 | Some(Token { kind, len: TextUnit::from_usize(t.len) }) | 141 | Some(Token { kind, len: TextUnit::from_usize(t.len) }) |
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index 1f904434e..2bb3c0a03 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs | |||
@@ -1,13 +1,12 @@ | |||
1 | mod block; | 1 | mod block; |
2 | mod field_expr; | ||
3 | 2 | ||
4 | use ra_rustc_lexer::unescape; | 3 | use ra_rustc_lexer::unescape; |
5 | 4 | ||
6 | use crate::{ | 5 | use crate::{ |
7 | algo::visit::{visitor_ctx, VisitorCtx}, | 6 | algo::visit::{visitor_ctx, VisitorCtx}, |
8 | ast, SyntaxError, SyntaxErrorKind, | 7 | ast, AstNode, SyntaxError, SyntaxErrorKind, |
9 | SyntaxKind::{BYTE, BYTE_STRING, CHAR, STRING}, | 8 | SyntaxKind::{BYTE, BYTE_STRING, CHAR, INT_NUMBER, STRING}, |
10 | SyntaxNode, TextUnit, T, | 9 | SyntaxNode, SyntaxToken, TextUnit, T, |
11 | }; | 10 | }; |
12 | 11 | ||
13 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] | 12 | #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
@@ -101,7 +100,8 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { | |||
101 | let _ = visitor_ctx(&mut errors) | 100 | let _ = visitor_ctx(&mut errors) |
102 | .visit::<ast::Literal, _>(validate_literal) | 101 | .visit::<ast::Literal, _>(validate_literal) |
103 | .visit::<ast::Block, _>(block::validate_block_node) | 102 | .visit::<ast::Block, _>(block::validate_block_node) |
104 | .visit::<ast::FieldExpr, _>(field_expr::validate_field_expr_node) | 103 | .visit::<ast::FieldExpr, _>(|it, errors| validate_numeric_name(it.name_ref(), errors)) |
104 | .visit::<ast::NamedField, _>(|it, errors| validate_numeric_name(it.name_ref(), errors)) | ||
105 | .accept(&node); | 105 | .accept(&node); |
106 | } | 106 | } |
107 | errors | 107 | errors |
@@ -189,3 +189,18 @@ pub(crate) fn validate_block_structure(root: &SyntaxNode) { | |||
189 | } | 189 | } |
190 | } | 190 | } |
191 | } | 191 | } |
192 | |||
193 | fn validate_numeric_name(name_ref: Option<ast::NameRef>, errors: &mut Vec<SyntaxError>) { | ||
194 | if let Some(int_token) = int_token(name_ref) { | ||
195 | if int_token.text().chars().any(|c| !c.is_digit(10)) { | ||
196 | errors.push(SyntaxError::new( | ||
197 | SyntaxErrorKind::InvalidTupleIndexFormat, | ||
198 | int_token.text_range(), | ||
199 | )); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | fn int_token(name_ref: Option<ast::NameRef>) -> Option<SyntaxToken> { | ||
204 | name_ref?.syntax().first_child_or_token()?.into_token().filter(|it| it.kind() == INT_NUMBER) | ||
205 | } | ||
206 | } | ||
diff --git a/crates/ra_syntax/src/validation/field_expr.rs b/crates/ra_syntax/src/validation/field_expr.rs deleted file mode 100644 index 004f199fd..000000000 --- a/crates/ra_syntax/src/validation/field_expr.rs +++ /dev/null | |||
@@ -1,13 +0,0 @@ | |||
1 | use crate::{ | ||
2 | ast::{self, FieldKind}, | ||
3 | SyntaxError, | ||
4 | SyntaxErrorKind::*, | ||
5 | }; | ||
6 | |||
7 | pub(crate) fn validate_field_expr_node(node: ast::FieldExpr, errors: &mut Vec<SyntaxError>) { | ||
8 | if let Some(FieldKind::Index(idx)) = node.field_access() { | ||
9 | if idx.text().chars().any(|c| c < '0' || c > '9') { | ||
10 | errors.push(SyntaxError::new(InvalidTupleIndexFormat, idx.text_range())); | ||
11 | } | ||
12 | } | ||
13 | } | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.txt b/crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.txt index a21b29c80..465e79e7b 100644 --- a/crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.txt +++ b/crates/ra_syntax/test_data/parser/inline/err/0010_bad_tuple_index_expr.txt | |||
@@ -30,7 +30,8 @@ SOURCE_FILE@[0; 47) | |||
30 | NAME_REF@[25; 26) | 30 | NAME_REF@[25; 26) |
31 | IDENT@[25; 26) "x" | 31 | IDENT@[25; 26) "x" |
32 | DOT@[26; 27) "." | 32 | DOT@[26; 27) "." |
33 | INT_NUMBER@[27; 31) "1i32" | 33 | NAME_REF@[27; 31) |
34 | INT_NUMBER@[27; 31) "1i32" | ||
34 | SEMI@[31; 32) ";" | 35 | SEMI@[31; 32) ";" |
35 | WHITESPACE@[32; 37) "\n " | 36 | WHITESPACE@[32; 37) "\n " |
36 | EXPR_STMT@[37; 44) | 37 | EXPR_STMT@[37; 44) |
@@ -41,11 +42,11 @@ SOURCE_FILE@[0; 47) | |||
41 | NAME_REF@[37; 38) | 42 | NAME_REF@[37; 38) |
42 | IDENT@[37; 38) "x" | 43 | IDENT@[37; 38) "x" |
43 | DOT@[38; 39) "." | 44 | DOT@[38; 39) "." |
44 | INT_NUMBER@[39; 43) "0x01" | 45 | NAME_REF@[39; 43) |
46 | INT_NUMBER@[39; 43) "0x01" | ||
45 | SEMI@[43; 44) ";" | 47 | SEMI@[43; 44) ";" |
46 | WHITESPACE@[44; 45) "\n" | 48 | WHITESPACE@[44; 45) "\n" |
47 | R_CURLY@[45; 46) "}" | 49 | R_CURLY@[45; 46) "}" |
48 | WHITESPACE@[46; 47) "\n" | 50 | WHITESPACE@[46; 47) "\n" |
49 | error [17; 19): Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix | ||
50 | error [27; 31): Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix | 51 | error [27; 31): Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix |
51 | error [39; 43): Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix | 52 | error [39; 43): Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix |
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.txt b/crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.txt index 78054ec5a..1d2cf2761 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.txt +++ b/crates/ra_syntax/test_data/parser/inline/ok/0011_field_expr.txt | |||
@@ -32,7 +32,8 @@ SOURCE_FILE@[0; 48) | |||
32 | NAME_REF@[26; 27) | 32 | NAME_REF@[26; 27) |
33 | IDENT@[26; 27) "x" | 33 | IDENT@[26; 27) "x" |
34 | DOT@[27; 28) "." | 34 | DOT@[27; 28) "." |
35 | INT_NUMBER@[28; 29) "0" | 35 | NAME_REF@[28; 29) |
36 | INT_NUMBER@[28; 29) "0" | ||
36 | DOT@[29; 30) "." | 37 | DOT@[29; 30) "." |
37 | NAME_REF@[30; 33) | 38 | NAME_REF@[30; 33) |
38 | IDENT@[30; 33) "bar" | 39 | IDENT@[30; 33) "bar" |
@@ -47,7 +48,8 @@ SOURCE_FILE@[0; 48) | |||
47 | NAME_REF@[39; 40) | 48 | NAME_REF@[39; 40) |
48 | IDENT@[39; 40) "x" | 49 | IDENT@[39; 40) "x" |
49 | DOT@[40; 41) "." | 50 | DOT@[40; 41) "." |
50 | INT_NUMBER@[41; 42) "0" | 51 | NAME_REF@[41; 42) |
52 | INT_NUMBER@[41; 42) "0" | ||
51 | ARG_LIST@[42; 44) | 53 | ARG_LIST@[42; 44) |
52 | L_PAREN@[42; 43) "(" | 54 | L_PAREN@[42; 43) "(" |
53 | R_PAREN@[43; 44) ")" | 55 | R_PAREN@[43; 44) ")" |
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0061_struct_lit.rs b/crates/ra_syntax/test_data/parser/inline/ok/0061_struct_lit.rs index eb711f68a..6285e5549 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0061_struct_lit.rs +++ b/crates/ra_syntax/test_data/parser/inline/ok/0061_struct_lit.rs | |||
@@ -2,4 +2,5 @@ fn foo() { | |||
2 | S {}; | 2 | S {}; |
3 | S { x, y: 32, }; | 3 | S { x, y: 32, }; |
4 | S { x, y: 32, ..Default::default() }; | 4 | S { x, y: 32, ..Default::default() }; |
5 | TupleStruct { 0: 1 }; | ||
5 | } | 6 | } |
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0061_struct_lit.txt b/crates/ra_syntax/test_data/parser/inline/ok/0061_struct_lit.txt index 94d1bfe2e..d06594cae 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0061_struct_lit.txt +++ b/crates/ra_syntax/test_data/parser/inline/ok/0061_struct_lit.txt | |||
@@ -1,5 +1,5 @@ | |||
1 | SOURCE_FILE@[0; 86) | 1 | SOURCE_FILE@[0; 112) |
2 | FN_DEF@[0; 85) | 2 | FN_DEF@[0; 111) |
3 | FN_KW@[0; 2) "fn" | 3 | FN_KW@[0; 2) "fn" |
4 | WHITESPACE@[2; 3) " " | 4 | WHITESPACE@[2; 3) " " |
5 | NAME@[3; 6) | 5 | NAME@[3; 6) |
@@ -8,7 +8,7 @@ SOURCE_FILE@[0; 86) | |||
8 | L_PAREN@[6; 7) "(" | 8 | L_PAREN@[6; 7) "(" |
9 | R_PAREN@[7; 8) ")" | 9 | R_PAREN@[7; 8) ")" |
10 | WHITESPACE@[8; 9) " " | 10 | WHITESPACE@[8; 9) " " |
11 | BLOCK@[9; 85) | 11 | BLOCK@[9; 111) |
12 | L_CURLY@[9; 10) "{" | 12 | L_CURLY@[9; 10) "{" |
13 | WHITESPACE@[10; 15) "\n " | 13 | WHITESPACE@[10; 15) "\n " |
14 | EXPR_STMT@[15; 20) | 14 | EXPR_STMT@[15; 20) |
@@ -92,6 +92,27 @@ SOURCE_FILE@[0; 86) | |||
92 | WHITESPACE@[80; 81) " " | 92 | WHITESPACE@[80; 81) " " |
93 | R_CURLY@[81; 82) "}" | 93 | R_CURLY@[81; 82) "}" |
94 | SEMI@[82; 83) ";" | 94 | SEMI@[82; 83) ";" |
95 | WHITESPACE@[83; 84) "\n" | 95 | WHITESPACE@[83; 88) "\n " |
96 | R_CURLY@[84; 85) "}" | 96 | EXPR_STMT@[88; 109) |
97 | WHITESPACE@[85; 86) "\n" | 97 | STRUCT_LIT@[88; 108) |
98 | PATH@[88; 99) | ||
99 | PATH_SEGMENT@[88; 99) | ||
100 | NAME_REF@[88; 99) | ||
101 | IDENT@[88; 99) "TupleStruct" | ||
102 | WHITESPACE@[99; 100) " " | ||
103 | NAMED_FIELD_LIST@[100; 108) | ||
104 | L_CURLY@[100; 101) "{" | ||
105 | WHITESPACE@[101; 102) " " | ||
106 | NAMED_FIELD@[102; 106) | ||
107 | NAME_REF@[102; 103) | ||
108 | INT_NUMBER@[102; 103) "0" | ||
109 | COLON@[103; 104) ":" | ||
110 | WHITESPACE@[104; 105) " " | ||
111 | LITERAL@[105; 106) | ||
112 | INT_NUMBER@[105; 106) "1" | ||
113 | WHITESPACE@[106; 107) " " | ||
114 | R_CURLY@[107; 108) "}" | ||
115 | SEMI@[108; 109) ";" | ||
116 | WHITESPACE@[109; 110) "\n" | ||
117 | R_CURLY@[110; 111) "}" | ||
118 | WHITESPACE@[111; 112) "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.txt b/crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.txt index 99bd76ace..7adb662de 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.txt +++ b/crates/ra_syntax/test_data/parser/inline/ok/0137_await_expr.txt | |||
@@ -31,7 +31,8 @@ SOURCE_FILE@[0; 67) | |||
31 | NAME_REF@[28; 29) | 31 | NAME_REF@[28; 29) |
32 | IDENT@[28; 29) "x" | 32 | IDENT@[28; 29) "x" |
33 | DOT@[29; 30) "." | 33 | DOT@[29; 30) "." |
34 | INT_NUMBER@[30; 31) "0" | 34 | NAME_REF@[30; 31) |
35 | INT_NUMBER@[30; 31) "0" | ||
35 | DOT@[31; 32) "." | 36 | DOT@[31; 32) "." |
36 | AWAIT_KW@[32; 37) "await" | 37 | AWAIT_KW@[32; 37) "await" |
37 | SEMI@[37; 38) ";" | 38 | SEMI@[37; 38) ";" |
@@ -48,7 +49,8 @@ SOURCE_FILE@[0; 67) | |||
48 | NAME_REF@[43; 44) | 49 | NAME_REF@[43; 44) |
49 | IDENT@[43; 44) "x" | 50 | IDENT@[43; 44) "x" |
50 | DOT@[44; 45) "." | 51 | DOT@[44; 45) "." |
51 | INT_NUMBER@[45; 46) "0" | 52 | NAME_REF@[45; 46) |
53 | INT_NUMBER@[45; 46) "0" | ||
52 | ARG_LIST@[46; 48) | 54 | ARG_LIST@[46; 48) |
53 | L_PAREN@[46; 47) "(" | 55 | L_PAREN@[46; 47) "(" |
54 | R_PAREN@[47; 48) ")" | 56 | R_PAREN@[47; 48) ")" |
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rs b/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rs new file mode 100644 index 000000000..eb21a657b --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rs | |||
@@ -0,0 +1 @@ | |||
fn print_all<T: Iterator<Item: Display>>(printables: T) {} | |||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.txt b/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.txt new file mode 100644 index 000000000..33e75510d --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.txt | |||
@@ -0,0 +1,55 @@ | |||
1 | SOURCE_FILE@[0; 59) | ||
2 | FN_DEF@[0; 58) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 12) | ||
6 | IDENT@[3; 12) "print_all" | ||
7 | TYPE_PARAM_LIST@[12; 40) | ||
8 | L_ANGLE@[12; 13) "<" | ||
9 | TYPE_PARAM@[13; 39) | ||
10 | NAME@[13; 14) | ||
11 | IDENT@[13; 14) "T" | ||
12 | COLON@[14; 15) ":" | ||
13 | WHITESPACE@[15; 16) " " | ||
14 | TYPE_BOUND_LIST@[16; 39) | ||
15 | TYPE_BOUND@[16; 39) | ||
16 | PATH_TYPE@[16; 39) | ||
17 | PATH@[16; 39) | ||
18 | PATH_SEGMENT@[16; 39) | ||
19 | NAME_REF@[16; 24) | ||
20 | IDENT@[16; 24) "Iterator" | ||
21 | TYPE_ARG_LIST@[24; 39) | ||
22 | L_ANGLE@[24; 25) "<" | ||
23 | ASSOC_TYPE_ARG@[25; 38) | ||
24 | NAME_REF@[25; 29) | ||
25 | IDENT@[25; 29) "Item" | ||
26 | COLON@[29; 30) ":" | ||
27 | WHITESPACE@[30; 31) " " | ||
28 | TYPE_BOUND_LIST@[31; 38) | ||
29 | TYPE_BOUND@[31; 38) | ||
30 | PATH_TYPE@[31; 38) | ||
31 | PATH@[31; 38) | ||
32 | PATH_SEGMENT@[31; 38) | ||
33 | NAME_REF@[31; 38) | ||
34 | IDENT@[31; 38) "Display" | ||
35 | R_ANGLE@[38; 39) ">" | ||
36 | R_ANGLE@[39; 40) ">" | ||
37 | PARAM_LIST@[40; 55) | ||
38 | L_PAREN@[40; 41) "(" | ||
39 | PARAM@[41; 54) | ||
40 | BIND_PAT@[41; 51) | ||
41 | NAME@[41; 51) | ||
42 | IDENT@[41; 51) "printables" | ||
43 | COLON@[51; 52) ":" | ||
44 | WHITESPACE@[52; 53) " " | ||
45 | PATH_TYPE@[53; 54) | ||
46 | PATH@[53; 54) | ||
47 | PATH_SEGMENT@[53; 54) | ||
48 | NAME_REF@[53; 54) | ||
49 | IDENT@[53; 54) "T" | ||
50 | R_PAREN@[54; 55) ")" | ||
51 | WHITESPACE@[55; 56) " " | ||
52 | BLOCK@[56; 58) | ||
53 | L_CURLY@[56; 57) "{" | ||
54 | R_CURLY@[57; 58) "}" | ||
55 | WHITESPACE@[58; 59) "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rs b/crates/ra_syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rs new file mode 100644 index 000000000..35155057a --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rs | |||
@@ -0,0 +1 @@ | |||
fn f(#[must_use] self) {} | |||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.txt b/crates/ra_syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.txt new file mode 100644 index 000000000..49b14e632 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.txt | |||
@@ -0,0 +1,23 @@ | |||
1 | SOURCE_FILE@[0; 26) | ||
2 | FN_DEF@[0; 25) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 4) | ||
6 | IDENT@[3; 4) "f" | ||
7 | PARAM_LIST@[4; 22) | ||
8 | L_PAREN@[4; 5) "(" | ||
9 | ATTR@[5; 16) | ||
10 | POUND@[5; 6) "#" | ||
11 | TOKEN_TREE@[6; 16) | ||
12 | L_BRACK@[6; 7) "[" | ||
13 | IDENT@[7; 15) "must_use" | ||
14 | R_BRACK@[15; 16) "]" | ||
15 | WHITESPACE@[16; 17) " " | ||
16 | SELF_PARAM@[17; 21) | ||
17 | SELF_KW@[17; 21) "self" | ||
18 | R_PAREN@[21; 22) ")" | ||
19 | WHITESPACE@[22; 23) " " | ||
20 | BLOCK@[23; 25) | ||
21 | L_CURLY@[23; 24) "{" | ||
22 | R_CURLY@[24; 25) "}" | ||
23 | WHITESPACE@[25; 26) "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0139_param_outer_arg.rs b/crates/ra_syntax/test_data/parser/inline/ok/0139_param_outer_arg.rs new file mode 100644 index 000000000..c238be791 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0139_param_outer_arg.rs | |||
@@ -0,0 +1 @@ | |||
fn f(#[attr1] pat: Type) {} | |||
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0139_param_outer_arg.txt b/crates/ra_syntax/test_data/parser/inline/ok/0139_param_outer_arg.txt new file mode 100644 index 000000000..91c5e5f9a --- /dev/null +++ b/crates/ra_syntax/test_data/parser/inline/ok/0139_param_outer_arg.txt | |||
@@ -0,0 +1,32 @@ | |||
1 | SOURCE_FILE@[0; 28) | ||
2 | FN_DEF@[0; 27) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 4) | ||
6 | IDENT@[3; 4) "f" | ||
7 | PARAM_LIST@[4; 24) | ||
8 | L_PAREN@[4; 5) "(" | ||
9 | ATTR@[5; 13) | ||
10 | POUND@[5; 6) "#" | ||
11 | TOKEN_TREE@[6; 13) | ||
12 | L_BRACK@[6; 7) "[" | ||
13 | IDENT@[7; 12) "attr1" | ||
14 | R_BRACK@[12; 13) "]" | ||
15 | WHITESPACE@[13; 14) " " | ||
16 | PARAM@[14; 23) | ||
17 | BIND_PAT@[14; 17) | ||
18 | NAME@[14; 17) | ||
19 | IDENT@[14; 17) "pat" | ||
20 | COLON@[17; 18) ":" | ||
21 | WHITESPACE@[18; 19) " " | ||
22 | PATH_TYPE@[19; 23) | ||
23 | PATH@[19; 23) | ||
24 | PATH_SEGMENT@[19; 23) | ||
25 | NAME_REF@[19; 23) | ||
26 | IDENT@[19; 23) "Type" | ||
27 | R_PAREN@[23; 24) ")" | ||
28 | WHITESPACE@[24; 25) " " | ||
29 | BLOCK@[25; 27) | ||
30 | L_CURLY@[25; 26) "{" | ||
31 | R_CURLY@[26; 27) "}" | ||
32 | WHITESPACE@[27; 28) "\n" | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.rs b/crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.rs new file mode 100644 index 000000000..de350d858 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.rs | |||
@@ -0,0 +1,21 @@ | |||
1 | fn g1(#[attr1] #[attr2] pat: Type) {} | ||
2 | fn g2(#[attr1] x: u8) {} | ||
3 | |||
4 | extern "C" { fn printf(format: *const i8, #[attr] ...) -> i32; } | ||
5 | |||
6 | fn foo<F: FnMut(#[attr] &mut Foo<'a>)>(){} | ||
7 | |||
8 | trait Foo { | ||
9 | fn bar(#[attr] _: u64, # [attr] mut x: i32); | ||
10 | } | ||
11 | |||
12 | impl S { | ||
13 | fn f(#[must_use] self) {} | ||
14 | fn g1(#[attr] self) {} | ||
15 | fn g2(#[attr] &self) {} | ||
16 | fn g3<'a>(#[attr] &mut self) {} | ||
17 | fn g4<'a>(#[attr] &'a self) {} | ||
18 | fn g5<'a>(#[attr] &'a mut self) {} | ||
19 | fn c(#[attr] self: Self) {} | ||
20 | fn d(#[attr] self: Rc<Self>) {} | ||
21 | } \ No newline at end of file | ||
diff --git a/crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.txt b/crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.txt new file mode 100644 index 000000000..b360f29f4 --- /dev/null +++ b/crates/ra_syntax/test_data/parser/ok/0051_parameter_attrs.txt | |||
@@ -0,0 +1,477 @@ | |||
1 | SOURCE_FILE@[0; 519) | ||
2 | FN_DEF@[0; 37) | ||
3 | FN_KW@[0; 2) "fn" | ||
4 | WHITESPACE@[2; 3) " " | ||
5 | NAME@[3; 5) | ||
6 | IDENT@[3; 5) "g1" | ||
7 | PARAM_LIST@[5; 34) | ||
8 | L_PAREN@[5; 6) "(" | ||
9 | ATTR@[6; 14) | ||
10 | POUND@[6; 7) "#" | ||
11 | TOKEN_TREE@[7; 14) | ||
12 | L_BRACK@[7; 8) "[" | ||
13 | IDENT@[8; 13) "attr1" | ||
14 | R_BRACK@[13; 14) "]" | ||
15 | WHITESPACE@[14; 15) " " | ||
16 | ATTR@[15; 23) | ||
17 | POUND@[15; 16) "#" | ||
18 | TOKEN_TREE@[16; 23) | ||
19 | L_BRACK@[16; 17) "[" | ||
20 | IDENT@[17; 22) "attr2" | ||
21 | R_BRACK@[22; 23) "]" | ||
22 | WHITESPACE@[23; 24) " " | ||
23 | PARAM@[24; 33) | ||
24 | BIND_PAT@[24; 27) | ||
25 | NAME@[24; 27) | ||
26 | IDENT@[24; 27) "pat" | ||
27 | COLON@[27; 28) ":" | ||
28 | WHITESPACE@[28; 29) " " | ||
29 | PATH_TYPE@[29; 33) | ||
30 | PATH@[29; 33) | ||
31 | PATH_SEGMENT@[29; 33) | ||
32 | NAME_REF@[29; 33) | ||
33 | IDENT@[29; 33) "Type" | ||
34 | R_PAREN@[33; 34) ")" | ||
35 | WHITESPACE@[34; 35) " " | ||
36 | BLOCK@[35; 37) | ||
37 | L_CURLY@[35; 36) "{" | ||
38 | R_CURLY@[36; 37) "}" | ||
39 | WHITESPACE@[37; 38) "\n" | ||
40 | FN_DEF@[38; 62) | ||
41 | FN_KW@[38; 40) "fn" | ||
42 | WHITESPACE@[40; 41) " " | ||
43 | NAME@[41; 43) | ||
44 | IDENT@[41; 43) "g2" | ||
45 | PARAM_LIST@[43; 59) | ||
46 | L_PAREN@[43; 44) "(" | ||
47 | ATTR@[44; 52) | ||
48 | POUND@[44; 45) "#" | ||
49 | TOKEN_TREE@[45; 52) | ||
50 | L_BRACK@[45; 46) "[" | ||
51 | IDENT@[46; 51) "attr1" | ||
52 | R_BRACK@[51; 52) "]" | ||
53 | WHITESPACE@[52; 53) " " | ||
54 | PARAM@[53; 58) | ||
55 | BIND_PAT@[53; 54) | ||
56 | NAME@[53; 54) | ||
57 | IDENT@[53; 54) "x" | ||
58 | COLON@[54; 55) ":" | ||
59 | WHITESPACE@[55; 56) " " | ||
60 | PATH_TYPE@[56; 58) | ||
61 | PATH@[56; 58) | ||
62 | PATH_SEGMENT@[56; 58) | ||
63 | NAME_REF@[56; 58) | ||
64 | IDENT@[56; 58) "u8" | ||
65 | R_PAREN@[58; 59) ")" | ||
66 | WHITESPACE@[59; 60) " " | ||
67 | BLOCK@[60; 62) | ||
68 | L_CURLY@[60; 61) "{" | ||
69 | R_CURLY@[61; 62) "}" | ||
70 | WHITESPACE@[62; 64) "\n\n" | ||
71 | EXTERN_BLOCK@[64; 128) | ||
72 | ABI@[64; 74) | ||
73 | EXTERN_KW@[64; 70) "extern" | ||
74 | WHITESPACE@[70; 71) " " | ||
75 | STRING@[71; 74) "\"C\"" | ||
76 | WHITESPACE@[74; 75) " " | ||
77 | EXTERN_ITEM_LIST@[75; 128) | ||
78 | L_CURLY@[75; 76) "{" | ||
79 | WHITESPACE@[76; 77) " " | ||
80 | FN_DEF@[77; 126) | ||
81 | FN_KW@[77; 79) "fn" | ||
82 | WHITESPACE@[79; 80) " " | ||
83 | NAME@[80; 86) | ||
84 | IDENT@[80; 86) "printf" | ||
85 | PARAM_LIST@[86; 118) | ||
86 | L_PAREN@[86; 87) "(" | ||
87 | PARAM@[87; 104) | ||
88 | BIND_PAT@[87; 93) | ||
89 | NAME@[87; 93) | ||
90 | IDENT@[87; 93) "format" | ||
91 | COLON@[93; 94) ":" | ||
92 | WHITESPACE@[94; 95) " " | ||
93 | POINTER_TYPE@[95; 104) | ||
94 | STAR@[95; 96) "*" | ||
95 | CONST_KW@[96; 101) "const" | ||
96 | WHITESPACE@[101; 102) " " | ||
97 | PATH_TYPE@[102; 104) | ||
98 | PATH@[102; 104) | ||
99 | PATH_SEGMENT@[102; 104) | ||
100 | NAME_REF@[102; 104) | ||
101 | IDENT@[102; 104) "i8" | ||
102 | COMMA@[104; 105) "," | ||
103 | WHITESPACE@[105; 106) " " | ||
104 | ATTR@[106; 113) | ||
105 | POUND@[106; 107) "#" | ||
106 | TOKEN_TREE@[107; 113) | ||
107 | L_BRACK@[107; 108) "[" | ||
108 | IDENT@[108; 112) "attr" | ||
109 | R_BRACK@[112; 113) "]" | ||
110 | WHITESPACE@[113; 114) " " | ||
111 | DOTDOTDOT@[114; 117) "..." | ||
112 | R_PAREN@[117; 118) ")" | ||
113 | WHITESPACE@[118; 119) " " | ||
114 | RET_TYPE@[119; 125) | ||
115 | THIN_ARROW@[119; 121) "->" | ||
116 | WHITESPACE@[121; 122) " " | ||
117 | PATH_TYPE@[122; 125) | ||
118 | PATH@[122; 125) | ||
119 | PATH_SEGMENT@[122; 125) | ||
120 | NAME_REF@[122; 125) | ||
121 | IDENT@[122; 125) "i32" | ||
122 | SEMI@[125; 126) ";" | ||
123 | WHITESPACE@[126; 127) " " | ||
124 | R_CURLY@[127; 128) "}" | ||
125 | WHITESPACE@[128; 130) "\n\n" | ||
126 | FN_DEF@[130; 172) | ||
127 | FN_KW@[130; 132) "fn" | ||
128 | WHITESPACE@[132; 133) " " | ||
129 | NAME@[133; 136) | ||
130 | IDENT@[133; 136) "foo" | ||
131 | TYPE_PARAM_LIST@[136; 168) | ||
132 | L_ANGLE@[136; 137) "<" | ||
133 | TYPE_PARAM@[137; 167) | ||
134 | NAME@[137; 138) | ||
135 | IDENT@[137; 138) "F" | ||
136 | COLON@[138; 139) ":" | ||
137 | WHITESPACE@[139; 140) " " | ||
138 | TYPE_BOUND_LIST@[140; 167) | ||
139 | TYPE_BOUND@[140; 167) | ||
140 | PATH_TYPE@[140; 167) | ||
141 | PATH@[140; 167) | ||
142 | PATH_SEGMENT@[140; 167) | ||
143 | NAME_REF@[140; 145) | ||
144 | IDENT@[140; 145) "FnMut" | ||
145 | PARAM_LIST@[145; 167) | ||
146 | L_PAREN@[145; 146) "(" | ||
147 | ATTR@[146; 153) | ||
148 | POUND@[146; 147) "#" | ||
149 | TOKEN_TREE@[147; 153) | ||
150 | L_BRACK@[147; 148) "[" | ||
151 | IDENT@[148; 152) "attr" | ||
152 | R_BRACK@[152; 153) "]" | ||
153 | WHITESPACE@[153; 154) " " | ||
154 | PARAM@[154; 166) | ||
155 | REFERENCE_TYPE@[154; 166) | ||
156 | AMP@[154; 155) "&" | ||
157 | MUT_KW@[155; 158) "mut" | ||
158 | WHITESPACE@[158; 159) " " | ||
159 | PATH_TYPE@[159; 166) | ||
160 | PATH@[159; 166) | ||
161 | PATH_SEGMENT@[159; 166) | ||
162 | NAME_REF@[159; 162) | ||
163 | IDENT@[159; 162) "Foo" | ||
164 | TYPE_ARG_LIST@[162; 166) | ||
165 | L_ANGLE@[162; 163) "<" | ||
166 | LIFETIME_ARG@[163; 165) | ||
167 | LIFETIME@[163; 165) "\'a" | ||
168 | R_ANGLE@[165; 166) ">" | ||
169 | R_PAREN@[166; 167) ")" | ||
170 | R_ANGLE@[167; 168) ">" | ||
171 | PARAM_LIST@[168; 170) | ||
172 | L_PAREN@[168; 169) "(" | ||
173 | R_PAREN@[169; 170) ")" | ||
174 | BLOCK@[170; 172) | ||
175 | L_CURLY@[170; 171) "{" | ||
176 | R_CURLY@[171; 172) "}" | ||
177 | WHITESPACE@[172; 174) "\n\n" | ||
178 | TRAIT_DEF@[174; 236) | ||
179 | TRAIT_KW@[174; 179) "trait" | ||
180 | WHITESPACE@[179; 180) " " | ||
181 | NAME@[180; 183) | ||
182 | IDENT@[180; 183) "Foo" | ||
183 | WHITESPACE@[183; 184) " " | ||
184 | ITEM_LIST@[184; 236) | ||
185 | L_CURLY@[184; 185) "{" | ||
186 | WHITESPACE@[185; 190) "\n " | ||
187 | FN_DEF@[190; 234) | ||
188 | FN_KW@[190; 192) "fn" | ||
189 | WHITESPACE@[192; 193) " " | ||
190 | NAME@[193; 196) | ||
191 | IDENT@[193; 196) "bar" | ||
192 | PARAM_LIST@[196; 233) | ||
193 | L_PAREN@[196; 197) "(" | ||
194 | ATTR@[197; 204) | ||
195 | POUND@[197; 198) "#" | ||
196 | TOKEN_TREE@[198; 204) | ||
197 | L_BRACK@[198; 199) "[" | ||
198 | IDENT@[199; 203) "attr" | ||
199 | R_BRACK@[203; 204) "]" | ||
200 | WHITESPACE@[204; 205) " " | ||
201 | PARAM@[205; 211) | ||
202 | PLACEHOLDER_PAT@[205; 206) | ||
203 | UNDERSCORE@[205; 206) "_" | ||
204 | COLON@[206; 207) ":" | ||
205 | WHITESPACE@[207; 208) " " | ||
206 | PATH_TYPE@[208; 211) | ||
207 | PATH@[208; 211) | ||
208 | PATH_SEGMENT@[208; 211) | ||
209 | NAME_REF@[208; 211) | ||
210 | IDENT@[208; 211) "u64" | ||
211 | COMMA@[211; 212) "," | ||
212 | WHITESPACE@[212; 213) " " | ||
213 | ATTR@[213; 221) | ||
214 | POUND@[213; 214) "#" | ||
215 | WHITESPACE@[214; 215) " " | ||
216 | TOKEN_TREE@[215; 221) | ||
217 | L_BRACK@[215; 216) "[" | ||
218 | IDENT@[216; 220) "attr" | ||
219 | R_BRACK@[220; 221) "]" | ||
220 | WHITESPACE@[221; 222) " " | ||
221 | PARAM@[222; 232) | ||
222 | BIND_PAT@[222; 227) | ||
223 | MUT_KW@[222; 225) "mut" | ||
224 | WHITESPACE@[225; 226) " " | ||
225 | NAME@[226; 227) | ||
226 | IDENT@[226; 227) "x" | ||
227 | COLON@[227; 228) ":" | ||
228 | WHITESPACE@[228; 229) " " | ||
229 | PATH_TYPE@[229; 232) | ||
230 | PATH@[229; 232) | ||
231 | PATH_SEGMENT@[229; 232) | ||
232 | NAME_REF@[229; 232) | ||
233 | IDENT@[229; 232) "i32" | ||
234 | R_PAREN@[232; 233) ")" | ||
235 | SEMI@[233; 234) ";" | ||
236 | WHITESPACE@[234; 235) "\n" | ||
237 | R_CURLY@[235; 236) "}" | ||
238 | WHITESPACE@[236; 238) "\n\n" | ||
239 | IMPL_BLOCK@[238; 519) | ||
240 | IMPL_KW@[238; 242) "impl" | ||
241 | WHITESPACE@[242; 243) " " | ||
242 | PATH_TYPE@[243; 244) | ||
243 | PATH@[243; 244) | ||
244 | PATH_SEGMENT@[243; 244) | ||
245 | NAME_REF@[243; 244) | ||
246 | IDENT@[243; 244) "S" | ||
247 | WHITESPACE@[244; 245) " " | ||
248 | ITEM_LIST@[245; 519) | ||
249 | L_CURLY@[245; 246) "{" | ||
250 | WHITESPACE@[246; 252) "\n " | ||
251 | FN_DEF@[252; 277) | ||
252 | FN_KW@[252; 254) "fn" | ||
253 | WHITESPACE@[254; 255) " " | ||
254 | NAME@[255; 256) | ||
255 | IDENT@[255; 256) "f" | ||
256 | PARAM_LIST@[256; 274) | ||
257 | L_PAREN@[256; 257) "(" | ||
258 | ATTR@[257; 268) | ||
259 | POUND@[257; 258) "#" | ||
260 | TOKEN_TREE@[258; 268) | ||
261 | L_BRACK@[258; 259) "[" | ||
262 | IDENT@[259; 267) "must_use" | ||
263 | R_BRACK@[267; 268) "]" | ||
264 | WHITESPACE@[268; 269) " " | ||
265 | SELF_PARAM@[269; 273) | ||
266 | SELF_KW@[269; 273) "self" | ||
267 | R_PAREN@[273; 274) ")" | ||
268 | WHITESPACE@[274; 275) " " | ||
269 | BLOCK@[275; 277) | ||
270 | L_CURLY@[275; 276) "{" | ||
271 | R_CURLY@[276; 277) "}" | ||
272 | WHITESPACE@[277; 283) "\n " | ||
273 | FN_DEF@[283; 305) | ||
274 | FN_KW@[283; 285) "fn" | ||
275 | WHITESPACE@[285; 286) " " | ||
276 | NAME@[286; 288) | ||
277 | IDENT@[286; 288) "g1" | ||
278 | PARAM_LIST@[288; 302) | ||
279 | L_PAREN@[288; 289) "(" | ||
280 | ATTR@[289; 296) | ||
281 | POUND@[289; 290) "#" | ||
282 | TOKEN_TREE@[290; 296) | ||
283 | L_BRACK@[290; 291) "[" | ||
284 | IDENT@[291; 295) "attr" | ||
285 | R_BRACK@[295; 296) "]" | ||
286 | WHITESPACE@[296; 297) " " | ||
287 | SELF_PARAM@[297; 301) | ||
288 | SELF_KW@[297; 301) "self" | ||
289 | R_PAREN@[301; 302) ")" | ||
290 | WHITESPACE@[302; 303) " " | ||
291 | BLOCK@[303; 305) | ||
292 | L_CURLY@[303; 304) "{" | ||
293 | R_CURLY@[304; 305) "}" | ||
294 | WHITESPACE@[305; 311) "\n " | ||
295 | FN_DEF@[311; 334) | ||
296 | FN_KW@[311; 313) "fn" | ||
297 | WHITESPACE@[313; 314) " " | ||
298 | NAME@[314; 316) | ||
299 | IDENT@[314; 316) "g2" | ||
300 | PARAM_LIST@[316; 331) | ||
301 | L_PAREN@[316; 317) "(" | ||
302 | ATTR@[317; 324) | ||
303 | POUND@[317; 318) "#" | ||
304 | TOKEN_TREE@[318; 324) | ||
305 | L_BRACK@[318; 319) "[" | ||
306 | IDENT@[319; 323) "attr" | ||
307 | R_BRACK@[323; 324) "]" | ||
308 | WHITESPACE@[324; 325) " " | ||
309 | SELF_PARAM@[325; 330) | ||
310 | AMP@[325; 326) "&" | ||
311 | SELF_KW@[326; 330) "self" | ||
312 | R_PAREN@[330; 331) ")" | ||
313 | WHITESPACE@[331; 332) " " | ||
314 | BLOCK@[332; 334) | ||
315 | L_CURLY@[332; 333) "{" | ||
316 | R_CURLY@[333; 334) "}" | ||
317 | WHITESPACE@[334; 340) "\n " | ||
318 | FN_DEF@[340; 371) | ||
319 | FN_KW@[340; 342) "fn" | ||
320 | WHITESPACE@[342; 343) " " | ||
321 | NAME@[343; 345) | ||
322 | IDENT@[343; 345) "g3" | ||
323 | TYPE_PARAM_LIST@[345; 349) | ||
324 | L_ANGLE@[345; 346) "<" | ||
325 | LIFETIME_PARAM@[346; 348) | ||
326 | LIFETIME@[346; 348) "\'a" | ||
327 | R_ANGLE@[348; 349) ">" | ||
328 | PARAM_LIST@[349; 368) | ||
329 | L_PAREN@[349; 350) "(" | ||
330 | ATTR@[350; 357) | ||
331 | POUND@[350; 351) "#" | ||
332 | TOKEN_TREE@[351; 357) | ||
333 | L_BRACK@[351; 352) "[" | ||
334 | IDENT@[352; 356) "attr" | ||
335 | R_BRACK@[356; 357) "]" | ||
336 | WHITESPACE@[357; 358) " " | ||
337 | SELF_PARAM@[358; 367) | ||
338 | AMP@[358; 359) "&" | ||
339 | MUT_KW@[359; 362) "mut" | ||
340 | WHITESPACE@[362; 363) " " | ||
341 | SELF_KW@[363; 367) "self" | ||
342 | R_PAREN@[367; 368) ")" | ||
343 | WHITESPACE@[368; 369) " " | ||
344 | BLOCK@[369; 371) | ||
345 | L_CURLY@[369; 370) "{" | ||
346 | R_CURLY@[370; 371) "}" | ||
347 | WHITESPACE@[371; 377) "\n " | ||
348 | FN_DEF@[377; 407) | ||
349 | FN_KW@[377; 379) "fn" | ||
350 | WHITESPACE@[379; 380) " " | ||
351 | NAME@[380; 382) | ||
352 | IDENT@[380; 382) "g4" | ||
353 | TYPE_PARAM_LIST@[382; 386) | ||
354 | L_ANGLE@[382; 383) "<" | ||
355 | LIFETIME_PARAM@[383; 385) | ||
356 | LIFETIME@[383; 385) "\'a" | ||
357 | R_ANGLE@[385; 386) ">" | ||
358 | PARAM_LIST@[386; 404) | ||
359 | L_PAREN@[386; 387) "(" | ||
360 | ATTR@[387; 394) | ||
361 | POUND@[387; 388) "#" | ||
362 | TOKEN_TREE@[388; 394) | ||
363 | L_BRACK@[388; 389) "[" | ||
364 | IDENT@[389; 393) "attr" | ||
365 | R_BRACK@[393; 394) "]" | ||
366 | WHITESPACE@[394; 395) " " | ||
367 | SELF_PARAM@[395; 403) | ||
368 | AMP@[395; 396) "&" | ||
369 | LIFETIME@[396; 398) "\'a" | ||
370 | WHITESPACE@[398; 399) " " | ||
371 | SELF_KW@[399; 403) "self" | ||
372 | R_PAREN@[403; 404) ")" | ||
373 | WHITESPACE@[404; 405) " " | ||
374 | BLOCK@[405; 407) | ||
375 | L_CURLY@[405; 406) "{" | ||
376 | R_CURLY@[406; 407) "}" | ||
377 | WHITESPACE@[407; 413) "\n " | ||
378 | FN_DEF@[413; 447) | ||
379 | FN_KW@[413; 415) "fn" | ||
380 | WHITESPACE@[415; 416) " " | ||
381 | NAME@[416; 418) | ||
382 | IDENT@[416; 418) "g5" | ||
383 | TYPE_PARAM_LIST@[418; 422) | ||
384 | L_ANGLE@[418; 419) "<" | ||
385 | LIFETIME_PARAM@[419; 421) | ||
386 | LIFETIME@[419; 421) "\'a" | ||
387 | R_ANGLE@[421; 422) ">" | ||
388 | PARAM_LIST@[422; 444) | ||
389 | L_PAREN@[422; 423) "(" | ||
390 | ATTR@[423; 430) | ||
391 | POUND@[423; 424) "#" | ||
392 | TOKEN_TREE@[424; 430) | ||
393 | L_BRACK@[424; 425) "[" | ||
394 | IDENT@[425; 429) "attr" | ||
395 | R_BRACK@[429; 430) "]" | ||
396 | WHITESPACE@[430; 431) " " | ||
397 | SELF_PARAM@[431; 443) | ||
398 | AMP@[431; 432) "&" | ||
399 | LIFETIME@[432; 434) "\'a" | ||
400 | WHITESPACE@[434; 435) " " | ||
401 | MUT_KW@[435; 438) "mut" | ||
402 | WHITESPACE@[438; 439) " " | ||
403 | SELF_KW@[439; 443) "self" | ||
404 | R_PAREN@[443; 444) ")" | ||
405 | WHITESPACE@[444; 445) " " | ||
406 | BLOCK@[445; 447) | ||
407 | L_CURLY@[445; 446) "{" | ||
408 | R_CURLY@[446; 447) "}" | ||
409 | WHITESPACE@[447; 453) "\n " | ||
410 | FN_DEF@[453; 480) | ||
411 | FN_KW@[453; 455) "fn" | ||
412 | WHITESPACE@[455; 456) " " | ||
413 | NAME@[456; 457) | ||
414 | IDENT@[456; 457) "c" | ||
415 | PARAM_LIST@[457; 477) | ||
416 | L_PAREN@[457; 458) "(" | ||
417 | ATTR@[458; 465) | ||
418 | POUND@[458; 459) "#" | ||
419 | TOKEN_TREE@[459; 465) | ||
420 | L_BRACK@[459; 460) "[" | ||
421 | IDENT@[460; 464) "attr" | ||
422 | R_BRACK@[464; 465) "]" | ||
423 | WHITESPACE@[465; 466) " " | ||
424 | SELF_PARAM@[466; 476) | ||
425 | SELF_KW@[466; 470) "self" | ||
426 | COLON@[470; 471) ":" | ||
427 | WHITESPACE@[471; 472) " " | ||
428 | PATH_TYPE@[472; 476) | ||
429 | PATH@[472; 476) | ||
430 | PATH_SEGMENT@[472; 476) | ||
431 | NAME_REF@[472; 476) | ||
432 | IDENT@[472; 476) "Self" | ||
433 | R_PAREN@[476; 477) ")" | ||
434 | WHITESPACE@[477; 478) " " | ||
435 | BLOCK@[478; 480) | ||
436 | L_CURLY@[478; 479) "{" | ||
437 | R_CURLY@[479; 480) "}" | ||
438 | WHITESPACE@[480; 486) "\n " | ||
439 | FN_DEF@[486; 517) | ||
440 | FN_KW@[486; 488) "fn" | ||
441 | WHITESPACE@[488; 489) " " | ||
442 | NAME@[489; 490) | ||
443 | IDENT@[489; 490) "d" | ||
444 | PARAM_LIST@[490; 514) | ||
445 | L_PAREN@[490; 491) "(" | ||
446 | ATTR@[491; 498) | ||
447 | POUND@[491; 492) "#" | ||
448 | TOKEN_TREE@[492; 498) | ||
449 | L_BRACK@[492; 493) "[" | ||
450 | IDENT@[493; 497) "attr" | ||
451 | R_BRACK@[497; 498) "]" | ||
452 | WHITESPACE@[498; 499) " " | ||
453 | SELF_PARAM@[499; 513) | ||
454 | SELF_KW@[499; 503) "self" | ||
455 | COLON@[503; 504) ":" | ||
456 | WHITESPACE@[504; 505) " " | ||
457 | PATH_TYPE@[505; 513) | ||
458 | PATH@[505; 513) | ||
459 | PATH_SEGMENT@[505; 513) | ||
460 | NAME_REF@[505; 507) | ||
461 | IDENT@[505; 507) "Rc" | ||
462 | TYPE_ARG_LIST@[507; 513) | ||
463 | L_ANGLE@[507; 508) "<" | ||
464 | TYPE_ARG@[508; 512) | ||
465 | PATH_TYPE@[508; 512) | ||
466 | PATH@[508; 512) | ||
467 | PATH_SEGMENT@[508; 512) | ||
468 | NAME_REF@[508; 512) | ||
469 | IDENT@[508; 512) "Self" | ||
470 | R_ANGLE@[512; 513) ">" | ||
471 | R_PAREN@[513; 514) ")" | ||
472 | WHITESPACE@[514; 515) " " | ||
473 | BLOCK@[515; 517) | ||
474 | L_CURLY@[515; 516) "{" | ||
475 | R_CURLY@[516; 517) "}" | ||
476 | WHITESPACE@[517; 518) "\n" | ||
477 | R_CURLY@[518; 519) "}" | ||
diff --git a/crates/ra_tools/src/main.rs b/crates/ra_tools/src/main.rs index 4fcb2adeb..54d96e446 100644 --- a/crates/ra_tools/src/main.rs +++ b/crates/ra_tools/src/main.rs | |||
@@ -63,12 +63,12 @@ fn install(opts: InstallOpt) -> Result<()> { | |||
63 | if cfg!(target_os = "macos") { | 63 | if cfg!(target_os = "macos") { |
64 | fix_path_for_mac()? | 64 | fix_path_for_mac()? |
65 | } | 65 | } |
66 | if let Some(client) = opts.client { | ||
67 | install_client(client)?; | ||
68 | } | ||
69 | if let Some(server) = opts.server { | 66 | if let Some(server) = opts.server { |
70 | install_server(server)?; | 67 | install_server(server)?; |
71 | } | 68 | } |
69 | if let Some(client) = opts.client { | ||
70 | install_client(client)?; | ||
71 | } | ||
72 | Ok(()) | 72 | Ok(()) |
73 | } | 73 | } |
74 | 74 | ||
diff --git a/crates/ra_vfs_glob/Cargo.toml b/crates/ra_vfs_glob/Cargo.toml new file mode 100644 index 000000000..0390d7da1 --- /dev/null +++ b/crates/ra_vfs_glob/Cargo.toml | |||
@@ -0,0 +1,9 @@ | |||
1 | [package] | ||
2 | edition = "2018" | ||
3 | name = "ra_vfs_glob" | ||
4 | version = "0.1.0" | ||
5 | authors = ["rust-analyzer developers"] | ||
6 | |||
7 | [dependencies] | ||
8 | ra_vfs = "0.2.0" | ||
9 | globset = "0.4.4" | ||
diff --git a/crates/ra_vfs_glob/src/lib.rs b/crates/ra_vfs_glob/src/lib.rs new file mode 100644 index 000000000..12401d75a --- /dev/null +++ b/crates/ra_vfs_glob/src/lib.rs | |||
@@ -0,0 +1,94 @@ | |||
1 | //! `ra_vfs_glob` crate implements exclusion rules for vfs. | ||
2 | //! | ||
3 | //! By default, we include only `.rs` files, and skip some know offenders like | ||
4 | //! `/target` or `/node_modules` altogether. | ||
5 | //! | ||
6 | //! It's also possible to add custom exclusion globs. | ||
7 | |||
8 | use globset::{GlobSet, GlobSetBuilder}; | ||
9 | use ra_vfs::{Filter, RelativePath}; | ||
10 | |||
11 | pub use globset::{Glob, GlobBuilder}; | ||
12 | |||
13 | const ALWAYS_IGNORED: &[&str] = &["target/**", "**/node_modules/**", "**/.git/**"]; | ||
14 | const IGNORED_FOR_NON_MEMBERS: &[&str] = &["examples/**", "tests/**", "benches/**"]; | ||
15 | |||
16 | pub struct RustPackageFilterBuilder { | ||
17 | is_member: bool, | ||
18 | exclude: GlobSetBuilder, | ||
19 | } | ||
20 | |||
21 | impl Default for RustPackageFilterBuilder { | ||
22 | fn default() -> RustPackageFilterBuilder { | ||
23 | RustPackageFilterBuilder { is_member: false, exclude: GlobSetBuilder::new() } | ||
24 | } | ||
25 | } | ||
26 | |||
27 | impl RustPackageFilterBuilder { | ||
28 | pub fn set_member(mut self, is_member: bool) -> RustPackageFilterBuilder { | ||
29 | self.is_member = is_member; | ||
30 | self | ||
31 | } | ||
32 | pub fn exclude(mut self, glob: Glob) -> RustPackageFilterBuilder { | ||
33 | self.exclude.add(glob); | ||
34 | self | ||
35 | } | ||
36 | pub fn into_vfs_filter(self) -> Box<dyn Filter> { | ||
37 | let RustPackageFilterBuilder { is_member, mut exclude } = self; | ||
38 | for &glob in ALWAYS_IGNORED { | ||
39 | exclude.add(Glob::new(glob).unwrap()); | ||
40 | } | ||
41 | if !is_member { | ||
42 | for &glob in IGNORED_FOR_NON_MEMBERS { | ||
43 | exclude.add(Glob::new(glob).unwrap()); | ||
44 | } | ||
45 | } | ||
46 | Box::new(RustPackageFilter { exclude: exclude.build().unwrap() }) | ||
47 | } | ||
48 | } | ||
49 | |||
50 | struct RustPackageFilter { | ||
51 | exclude: GlobSet, | ||
52 | } | ||
53 | |||
54 | impl Filter for RustPackageFilter { | ||
55 | fn include_dir(&self, dir_path: &RelativePath) -> bool { | ||
56 | !self.exclude.is_match(dir_path.as_str()) | ||
57 | } | ||
58 | |||
59 | fn include_file(&self, file_path: &RelativePath) -> bool { | ||
60 | file_path.extension() == Some("rs") | ||
61 | } | ||
62 | } | ||
63 | |||
64 | #[test] | ||
65 | fn test_globs() { | ||
66 | let filter = RustPackageFilterBuilder::default().set_member(true).into_vfs_filter(); | ||
67 | |||
68 | assert!(filter.include_dir(RelativePath::new("src/tests"))); | ||
69 | assert!(filter.include_dir(RelativePath::new("src/target"))); | ||
70 | assert!(filter.include_dir(RelativePath::new("tests"))); | ||
71 | assert!(filter.include_dir(RelativePath::new("benches"))); | ||
72 | |||
73 | assert!(!filter.include_dir(RelativePath::new("target"))); | ||
74 | assert!(!filter.include_dir(RelativePath::new("src/foo/.git"))); | ||
75 | assert!(!filter.include_dir(RelativePath::new("foo/node_modules"))); | ||
76 | |||
77 | let filter = RustPackageFilterBuilder::default().set_member(false).into_vfs_filter(); | ||
78 | |||
79 | assert!(filter.include_dir(RelativePath::new("src/tests"))); | ||
80 | assert!(filter.include_dir(RelativePath::new("src/target"))); | ||
81 | |||
82 | assert!(!filter.include_dir(RelativePath::new("target"))); | ||
83 | assert!(!filter.include_dir(RelativePath::new("src/foo/.git"))); | ||
84 | assert!(!filter.include_dir(RelativePath::new("foo/node_modules"))); | ||
85 | assert!(!filter.include_dir(RelativePath::new("tests"))); | ||
86 | assert!(!filter.include_dir(RelativePath::new("benches"))); | ||
87 | |||
88 | let filter = RustPackageFilterBuilder::default() | ||
89 | .set_member(true) | ||
90 | .exclude(Glob::new("src/llvm-project/**").unwrap()) | ||
91 | .into_vfs_filter(); | ||
92 | |||
93 | assert!(!filter.include_dir(RelativePath::new("src/llvm-project/clang"))); | ||
94 | } | ||