diff options
Diffstat (limited to 'crates')
47 files changed, 1136 insertions, 332 deletions
diff --git a/crates/assists/src/assist_context.rs b/crates/assists/src/assist_context.rs index 69499ea32..80cf9aba1 100644 --- a/crates/assists/src/assist_context.rs +++ b/crates/assists/src/assist_context.rs | |||
@@ -4,10 +4,10 @@ use std::mem; | |||
4 | 4 | ||
5 | use algo::find_covering_element; | 5 | use algo::find_covering_element; |
6 | use hir::Semantics; | 6 | use hir::Semantics; |
7 | use ide_db::base_db::{FileId, FileRange}; | 7 | use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange}; |
8 | use ide_db::{ | 8 | use ide_db::{ |
9 | label::Label, | 9 | label::Label, |
10 | source_change::{SourceChange, SourceFileEdit}, | 10 | source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, |
11 | RootDatabase, | 11 | RootDatabase, |
12 | }; | 12 | }; |
13 | use syntax::{ | 13 | use syntax::{ |
@@ -209,6 +209,7 @@ pub(crate) struct AssistBuilder { | |||
209 | file_id: FileId, | 209 | file_id: FileId, |
210 | is_snippet: bool, | 210 | is_snippet: bool, |
211 | source_file_edits: Vec<SourceFileEdit>, | 211 | source_file_edits: Vec<SourceFileEdit>, |
212 | file_system_edits: Vec<FileSystemEdit>, | ||
212 | } | 213 | } |
213 | 214 | ||
214 | impl AssistBuilder { | 215 | impl AssistBuilder { |
@@ -218,6 +219,7 @@ impl AssistBuilder { | |||
218 | file_id, | 219 | file_id, |
219 | is_snippet: false, | 220 | is_snippet: false, |
220 | source_file_edits: Vec::default(), | 221 | source_file_edits: Vec::default(), |
222 | file_system_edits: Vec::default(), | ||
221 | } | 223 | } |
222 | } | 224 | } |
223 | 225 | ||
@@ -282,12 +284,17 @@ impl AssistBuilder { | |||
282 | algo::diff(&node, &new).into_text_edit(&mut self.edit); | 284 | algo::diff(&node, &new).into_text_edit(&mut self.edit); |
283 | } | 285 | } |
284 | } | 286 | } |
287 | pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) { | ||
288 | let file_system_edit = | ||
289 | FileSystemEdit::CreateFile { dst: dst.clone(), initial_contents: content.into() }; | ||
290 | self.file_system_edits.push(file_system_edit); | ||
291 | } | ||
285 | 292 | ||
286 | fn finish(mut self) -> SourceChange { | 293 | fn finish(mut self) -> SourceChange { |
287 | self.commit(); | 294 | self.commit(); |
288 | SourceChange { | 295 | SourceChange { |
289 | source_file_edits: mem::take(&mut self.source_file_edits), | 296 | source_file_edits: mem::take(&mut self.source_file_edits), |
290 | file_system_edits: Default::default(), | 297 | file_system_edits: mem::take(&mut self.file_system_edits), |
291 | is_snippet: self.is_snippet, | 298 | is_snippet: self.is_snippet, |
292 | } | 299 | } |
293 | } | 300 | } |
diff --git a/crates/assists/src/handlers/extract_module_to_file.rs b/crates/assists/src/handlers/extract_module_to_file.rs new file mode 100644 index 000000000..50bf67ef7 --- /dev/null +++ b/crates/assists/src/handlers/extract_module_to_file.rs | |||
@@ -0,0 +1,133 @@ | |||
1 | use ast::edit::IndentLevel; | ||
2 | use ide_db::base_db::AnchoredPathBuf; | ||
3 | use syntax::{ | ||
4 | ast::{self, edit::AstNodeEdit, NameOwner}, | ||
5 | AstNode, | ||
6 | }; | ||
7 | |||
8 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | ||
9 | |||
10 | // Assist: extract_module_to_file | ||
11 | // | ||
12 | // This assist extract module to file. | ||
13 | // | ||
14 | // ``` | ||
15 | // mod foo {<|> | ||
16 | // fn t() {} | ||
17 | // } | ||
18 | // ``` | ||
19 | // -> | ||
20 | // ``` | ||
21 | // mod foo; | ||
22 | // ``` | ||
23 | pub(crate) fn extract_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
24 | let module_ast = ctx.find_node_at_offset::<ast::Module>()?; | ||
25 | let module_name = module_ast.name()?; | ||
26 | |||
27 | let module_def = ctx.sema.to_def(&module_ast)?; | ||
28 | let parent_module = module_def.parent(ctx.db())?; | ||
29 | |||
30 | let module_items = module_ast.item_list()?; | ||
31 | let target = module_ast.syntax().text_range(); | ||
32 | let anchor_file_id = ctx.frange.file_id; | ||
33 | |||
34 | acc.add( | ||
35 | AssistId("extract_module_to_file", AssistKind::RefactorExtract), | ||
36 | "Extract module to file", | ||
37 | target, | ||
38 | |builder| { | ||
39 | let path = { | ||
40 | let dir = match parent_module.name(ctx.db()) { | ||
41 | Some(name) if !parent_module.is_mod_rs(ctx.db()) => format!("{}/", name), | ||
42 | _ => String::new(), | ||
43 | }; | ||
44 | format!("./{}{}.rs", dir, module_name) | ||
45 | }; | ||
46 | let contents = { | ||
47 | let items = module_items.dedent(IndentLevel(1)).to_string(); | ||
48 | let mut items = | ||
49 | items.trim_start_matches('{').trim_end_matches('}').trim().to_string(); | ||
50 | if !items.is_empty() { | ||
51 | items.push('\n'); | ||
52 | } | ||
53 | items | ||
54 | }; | ||
55 | |||
56 | builder.replace(target, format!("mod {};", module_name)); | ||
57 | |||
58 | let dst = AnchoredPathBuf { anchor: anchor_file_id, path }; | ||
59 | builder.create_file(dst, contents); | ||
60 | }, | ||
61 | ) | ||
62 | } | ||
63 | |||
64 | #[cfg(test)] | ||
65 | mod tests { | ||
66 | use crate::tests::check_assist; | ||
67 | |||
68 | use super::*; | ||
69 | |||
70 | #[test] | ||
71 | fn extract_from_root() { | ||
72 | check_assist( | ||
73 | extract_module_to_file, | ||
74 | r#" | ||
75 | mod tests {<|> | ||
76 | #[test] fn t() {} | ||
77 | } | ||
78 | "#, | ||
79 | r#" | ||
80 | //- /main.rs | ||
81 | mod tests; | ||
82 | //- /tests.rs | ||
83 | #[test] fn t() {} | ||
84 | "#, | ||
85 | ); | ||
86 | } | ||
87 | |||
88 | #[test] | ||
89 | fn extract_from_submodule() { | ||
90 | check_assist( | ||
91 | extract_module_to_file, | ||
92 | r#" | ||
93 | //- /main.rs | ||
94 | mod submod; | ||
95 | //- /submod.rs | ||
96 | mod inner<|> { | ||
97 | fn f() {} | ||
98 | } | ||
99 | fn g() {} | ||
100 | "#, | ||
101 | r#" | ||
102 | //- /submod.rs | ||
103 | mod inner; | ||
104 | fn g() {} | ||
105 | //- /submod/inner.rs | ||
106 | fn f() {} | ||
107 | "#, | ||
108 | ); | ||
109 | } | ||
110 | |||
111 | #[test] | ||
112 | fn extract_from_mod_rs() { | ||
113 | check_assist( | ||
114 | extract_module_to_file, | ||
115 | r#" | ||
116 | //- /main.rs | ||
117 | mod submodule; | ||
118 | //- /submodule/mod.rs | ||
119 | mod inner<|> { | ||
120 | fn f() {} | ||
121 | } | ||
122 | fn g() {} | ||
123 | "#, | ||
124 | r#" | ||
125 | //- /submodule/mod.rs | ||
126 | mod inner; | ||
127 | fn g() {} | ||
128 | //- /submodule/inner.rs | ||
129 | fn f() {} | ||
130 | "#, | ||
131 | ); | ||
132 | } | ||
133 | } | ||
diff --git a/crates/assists/src/handlers/invert_if.rs b/crates/assists/src/handlers/invert_if.rs index 91e2f5c8c..f9c33b3f7 100644 --- a/crates/assists/src/handlers/invert_if.rs +++ b/crates/assists/src/handlers/invert_if.rs | |||
@@ -78,6 +78,15 @@ mod tests { | |||
78 | } | 78 | } |
79 | 79 | ||
80 | #[test] | 80 | #[test] |
81 | fn invert_if_remove_not_parentheses() { | ||
82 | check_assist( | ||
83 | invert_if, | ||
84 | "fn f() { i<|>f !(x == 3 || x == 4 || x == 5) { 3 * 2 } else { 1 } }", | ||
85 | "fn f() { if x == 3 || x == 4 || x == 5 { 1 } else { 3 * 2 } }", | ||
86 | ) | ||
87 | } | ||
88 | |||
89 | #[test] | ||
81 | fn invert_if_remove_inequality() { | 90 | fn invert_if_remove_inequality() { |
82 | check_assist( | 91 | check_assist( |
83 | invert_if, | 92 | invert_if, |
diff --git a/crates/assists/src/handlers/remove_unused_param.rs b/crates/assists/src/handlers/remove_unused_param.rs index 1ff5e92b0..f72dd49ed 100644 --- a/crates/assists/src/handlers/remove_unused_param.rs +++ b/crates/assists/src/handlers/remove_unused_param.rs | |||
@@ -2,9 +2,10 @@ use ide_db::{defs::Definition, search::Reference}; | |||
2 | use syntax::{ | 2 | use syntax::{ |
3 | algo::find_node_at_range, | 3 | algo::find_node_at_range, |
4 | ast::{self, ArgListOwner}, | 4 | ast::{self, ArgListOwner}, |
5 | AstNode, SyntaxNode, TextRange, T, | 5 | AstNode, SyntaxKind, SyntaxNode, TextRange, T, |
6 | }; | 6 | }; |
7 | use test_utils::mark; | 7 | use test_utils::mark; |
8 | use SyntaxKind::WHITESPACE; | ||
8 | 9 | ||
9 | use crate::{ | 10 | use crate::{ |
10 | assist_context::AssistBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, Assists, | 11 | assist_context::AssistBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, Assists, |
@@ -56,7 +57,7 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext) -> Opt | |||
56 | "Remove unused parameter", | 57 | "Remove unused parameter", |
57 | param.syntax().text_range(), | 58 | param.syntax().text_range(), |
58 | |builder| { | 59 | |builder| { |
59 | builder.delete(range_with_coma(param.syntax())); | 60 | builder.delete(range_to_remove(param.syntax())); |
60 | for usage in fn_def.usages(&ctx.sema).all() { | 61 | for usage in fn_def.usages(&ctx.sema).all() { |
61 | process_usage(ctx, builder, usage, param_position); | 62 | process_usage(ctx, builder, usage, param_position); |
62 | } | 63 | } |
@@ -80,19 +81,34 @@ fn process_usage( | |||
80 | let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?; | 81 | let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?; |
81 | 82 | ||
82 | builder.edit_file(usage.file_range.file_id); | 83 | builder.edit_file(usage.file_range.file_id); |
83 | builder.delete(range_with_coma(arg.syntax())); | 84 | builder.delete(range_to_remove(arg.syntax())); |
84 | 85 | ||
85 | Some(()) | 86 | Some(()) |
86 | } | 87 | } |
87 | 88 | ||
88 | fn range_with_coma(node: &SyntaxNode) -> TextRange { | 89 | fn range_to_remove(node: &SyntaxNode) -> TextRange { |
89 | let up_to = next_prev().find_map(|dir| { | 90 | let up_to_comma = next_prev().find_map(|dir| { |
90 | node.siblings_with_tokens(dir) | 91 | node.siblings_with_tokens(dir) |
91 | .filter_map(|it| it.into_token()) | 92 | .filter_map(|it| it.into_token()) |
92 | .find(|it| it.kind() == T![,]) | 93 | .find(|it| it.kind() == T![,]) |
94 | .map(|it| (dir, it)) | ||
93 | }); | 95 | }); |
94 | let up_to = up_to.map_or(node.text_range(), |it| it.text_range()); | 96 | if let Some((dir, token)) = up_to_comma { |
95 | node.text_range().cover(up_to) | 97 | if node.next_sibling().is_some() { |
98 | let up_to_space = token | ||
99 | .siblings_with_tokens(dir) | ||
100 | .skip(1) | ||
101 | .take_while(|it| it.kind() == WHITESPACE) | ||
102 | .last() | ||
103 | .and_then(|it| it.into_token()); | ||
104 | return node | ||
105 | .text_range() | ||
106 | .cover(up_to_space.map_or(token.text_range(), |it| it.text_range())); | ||
107 | } | ||
108 | node.text_range().cover(token.text_range()) | ||
109 | } else { | ||
110 | node.text_range() | ||
111 | } | ||
96 | } | 112 | } |
97 | 113 | ||
98 | #[cfg(test)] | 114 | #[cfg(test)] |
@@ -119,6 +135,57 @@ fn b() { foo(9, ) } | |||
119 | } | 135 | } |
120 | 136 | ||
121 | #[test] | 137 | #[test] |
138 | fn remove_unused_first_param() { | ||
139 | check_assist( | ||
140 | remove_unused_param, | ||
141 | r#" | ||
142 | fn foo(<|>x: i32, y: i32) { y; } | ||
143 | fn a() { foo(1, 2) } | ||
144 | fn b() { foo(1, 2,) } | ||
145 | "#, | ||
146 | r#" | ||
147 | fn foo(y: i32) { y; } | ||
148 | fn a() { foo(2) } | ||
149 | fn b() { foo(2,) } | ||
150 | "#, | ||
151 | ); | ||
152 | } | ||
153 | |||
154 | #[test] | ||
155 | fn remove_unused_single_param() { | ||
156 | check_assist( | ||
157 | remove_unused_param, | ||
158 | r#" | ||
159 | fn foo(<|>x: i32) { 0; } | ||
160 | fn a() { foo(1) } | ||
161 | fn b() { foo(1, ) } | ||
162 | "#, | ||
163 | r#" | ||
164 | fn foo() { 0; } | ||
165 | fn a() { foo() } | ||
166 | fn b() { foo( ) } | ||
167 | "#, | ||
168 | ); | ||
169 | } | ||
170 | |||
171 | #[test] | ||
172 | fn remove_unused_surrounded_by_parms() { | ||
173 | check_assist( | ||
174 | remove_unused_param, | ||
175 | r#" | ||
176 | fn foo(x: i32, <|>y: i32, z: i32) { x; } | ||
177 | fn a() { foo(1, 2, 3) } | ||
178 | fn b() { foo(1, 2, 3,) } | ||
179 | "#, | ||
180 | r#" | ||
181 | fn foo(x: i32, z: i32) { x; } | ||
182 | fn a() { foo(1, 3) } | ||
183 | fn b() { foo(1, 3,) } | ||
184 | "#, | ||
185 | ); | ||
186 | } | ||
187 | |||
188 | #[test] | ||
122 | fn remove_unused_qualified_call() { | 189 | fn remove_unused_qualified_call() { |
123 | check_assist( | 190 | check_assist( |
124 | remove_unused_param, | 191 | remove_unused_param, |
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs index 6e736ccb3..6b89b2d04 100644 --- a/crates/assists/src/lib.rs +++ b/crates/assists/src/lib.rs | |||
@@ -129,6 +129,7 @@ mod handlers { | |||
129 | mod convert_integer_literal; | 129 | mod convert_integer_literal; |
130 | mod early_return; | 130 | mod early_return; |
131 | mod expand_glob_import; | 131 | mod expand_glob_import; |
132 | mod extract_module_to_file; | ||
132 | mod extract_struct_from_enum_variant; | 133 | mod extract_struct_from_enum_variant; |
133 | mod extract_variable; | 134 | mod extract_variable; |
134 | mod fill_match_arms; | 135 | mod fill_match_arms; |
@@ -179,6 +180,7 @@ mod handlers { | |||
179 | convert_integer_literal::convert_integer_literal, | 180 | convert_integer_literal::convert_integer_literal, |
180 | early_return::convert_to_guarded_return, | 181 | early_return::convert_to_guarded_return, |
181 | expand_glob_import::expand_glob_import, | 182 | expand_glob_import::expand_glob_import, |
183 | extract_module_to_file::extract_module_to_file, | ||
182 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, | 184 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, |
183 | extract_variable::extract_variable, | 185 | extract_variable::extract_variable, |
184 | fill_match_arms::fill_match_arms, | 186 | fill_match_arms::fill_match_arms, |
diff --git a/crates/assists/src/tests.rs b/crates/assists/src/tests.rs index 709a34d03..b41f4874a 100644 --- a/crates/assists/src/tests.rs +++ b/crates/assists/src/tests.rs | |||
@@ -2,6 +2,7 @@ mod generated; | |||
2 | 2 | ||
3 | use hir::Semantics; | 3 | use hir::Semantics; |
4 | use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; | 4 | use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; |
5 | use ide_db::source_change::FileSystemEdit; | ||
5 | use ide_db::RootDatabase; | 6 | use ide_db::RootDatabase; |
6 | use syntax::TextRange; | 7 | use syntax::TextRange; |
7 | use test_utils::{assert_eq_text, extract_offset, extract_range}; | 8 | use test_utils::{assert_eq_text, extract_offset, extract_range}; |
@@ -47,7 +48,7 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) { | |||
47 | let before = db.file_text(file_id).to_string(); | 48 | let before = db.file_text(file_id).to_string(); |
48 | let frange = FileRange { file_id, range: selection.into() }; | 49 | let frange = FileRange { file_id, range: selection.into() }; |
49 | 50 | ||
50 | let mut assist = Assist::resolved(&db, &AssistConfig::default(), frange) | 51 | let assist = Assist::resolved(&db, &AssistConfig::default(), frange) |
51 | .into_iter() | 52 | .into_iter() |
52 | .find(|assist| assist.assist.id.0 == assist_id) | 53 | .find(|assist| assist.assist.id.0 == assist_id) |
53 | .unwrap_or_else(|| { | 54 | .unwrap_or_else(|| { |
@@ -63,9 +64,12 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) { | |||
63 | }); | 64 | }); |
64 | 65 | ||
65 | let actual = { | 66 | let actual = { |
66 | let change = assist.source_change.source_file_edits.pop().unwrap(); | ||
67 | let mut actual = before; | 67 | let mut actual = before; |
68 | change.edit.apply(&mut actual); | 68 | for source_file_edit in assist.source_change.source_file_edits { |
69 | if source_file_edit.file_id == file_id { | ||
70 | source_file_edit.edit.apply(&mut actual) | ||
71 | } | ||
72 | } | ||
69 | actual | 73 | actual |
70 | }; | 74 | }; |
71 | assert_eq_text!(&after, &actual); | 75 | assert_eq_text!(&after, &actual); |
@@ -99,7 +103,8 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label: | |||
99 | (Some(assist), ExpectedResult::After(after)) => { | 103 | (Some(assist), ExpectedResult::After(after)) => { |
100 | let mut source_change = assist.source_change; | 104 | let mut source_change = assist.source_change; |
101 | assert!(!source_change.source_file_edits.is_empty()); | 105 | assert!(!source_change.source_file_edits.is_empty()); |
102 | let skip_header = source_change.source_file_edits.len() == 1; | 106 | let skip_header = source_change.source_file_edits.len() == 1 |
107 | && source_change.file_system_edits.len() == 0; | ||
103 | source_change.source_file_edits.sort_by_key(|it| it.file_id); | 108 | source_change.source_file_edits.sort_by_key(|it| it.file_id); |
104 | 109 | ||
105 | let mut buf = String::new(); | 110 | let mut buf = String::new(); |
@@ -115,6 +120,21 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label: | |||
115 | buf.push_str(&text); | 120 | buf.push_str(&text); |
116 | } | 121 | } |
117 | 122 | ||
123 | for file_system_edit in source_change.file_system_edits.clone() { | ||
124 | match file_system_edit { | ||
125 | FileSystemEdit::CreateFile { dst, initial_contents } => { | ||
126 | let sr = db.file_source_root(dst.anchor); | ||
127 | let sr = db.source_root(sr); | ||
128 | let mut base = sr.path_for_file(&dst.anchor).unwrap().clone(); | ||
129 | base.pop(); | ||
130 | let created_file_path = format!("{}{}", base.to_string(), &dst.path[1..]); | ||
131 | format_to!(buf, "//- {}\n", created_file_path); | ||
132 | buf.push_str(&initial_contents); | ||
133 | } | ||
134 | _ => (), | ||
135 | } | ||
136 | } | ||
137 | |||
118 | assert_eq_text!(after, &buf); | 138 | assert_eq_text!(after, &buf); |
119 | } | 139 | } |
120 | (Some(assist), ExpectedResult::Target(target)) => { | 140 | (Some(assist), ExpectedResult::Target(target)) => { |
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs index cc7c4a343..e9093ec53 100644 --- a/crates/assists/src/tests/generated.rs +++ b/crates/assists/src/tests/generated.rs | |||
@@ -236,6 +236,21 @@ fn qux(bar: Bar, baz: Baz) {} | |||
236 | } | 236 | } |
237 | 237 | ||
238 | #[test] | 238 | #[test] |
239 | fn doctest_extract_module_to_file() { | ||
240 | check_doc_test( | ||
241 | "extract_module_to_file", | ||
242 | r#####" | ||
243 | mod foo {<|> | ||
244 | fn t() {} | ||
245 | } | ||
246 | "#####, | ||
247 | r#####" | ||
248 | mod foo; | ||
249 | "#####, | ||
250 | ) | ||
251 | } | ||
252 | |||
253 | #[test] | ||
239 | fn doctest_extract_struct_from_enum_variant() { | 254 | fn doctest_extract_struct_from_enum_variant() { |
240 | check_doc_test( | 255 | check_doc_test( |
241 | "extract_struct_from_enum_variant", | 256 | "extract_struct_from_enum_variant", |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index f2cacf7c8..d41084b59 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -232,7 +232,13 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> { | |||
232 | }; | 232 | }; |
233 | Some(make::expr_method_call(receiver, method, arg_list)) | 233 | Some(make::expr_method_call(receiver, method, arg_list)) |
234 | } | 234 | } |
235 | ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => pe.expr(), | 235 | ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => { |
236 | if let ast::Expr::ParenExpr(parexpr) = pe.expr()? { | ||
237 | parexpr.expr() | ||
238 | } else { | ||
239 | pe.expr() | ||
240 | } | ||
241 | } | ||
236 | // FIXME: | 242 | // FIXME: |
237 | // ast::Expr::Literal(true | false ) | 243 | // ast::Expr::Literal(true | false ) |
238 | _ => None, | 244 | _ => None, |
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index 1ef6b5f48..d9fe13485 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs | |||
@@ -19,9 +19,14 @@ use hir::{ModPath, ScopeDef, Type}; | |||
19 | use crate::{ | 19 | use crate::{ |
20 | item::Builder, | 20 | item::Builder, |
21 | render::{ | 21 | render::{ |
22 | const_::render_const, enum_variant::render_variant, function::render_fn, | 22 | const_::render_const, |
23 | macro_::render_macro, render_field, render_resolution, render_tuple_field, | 23 | enum_variant::render_variant, |
24 | type_alias::render_type_alias, RenderContext, | 24 | function::render_fn, |
25 | macro_::render_macro, | ||
26 | pattern::{render_struct_pat, render_variant_pat}, | ||
27 | render_field, render_resolution, render_tuple_field, | ||
28 | type_alias::render_type_alias, | ||
29 | RenderContext, | ||
25 | }, | 30 | }, |
26 | CompletionContext, CompletionItem, | 31 | CompletionContext, CompletionItem, |
27 | }; | 32 | }; |
@@ -105,6 +110,28 @@ impl Completions { | |||
105 | self.add(item) | 110 | self.add(item) |
106 | } | 111 | } |
107 | 112 | ||
113 | pub(crate) fn add_variant_pat( | ||
114 | &mut self, | ||
115 | ctx: &CompletionContext, | ||
116 | variant: hir::Variant, | ||
117 | local_name: Option<hir::Name>, | ||
118 | ) { | ||
119 | if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, local_name) { | ||
120 | self.add(item); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | pub(crate) fn add_struct_pat( | ||
125 | &mut self, | ||
126 | ctx: &CompletionContext, | ||
127 | strukt: hir::Struct, | ||
128 | local_name: Option<hir::Name>, | ||
129 | ) { | ||
130 | if let Some(item) = render_struct_pat(RenderContext::new(ctx), strukt, local_name) { | ||
131 | self.add(item); | ||
132 | } | ||
133 | } | ||
134 | |||
108 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { | 135 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { |
109 | if let Some(item) = render_const(RenderContext::new(ctx), constant) { | 136 | if let Some(item) = render_const(RenderContext::new(ctx), constant) { |
110 | self.add(item); | 137 | self.add(item); |
diff --git a/crates/completion/src/completions/pattern.rs b/crates/completion/src/completions/pattern.rs index 4d56731ec..eee31098d 100644 --- a/crates/completion/src/completions/pattern.rs +++ b/crates/completion/src/completions/pattern.rs | |||
@@ -2,9 +2,9 @@ | |||
2 | 2 | ||
3 | use crate::{CompletionContext, Completions}; | 3 | use crate::{CompletionContext, Completions}; |
4 | 4 | ||
5 | /// Completes constats and paths in patterns. | 5 | /// Completes constants and paths in patterns. |
6 | pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | 6 | pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { |
7 | if !(ctx.is_pat_binding_or_const || ctx.is_irrefutable_let_pat_binding) { | 7 | if !(ctx.is_pat_binding_or_const || ctx.is_irrefutable_pat_binding) { |
8 | return; | 8 | return; |
9 | } | 9 | } |
10 | if ctx.record_pat_syntax.is_some() { | 10 | if ctx.record_pat_syntax.is_some() { |
@@ -15,20 +15,21 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
15 | // suggest variants + auto-imports | 15 | // suggest variants + auto-imports |
16 | ctx.scope.process_all_names(&mut |name, res| { | 16 | ctx.scope.process_all_names(&mut |name, res| { |
17 | let add_resolution = match &res { | 17 | let add_resolution = match &res { |
18 | hir::ScopeDef::ModuleDef(def) => { | 18 | hir::ScopeDef::ModuleDef(def) => match def { |
19 | if ctx.is_irrefutable_let_pat_binding { | 19 | hir::ModuleDef::Adt(hir::Adt::Struct(strukt)) => { |
20 | matches!(def, hir::ModuleDef::Adt(hir::Adt::Struct(_))) | 20 | acc.add_struct_pat(ctx, strukt.clone(), Some(name.clone())); |
21 | } else { | 21 | true |
22 | matches!( | ||
23 | def, | ||
24 | hir::ModuleDef::Adt(hir::Adt::Enum(..)) | ||
25 | | hir::ModuleDef::Adt(hir::Adt::Struct(..)) | ||
26 | | hir::ModuleDef::Variant(..) | ||
27 | | hir::ModuleDef::Const(..) | ||
28 | | hir::ModuleDef::Module(..) | ||
29 | ) | ||
30 | } | 22 | } |
31 | } | 23 | hir::ModuleDef::Variant(variant) if !ctx.is_irrefutable_pat_binding => { |
24 | acc.add_variant_pat(ctx, variant.clone(), Some(name.clone())); | ||
25 | true | ||
26 | } | ||
27 | hir::ModuleDef::Adt(hir::Adt::Enum(..)) | ||
28 | | hir::ModuleDef::Variant(..) | ||
29 | | hir::ModuleDef::Const(..) | ||
30 | | hir::ModuleDef::Module(..) => !ctx.is_irrefutable_pat_binding, | ||
31 | _ => false, | ||
32 | }, | ||
32 | hir::ScopeDef::MacroDef(_) => true, | 33 | hir::ScopeDef::MacroDef(_) => true, |
33 | _ => false, | 34 | _ => false, |
34 | }; | 35 | }; |
@@ -42,13 +43,21 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { | |||
42 | mod tests { | 43 | mod tests { |
43 | use expect_test::{expect, Expect}; | 44 | use expect_test::{expect, Expect}; |
44 | 45 | ||
45 | use crate::{test_utils::completion_list, CompletionKind}; | 46 | use crate::{ |
47 | test_utils::{check_edit, completion_list}, | ||
48 | CompletionKind, | ||
49 | }; | ||
46 | 50 | ||
47 | fn check(ra_fixture: &str, expect: Expect) { | 51 | fn check(ra_fixture: &str, expect: Expect) { |
48 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | 52 | let actual = completion_list(ra_fixture, CompletionKind::Reference); |
49 | expect.assert_eq(&actual) | 53 | expect.assert_eq(&actual) |
50 | } | 54 | } |
51 | 55 | ||
56 | fn check_snippet(ra_fixture: &str, expect: Expect) { | ||
57 | let actual = completion_list(ra_fixture, CompletionKind::Snippet); | ||
58 | expect.assert_eq(&actual) | ||
59 | } | ||
60 | |||
52 | #[test] | 61 | #[test] |
53 | fn completes_enum_variants_and_modules() { | 62 | fn completes_enum_variants_and_modules() { |
54 | check( | 63 | check( |
@@ -69,7 +78,7 @@ fn foo() { | |||
69 | en E | 78 | en E |
70 | ct Z | 79 | ct Z |
71 | st Bar | 80 | st Bar |
72 | ev X () | 81 | ev X |
73 | md m | 82 | md m |
74 | "#]], | 83 | "#]], |
75 | ); | 84 | ); |
@@ -114,4 +123,139 @@ fn foo() { | |||
114 | "#]], | 123 | "#]], |
115 | ); | 124 | ); |
116 | } | 125 | } |
126 | |||
127 | #[test] | ||
128 | fn completes_in_param() { | ||
129 | check( | ||
130 | r#" | ||
131 | enum E { X } | ||
132 | |||
133 | static FOO: E = E::X; | ||
134 | struct Bar { f: u32 } | ||
135 | |||
136 | fn foo(<|>) { | ||
137 | } | ||
138 | "#, | ||
139 | expect![[r#" | ||
140 | st Bar | ||
141 | "#]], | ||
142 | ); | ||
143 | } | ||
144 | |||
145 | #[test] | ||
146 | fn completes_pat_in_let() { | ||
147 | check_snippet( | ||
148 | r#" | ||
149 | struct Bar { f: u32 } | ||
150 | |||
151 | fn foo() { | ||
152 | let <|> | ||
153 | } | ||
154 | "#, | ||
155 | expect![[r#" | ||
156 | bn Bar Bar { f$1 }$0 | ||
157 | "#]], | ||
158 | ); | ||
159 | } | ||
160 | |||
161 | #[test] | ||
162 | fn completes_param_pattern() { | ||
163 | check_snippet( | ||
164 | r#" | ||
165 | struct Foo { bar: String, baz: String } | ||
166 | struct Bar(String, String); | ||
167 | struct Baz; | ||
168 | fn outer(<|>) {} | ||
169 | "#, | ||
170 | expect![[r#" | ||
171 | bn Foo Foo { bar$1, baz$2 }: Foo$0 | ||
172 | bn Bar Bar($1, $2): Bar$0 | ||
173 | "#]], | ||
174 | ) | ||
175 | } | ||
176 | |||
177 | #[test] | ||
178 | fn completes_let_pattern() { | ||
179 | check_snippet( | ||
180 | r#" | ||
181 | struct Foo { bar: String, baz: String } | ||
182 | struct Bar(String, String); | ||
183 | struct Baz; | ||
184 | fn outer() { | ||
185 | let <|> | ||
186 | } | ||
187 | "#, | ||
188 | expect![[r#" | ||
189 | bn Foo Foo { bar$1, baz$2 }$0 | ||
190 | bn Bar Bar($1, $2)$0 | ||
191 | "#]], | ||
192 | ) | ||
193 | } | ||
194 | |||
195 | #[test] | ||
196 | fn completes_refutable_pattern() { | ||
197 | check_snippet( | ||
198 | r#" | ||
199 | struct Foo { bar: i32, baz: i32 } | ||
200 | struct Bar(String, String); | ||
201 | struct Baz; | ||
202 | fn outer() { | ||
203 | match () { | ||
204 | <|> | ||
205 | } | ||
206 | } | ||
207 | "#, | ||
208 | expect![[r#" | ||
209 | bn Foo Foo { bar$1, baz$2 }$0 | ||
210 | bn Bar Bar($1, $2)$0 | ||
211 | "#]], | ||
212 | ) | ||
213 | } | ||
214 | |||
215 | #[test] | ||
216 | fn omits_private_fields_pat() { | ||
217 | check_snippet( | ||
218 | r#" | ||
219 | mod foo { | ||
220 | pub struct Foo { pub bar: i32, baz: i32 } | ||
221 | pub struct Bar(pub String, String); | ||
222 | pub struct Invisible(String, String); | ||
223 | } | ||
224 | use foo::*; | ||
225 | |||
226 | fn outer() { | ||
227 | match () { | ||
228 | <|> | ||
229 | } | ||
230 | } | ||
231 | "#, | ||
232 | expect![[r#" | ||
233 | bn Foo Foo { bar$1, .. }$0 | ||
234 | bn Bar Bar($1, ..)$0 | ||
235 | "#]], | ||
236 | ) | ||
237 | } | ||
238 | |||
239 | #[test] | ||
240 | fn only_shows_ident_completion() { | ||
241 | check_edit( | ||
242 | "Foo", | ||
243 | r#" | ||
244 | struct Foo(i32); | ||
245 | fn main() { | ||
246 | match Foo(92) { | ||
247 | <|>(92) => (), | ||
248 | } | ||
249 | } | ||
250 | "#, | ||
251 | r#" | ||
252 | struct Foo(i32); | ||
253 | fn main() { | ||
254 | match Foo(92) { | ||
255 | Foo(92) => (), | ||
256 | } | ||
257 | } | ||
258 | "#, | ||
259 | ); | ||
260 | } | ||
117 | } | 261 | } |
diff --git a/crates/completion/src/context.rs b/crates/completion/src/context.rs index 5cd11cf77..41de324d8 100644 --- a/crates/completion/src/context.rs +++ b/crates/completion/src/context.rs | |||
@@ -51,7 +51,7 @@ pub(crate) struct CompletionContext<'a> { | |||
51 | /// If a name-binding or reference to a const in a pattern. | 51 | /// If a name-binding or reference to a const in a pattern. |
52 | /// Irrefutable patterns (like let) are excluded. | 52 | /// Irrefutable patterns (like let) are excluded. |
53 | pub(super) is_pat_binding_or_const: bool, | 53 | pub(super) is_pat_binding_or_const: bool, |
54 | pub(super) is_irrefutable_let_pat_binding: bool, | 54 | pub(super) is_irrefutable_pat_binding: bool, |
55 | /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. | 55 | /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. |
56 | pub(super) is_trivial_path: bool, | 56 | pub(super) is_trivial_path: bool, |
57 | /// If not a trivial path, the prefix (qualifier). | 57 | /// If not a trivial path, the prefix (qualifier). |
@@ -147,7 +147,7 @@ impl<'a> CompletionContext<'a> { | |||
147 | active_parameter: ActiveParameter::at(db, position), | 147 | active_parameter: ActiveParameter::at(db, position), |
148 | is_param: false, | 148 | is_param: false, |
149 | is_pat_binding_or_const: false, | 149 | is_pat_binding_or_const: false, |
150 | is_irrefutable_let_pat_binding: false, | 150 | is_irrefutable_pat_binding: false, |
151 | is_trivial_path: false, | 151 | is_trivial_path: false, |
152 | path_qual: None, | 152 | path_qual: None, |
153 | after_if: false, | 153 | after_if: false, |
@@ -327,14 +327,19 @@ impl<'a> CompletionContext<'a> { | |||
327 | if bind_pat.syntax().parent().and_then(ast::RecordPatFieldList::cast).is_some() { | 327 | if bind_pat.syntax().parent().and_then(ast::RecordPatFieldList::cast).is_some() { |
328 | self.is_pat_binding_or_const = false; | 328 | self.is_pat_binding_or_const = false; |
329 | } | 329 | } |
330 | if let Some(let_stmt) = bind_pat.syntax().ancestors().find_map(ast::LetStmt::cast) { | 330 | if let Some(Some(pat)) = bind_pat.syntax().ancestors().find_map(|node| { |
331 | if let Some(pat) = let_stmt.pat() { | 331 | match_ast! { |
332 | if pat.syntax().text_range().contains_range(bind_pat.syntax().text_range()) | 332 | match node { |
333 | { | 333 | ast::LetStmt(it) => Some(it.pat()), |
334 | self.is_pat_binding_or_const = false; | 334 | ast::Param(it) => Some(it.pat()), |
335 | self.is_irrefutable_let_pat_binding = true; | 335 | _ => None, |
336 | } | 336 | } |
337 | } | 337 | } |
338 | }) { | ||
339 | if pat.syntax().text_range().contains_range(bind_pat.syntax().text_range()) { | ||
340 | self.is_pat_binding_or_const = false; | ||
341 | self.is_irrefutable_pat_binding = true; | ||
342 | } | ||
338 | } | 343 | } |
339 | } | 344 | } |
340 | if is_node::<ast::Param>(name.syntax()) { | 345 | if is_node::<ast::Param>(name.syntax()) { |
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs index 1092a4825..1ba7201a1 100644 --- a/crates/completion/src/render.rs +++ b/crates/completion/src/render.rs | |||
@@ -5,6 +5,7 @@ pub(crate) mod macro_; | |||
5 | pub(crate) mod function; | 5 | pub(crate) mod function; |
6 | pub(crate) mod enum_variant; | 6 | pub(crate) mod enum_variant; |
7 | pub(crate) mod const_; | 7 | pub(crate) mod const_; |
8 | pub(crate) mod pattern; | ||
8 | pub(crate) mod type_alias; | 9 | pub(crate) mod type_alias; |
9 | 10 | ||
10 | mod builder_ext; | 11 | mod builder_ext; |
@@ -159,6 +160,12 @@ impl<'a> Render<'a> { | |||
159 | let item = render_fn(self.ctx, import_to_add, Some(local_name), *func); | 160 | let item = render_fn(self.ctx, import_to_add, Some(local_name), *func); |
160 | return Some(item); | 161 | return Some(item); |
161 | } | 162 | } |
163 | ScopeDef::ModuleDef(Variant(_)) | ||
164 | if self.ctx.completion.is_pat_binding_or_const | ||
165 | | self.ctx.completion.is_irrefutable_pat_binding => | ||
166 | { | ||
167 | CompletionItemKind::EnumVariant | ||
168 | } | ||
162 | ScopeDef::ModuleDef(Variant(var)) => { | 169 | ScopeDef::ModuleDef(Variant(var)) => { |
163 | let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); | 170 | let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); |
164 | return Some(item); | 171 | return Some(item); |
diff --git a/crates/completion/src/render/builder_ext.rs b/crates/completion/src/render/builder_ext.rs index ce8718bd5..d053a988b 100644 --- a/crates/completion/src/render/builder_ext.rs +++ b/crates/completion/src/render/builder_ext.rs | |||
@@ -34,7 +34,6 @@ impl Builder { | |||
34 | return false; | 34 | return false; |
35 | } | 35 | } |
36 | if ctx.is_pattern_call { | 36 | if ctx.is_pattern_call { |
37 | mark::hit!(dont_duplicate_pattern_parens); | ||
38 | return false; | 37 | return false; |
39 | } | 38 | } |
40 | if ctx.is_call { | 39 | if ctx.is_call { |
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs index 7176fd9b3..732e139ec 100644 --- a/crates/completion/src/render/enum_variant.rs +++ b/crates/completion/src/render/enum_variant.rs | |||
@@ -126,50 +126,5 @@ fn main() -> Option<i32> { | |||
126 | } | 126 | } |
127 | "#, | 127 | "#, |
128 | ); | 128 | ); |
129 | check_edit( | ||
130 | "Some", | ||
131 | r#" | ||
132 | enum Option<T> { Some(T), None } | ||
133 | use Option::*; | ||
134 | fn main(value: Option<i32>) { | ||
135 | match value { | ||
136 | Som<|> | ||
137 | } | ||
138 | } | ||
139 | "#, | ||
140 | r#" | ||
141 | enum Option<T> { Some(T), None } | ||
142 | use Option::*; | ||
143 | fn main(value: Option<i32>) { | ||
144 | match value { | ||
145 | Some($0) | ||
146 | } | ||
147 | } | ||
148 | "#, | ||
149 | ); | ||
150 | } | ||
151 | |||
152 | #[test] | ||
153 | fn dont_duplicate_pattern_parens() { | ||
154 | mark::check!(dont_duplicate_pattern_parens); | ||
155 | check_edit( | ||
156 | "Var", | ||
157 | r#" | ||
158 | enum E { Var(i32) } | ||
159 | fn main() { | ||
160 | match E::Var(92) { | ||
161 | E::<|>(92) => (), | ||
162 | } | ||
163 | } | ||
164 | "#, | ||
165 | r#" | ||
166 | enum E { Var(i32) } | ||
167 | fn main() { | ||
168 | match E::Var(92) { | ||
169 | E::Var(92) => (), | ||
170 | } | ||
171 | } | ||
172 | "#, | ||
173 | ); | ||
174 | } | 129 | } |
175 | } | 130 | } |
diff --git a/crates/completion/src/render/pattern.rs b/crates/completion/src/render/pattern.rs new file mode 100644 index 000000000..a3b6a3cac --- /dev/null +++ b/crates/completion/src/render/pattern.rs | |||
@@ -0,0 +1,148 @@ | |||
1 | //! Renderer for patterns. | ||
2 | |||
3 | use hir::{db::HirDatabase, HasAttrs, HasVisibility, Name, StructKind}; | ||
4 | use itertools::Itertools; | ||
5 | |||
6 | use crate::{ | ||
7 | config::SnippetCap, item::CompletionKind, render::RenderContext, CompletionItem, | ||
8 | CompletionItemKind, | ||
9 | }; | ||
10 | |||
11 | fn visible_fields( | ||
12 | ctx: &RenderContext<'_>, | ||
13 | fields: &[hir::Field], | ||
14 | item: impl HasAttrs, | ||
15 | ) -> Option<(Vec<hir::Field>, bool)> { | ||
16 | let module = ctx.completion.scope.module()?; | ||
17 | let n_fields = fields.len(); | ||
18 | let fields = fields | ||
19 | .into_iter() | ||
20 | .filter(|field| field.is_visible_from(ctx.db(), module)) | ||
21 | .copied() | ||
22 | .collect::<Vec<_>>(); | ||
23 | |||
24 | let fields_omitted = | ||
25 | n_fields - fields.len() > 0 || item.attrs(ctx.db()).by_key("non_exhaustive").exists(); | ||
26 | Some((fields, fields_omitted)) | ||
27 | } | ||
28 | |||
29 | pub(crate) fn render_struct_pat( | ||
30 | ctx: RenderContext<'_>, | ||
31 | strukt: hir::Struct, | ||
32 | local_name: Option<Name>, | ||
33 | ) -> Option<CompletionItem> { | ||
34 | let _p = profile::span("render_struct_pat"); | ||
35 | |||
36 | let fields = strukt.fields(ctx.db()); | ||
37 | let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, strukt)?; | ||
38 | |||
39 | if visible_fields.is_empty() { | ||
40 | // Matching a struct without matching its fields is pointless, unlike matching a Variant without its fields | ||
41 | return None; | ||
42 | } | ||
43 | |||
44 | let name = local_name.unwrap_or_else(|| strukt.name(ctx.db())).to_string(); | ||
45 | let pat = render_pat(&ctx, &name, strukt.kind(ctx.db()), &visible_fields, fields_omitted)?; | ||
46 | |||
47 | Some(build_completion(ctx, name, pat, strukt)) | ||
48 | } | ||
49 | |||
50 | pub(crate) fn render_variant_pat( | ||
51 | ctx: RenderContext<'_>, | ||
52 | variant: hir::Variant, | ||
53 | local_name: Option<Name>, | ||
54 | ) -> Option<CompletionItem> { | ||
55 | let _p = profile::span("render_variant_pat"); | ||
56 | |||
57 | let fields = variant.fields(ctx.db()); | ||
58 | let (visible_fields, fields_omitted) = visible_fields(&ctx, &fields, variant)?; | ||
59 | |||
60 | let name = local_name.unwrap_or_else(|| variant.name(ctx.db())).to_string(); | ||
61 | let pat = render_pat(&ctx, &name, variant.kind(ctx.db()), &visible_fields, fields_omitted)?; | ||
62 | |||
63 | Some(build_completion(ctx, name, pat, variant)) | ||
64 | } | ||
65 | |||
66 | fn build_completion( | ||
67 | ctx: RenderContext<'_>, | ||
68 | name: String, | ||
69 | pat: String, | ||
70 | item: impl HasAttrs + Copy, | ||
71 | ) -> CompletionItem { | ||
72 | let completion = CompletionItem::new(CompletionKind::Snippet, ctx.source_range(), name) | ||
73 | .kind(CompletionItemKind::Binding) | ||
74 | .set_documentation(ctx.docs(item)) | ||
75 | .set_deprecated(ctx.is_deprecated(item)) | ||
76 | .detail(&pat); | ||
77 | let completion = if let Some(snippet_cap) = ctx.snippet_cap() { | ||
78 | completion.insert_snippet(snippet_cap, pat) | ||
79 | } else { | ||
80 | completion.insert_text(pat) | ||
81 | }; | ||
82 | completion.build() | ||
83 | } | ||
84 | |||
85 | fn render_pat( | ||
86 | ctx: &RenderContext<'_>, | ||
87 | name: &str, | ||
88 | kind: StructKind, | ||
89 | fields: &[hir::Field], | ||
90 | fields_omitted: bool, | ||
91 | ) -> Option<String> { | ||
92 | let mut pat = match kind { | ||
93 | StructKind::Tuple if ctx.snippet_cap().is_some() => { | ||
94 | render_tuple_as_pat(&fields, &name, fields_omitted) | ||
95 | } | ||
96 | StructKind::Record => { | ||
97 | render_record_as_pat(ctx.db(), ctx.snippet_cap(), &fields, &name, fields_omitted) | ||
98 | } | ||
99 | _ => return None, | ||
100 | }; | ||
101 | |||
102 | if ctx.completion.is_param { | ||
103 | pat.push(':'); | ||
104 | pat.push(' '); | ||
105 | pat.push_str(&name); | ||
106 | } | ||
107 | if ctx.snippet_cap().is_some() { | ||
108 | pat.push_str("$0"); | ||
109 | } | ||
110 | Some(pat) | ||
111 | } | ||
112 | |||
113 | fn render_record_as_pat( | ||
114 | db: &dyn HirDatabase, | ||
115 | snippet_cap: Option<SnippetCap>, | ||
116 | fields: &[hir::Field], | ||
117 | name: &str, | ||
118 | fields_omitted: bool, | ||
119 | ) -> String { | ||
120 | let fields = fields.iter(); | ||
121 | if snippet_cap.is_some() { | ||
122 | format!( | ||
123 | "{name} {{ {}{} }}", | ||
124 | fields | ||
125 | .enumerate() | ||
126 | .map(|(idx, field)| format!("{}${}", field.name(db), idx + 1)) | ||
127 | .format(", "), | ||
128 | if fields_omitted { ", .." } else { "" }, | ||
129 | name = name | ||
130 | ) | ||
131 | } else { | ||
132 | format!( | ||
133 | "{name} {{ {}{} }}", | ||
134 | fields.map(|field| field.name(db)).format(", "), | ||
135 | if fields_omitted { ", .." } else { "" }, | ||
136 | name = name | ||
137 | ) | ||
138 | } | ||
139 | } | ||
140 | |||
141 | fn render_tuple_as_pat(fields: &[hir::Field], name: &str, fields_omitted: bool) -> String { | ||
142 | format!( | ||
143 | "{name}({}{})", | ||
144 | fields.iter().enumerate().map(|(idx, _)| format!("${}", idx + 1)).format(", "), | ||
145 | if fields_omitted { ", .." } else { "" }, | ||
146 | name = name | ||
147 | ) | ||
148 | } | ||
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index d6c7e71ea..1d7e5ddd7 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -511,6 +511,10 @@ impl Struct { | |||
511 | db.struct_data(self.id).repr.clone() | 511 | db.struct_data(self.id).repr.clone() |
512 | } | 512 | } |
513 | 513 | ||
514 | pub fn kind(self, db: &dyn HirDatabase) -> StructKind { | ||
515 | self.variant_data(db).kind() | ||
516 | } | ||
517 | |||
514 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { | 518 | fn variant_data(self, db: &dyn HirDatabase) -> Arc<VariantData> { |
515 | db.struct_data(self.id).variant_data.clone() | 519 | db.struct_data(self.id).variant_data.clone() |
516 | } | 520 | } |
@@ -1268,7 +1272,6 @@ impl LifetimeParam { | |||
1268 | } | 1272 | } |
1269 | } | 1273 | } |
1270 | 1274 | ||
1271 | // FIXME: rename from `ImplDef` to `Impl` | ||
1272 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 1275 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
1273 | pub struct Impl { | 1276 | pub struct Impl { |
1274 | pub(crate) id: ImplId, | 1277 | pub(crate) id: ImplId, |
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index 41134d23b..bb8fca009 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs | |||
@@ -62,6 +62,7 @@ pub struct GenericParams { | |||
62 | pub enum WherePredicate { | 62 | pub enum WherePredicate { |
63 | TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, | 63 | TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, |
64 | Lifetime { target: LifetimeRef, bound: LifetimeRef }, | 64 | Lifetime { target: LifetimeRef, bound: LifetimeRef }, |
65 | ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound }, | ||
65 | } | 66 | } |
66 | 67 | ||
67 | #[derive(Clone, PartialEq, Eq, Debug)] | 68 | #[derive(Clone, PartialEq, Eq, Debug)] |
@@ -69,7 +70,6 @@ pub enum WherePredicateTypeTarget { | |||
69 | TypeRef(TypeRef), | 70 | TypeRef(TypeRef), |
70 | /// For desugared where predicates that can directly refer to a type param. | 71 | /// For desugared where predicates that can directly refer to a type param. |
71 | TypeParam(LocalTypeParamId), | 72 | TypeParam(LocalTypeParamId), |
72 | // FIXME: ForLifetime(Vec<LifetimeParamId>, TypeRef) | ||
73 | } | 73 | } |
74 | 74 | ||
75 | #[derive(Default)] | 75 | #[derive(Default)] |
@@ -234,7 +234,7 @@ impl GenericParams { | |||
234 | for bound in | 234 | for bound in |
235 | node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) | 235 | node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) |
236 | { | 236 | { |
237 | self.add_where_predicate_from_bound(lower_ctx, bound, target.clone()); | 237 | self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone()); |
238 | } | 238 | } |
239 | } | 239 | } |
240 | 240 | ||
@@ -279,8 +279,25 @@ impl GenericParams { | |||
279 | } else { | 279 | } else { |
280 | continue; | 280 | continue; |
281 | }; | 281 | }; |
282 | |||
283 | let lifetimes: Option<Box<_>> = pred.generic_param_list().map(|param_list| { | ||
284 | // Higher-Ranked Trait Bounds | ||
285 | param_list | ||
286 | .lifetime_params() | ||
287 | .map(|lifetime_param| { | ||
288 | lifetime_param | ||
289 | .lifetime() | ||
290 | .map_or_else(Name::missing, |lt| Name::new_lifetime(<)) | ||
291 | }) | ||
292 | .collect() | ||
293 | }); | ||
282 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { | 294 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { |
283 | self.add_where_predicate_from_bound(lower_ctx, bound, target.clone()); | 295 | self.add_where_predicate_from_bound( |
296 | lower_ctx, | ||
297 | bound, | ||
298 | lifetimes.as_ref(), | ||
299 | target.clone(), | ||
300 | ); | ||
284 | } | 301 | } |
285 | } | 302 | } |
286 | } | 303 | } |
@@ -289,6 +306,7 @@ impl GenericParams { | |||
289 | &mut self, | 306 | &mut self, |
290 | lower_ctx: &LowerCtx, | 307 | lower_ctx: &LowerCtx, |
291 | bound: ast::TypeBound, | 308 | bound: ast::TypeBound, |
309 | hrtb_lifetimes: Option<&Box<[Name]>>, | ||
292 | target: Either<TypeRef, LifetimeRef>, | 310 | target: Either<TypeRef, LifetimeRef>, |
293 | ) { | 311 | ) { |
294 | if bound.question_mark_token().is_some() { | 312 | if bound.question_mark_token().is_some() { |
@@ -297,9 +315,16 @@ impl GenericParams { | |||
297 | } | 315 | } |
298 | let bound = TypeBound::from_ast(lower_ctx, bound); | 316 | let bound = TypeBound::from_ast(lower_ctx, bound); |
299 | let predicate = match (target, bound) { | 317 | let predicate = match (target, bound) { |
300 | (Either::Left(type_ref), bound) => WherePredicate::TypeBound { | 318 | (Either::Left(type_ref), bound) => match hrtb_lifetimes { |
301 | target: WherePredicateTypeTarget::TypeRef(type_ref), | 319 | Some(hrtb_lifetimes) => WherePredicate::ForLifetime { |
302 | bound, | 320 | lifetimes: hrtb_lifetimes.clone(), |
321 | target: WherePredicateTypeTarget::TypeRef(type_ref), | ||
322 | bound, | ||
323 | }, | ||
324 | None => WherePredicate::TypeBound { | ||
325 | target: WherePredicateTypeTarget::TypeRef(type_ref), | ||
326 | bound, | ||
327 | }, | ||
303 | }, | 328 | }, |
304 | (Either::Right(lifetime), TypeBound::Lifetime(bound)) => { | 329 | (Either::Right(lifetime), TypeBound::Lifetime(bound)) => { |
305 | WherePredicate::Lifetime { target: lifetime, bound } | 330 | WherePredicate::Lifetime { target: lifetime, bound } |
diff --git a/crates/hir_def/src/nameres/mod_resolution.rs b/crates/hir_def/src/nameres/mod_resolution.rs index b4ccd4488..af3262439 100644 --- a/crates/hir_def/src/nameres/mod_resolution.rs +++ b/crates/hir_def/src/nameres/mod_resolution.rs | |||
@@ -79,7 +79,7 @@ impl ModDir { | |||
79 | for candidate in candidate_files.iter() { | 79 | for candidate in candidate_files.iter() { |
80 | let path = AnchoredPath { anchor: file_id, path: candidate.as_str() }; | 80 | let path = AnchoredPath { anchor: file_id, path: candidate.as_str() }; |
81 | if let Some(file_id) = db.resolve_path(path) { | 81 | if let Some(file_id) = db.resolve_path(path) { |
82 | let is_mod_rs = candidate.ends_with("mod.rs"); | 82 | let is_mod_rs = candidate.ends_with("/mod.rs"); |
83 | 83 | ||
84 | let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() { | 84 | let (dir_path, root_non_dir_owner) = if is_mod_rs || attr_path.is_some() { |
85 | (DirPath::empty(), false) | 85 | (DirPath::empty(), false) |
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index dddbbcdac..6382521fb 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs | |||
@@ -563,6 +563,7 @@ mod tests { | |||
563 | 563 | ||
564 | let args = macro_call.token_tree().unwrap(); | 564 | let args = macro_call.token_tree().unwrap(); |
565 | let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0; | 565 | let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0; |
566 | let call_id = AstId::new(file_id.into(), ast_id_map.ast_id(¯o_call)); | ||
566 | 567 | ||
567 | let arg_id = db.intern_eager_expansion({ | 568 | let arg_id = db.intern_eager_expansion({ |
568 | EagerCallLoc { | 569 | EagerCallLoc { |
@@ -570,7 +571,7 @@ mod tests { | |||
570 | fragment: FragmentKind::Expr, | 571 | fragment: FragmentKind::Expr, |
571 | subtree: Arc::new(parsed_args.clone()), | 572 | subtree: Arc::new(parsed_args.clone()), |
572 | krate, | 573 | krate, |
573 | file_id: file_id.into(), | 574 | call: call_id, |
574 | } | 575 | } |
575 | }); | 576 | }); |
576 | 577 | ||
@@ -580,7 +581,7 @@ mod tests { | |||
580 | fragment, | 581 | fragment, |
581 | subtree: Arc::new(subtree), | 582 | subtree: Arc::new(subtree), |
582 | krate, | 583 | krate, |
583 | file_id: file_id.into(), | 584 | call: call_id, |
584 | }; | 585 | }; |
585 | 586 | ||
586 | let id: MacroCallId = db.intern_eager_expansion(eager).into(); | 587 | let id: MacroCallId = db.intern_eager_expansion(eager).into(); |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 4477d867f..077de3727 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -5,7 +5,7 @@ use std::sync::Arc; | |||
5 | use base_db::{salsa, SourceDatabase}; | 5 | use base_db::{salsa, SourceDatabase}; |
6 | use mbe::{ExpandError, ExpandResult, MacroRules}; | 6 | use mbe::{ExpandError, ExpandResult, MacroRules}; |
7 | use parser::FragmentKind; | 7 | use parser::FragmentKind; |
8 | use syntax::{algo::diff, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; | 8 | use syntax::{algo::diff, ast::NameOwner, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, | 11 | ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, |
@@ -129,11 +129,11 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> { | |||
129 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { | 129 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { |
130 | match id.kind { | 130 | match id.kind { |
131 | MacroDefKind::Declarative => { | 131 | MacroDefKind::Declarative => { |
132 | let macro_call = match id.ast_id?.to_node(db) { | 132 | let macro_rules = match id.ast_id?.to_node(db) { |
133 | syntax::ast::Macro::MacroRules(mac) => mac, | 133 | syntax::ast::Macro::MacroRules(mac) => mac, |
134 | syntax::ast::Macro::MacroDef(_) => return None, | 134 | syntax::ast::Macro::MacroDef(_) => return None, |
135 | }; | 135 | }; |
136 | let arg = macro_call.token_tree()?; | 136 | let arg = macro_rules.token_tree()?; |
137 | let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { | 137 | let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { |
138 | log::warn!("fail on macro_def to token tree: {:#?}", arg); | 138 | log::warn!("fail on macro_def to token tree: {:#?}", arg); |
139 | None | 139 | None |
@@ -141,7 +141,8 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, | |||
141 | let rules = match MacroRules::parse(&tt) { | 141 | let rules = match MacroRules::parse(&tt) { |
142 | Ok(it) => it, | 142 | Ok(it) => it, |
143 | Err(err) => { | 143 | Err(err) => { |
144 | log::warn!("fail on macro_def parse: error: {:#?} {:#?}", err, tt); | 144 | let name = macro_rules.name().map(|n| n.to_string()).unwrap_or_default(); |
145 | log::warn!("fail on macro_def parse ({}): {:?} {:#?}", name, err, tt); | ||
145 | return None; | 146 | return None; |
146 | } | 147 | } |
147 | }; | 148 | }; |
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index 0229a836e..6354b090d 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs | |||
@@ -110,6 +110,9 @@ pub fn expand_eager_macro( | |||
110 | || err("malformed macro invocation"), | 110 | || err("malformed macro invocation"), |
111 | )?; | 111 | )?; |
112 | 112 | ||
113 | let ast_map = db.ast_id_map(macro_call.file_id); | ||
114 | let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(¯o_call.value)); | ||
115 | |||
113 | // Note: | 116 | // Note: |
114 | // When `lazy_expand` is called, its *parent* file must be already exists. | 117 | // When `lazy_expand` is called, its *parent* file must be already exists. |
115 | // Here we store an eager macro id for the argument expanded subtree here | 118 | // Here we store an eager macro id for the argument expanded subtree here |
@@ -120,7 +123,7 @@ pub fn expand_eager_macro( | |||
120 | fragment: FragmentKind::Expr, | 123 | fragment: FragmentKind::Expr, |
121 | subtree: Arc::new(parsed_args.clone()), | 124 | subtree: Arc::new(parsed_args.clone()), |
122 | krate, | 125 | krate, |
123 | file_id: macro_call.file_id, | 126 | call: call_id, |
124 | } | 127 | } |
125 | }); | 128 | }); |
126 | let arg_file_id: MacroCallId = arg_id.into(); | 129 | let arg_file_id: MacroCallId = arg_id.into(); |
@@ -141,13 +144,8 @@ pub fn expand_eager_macro( | |||
141 | let res = eager.expand(db, arg_id, &subtree); | 144 | let res = eager.expand(db, arg_id, &subtree); |
142 | 145 | ||
143 | let (subtree, fragment) = diagnostic_sink.expand_result_option(res)?; | 146 | let (subtree, fragment) = diagnostic_sink.expand_result_option(res)?; |
144 | let eager = EagerCallLoc { | 147 | let eager = |
145 | def, | 148 | EagerCallLoc { def, fragment, subtree: Arc::new(subtree), krate, call: call_id }; |
146 | fragment, | ||
147 | subtree: Arc::new(subtree), | ||
148 | krate, | ||
149 | file_id: macro_call.file_id, | ||
150 | }; | ||
151 | 149 | ||
152 | Ok(db.intern_eager_expansion(eager)) | 150 | Ok(db.intern_eager_expansion(eager)) |
153 | } else { | 151 | } else { |
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index d486186e5..3fa1b1d77 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -83,7 +83,7 @@ impl HirFileId { | |||
83 | } | 83 | } |
84 | MacroCallId::EagerMacro(id) => { | 84 | MacroCallId::EagerMacro(id) => { |
85 | let loc = db.lookup_intern_eager_expansion(id); | 85 | let loc = db.lookup_intern_eager_expansion(id); |
86 | loc.file_id | 86 | loc.call.file_id |
87 | } | 87 | } |
88 | }; | 88 | }; |
89 | file_id.original_file(db) | 89 | file_id.original_file(db) |
@@ -103,7 +103,7 @@ impl HirFileId { | |||
103 | } | 103 | } |
104 | MacroCallId::EagerMacro(id) => { | 104 | MacroCallId::EagerMacro(id) => { |
105 | let loc = db.lookup_intern_eager_expansion(id); | 105 | let loc = db.lookup_intern_eager_expansion(id); |
106 | loc.file_id | 106 | loc.call.file_id |
107 | } | 107 | } |
108 | }; | 108 | }; |
109 | } | 109 | } |
@@ -114,17 +114,16 @@ impl HirFileId { | |||
114 | pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> { | 114 | pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> { |
115 | match self.0 { | 115 | match self.0 { |
116 | HirFileIdRepr::FileId(_) => None, | 116 | HirFileIdRepr::FileId(_) => None, |
117 | HirFileIdRepr::MacroFile(macro_file) => { | 117 | HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id { |
118 | let lazy_id = match macro_file.macro_call_id { | 118 | MacroCallId::LazyMacro(lazy_id) => { |
119 | MacroCallId::LazyMacro(id) => id, | 119 | let loc: MacroCallLoc = db.lookup_intern_macro(lazy_id); |
120 | MacroCallId::EagerMacro(_id) => { | 120 | Some(loc.kind.node(db)) |
121 | // FIXME: handle call node for eager macro | 121 | } |
122 | return None; | 122 | MacroCallId::EagerMacro(id) => { |
123 | } | 123 | let loc: EagerCallLoc = db.lookup_intern_eager_expansion(id); |
124 | }; | 124 | Some(loc.call.with_value(loc.call.to_node(db).syntax().clone())) |
125 | let loc = db.lookup_intern_macro(lazy_id); | 125 | } |
126 | Some(loc.kind.node(db)) | 126 | }, |
127 | } | ||
128 | } | 127 | } |
129 | } | 128 | } |
130 | 129 | ||
@@ -304,7 +303,7 @@ pub struct EagerCallLoc { | |||
304 | pub(crate) fragment: FragmentKind, | 303 | pub(crate) fragment: FragmentKind, |
305 | pub(crate) subtree: Arc<tt::Subtree>, | 304 | pub(crate) subtree: Arc<tt::Subtree>, |
306 | pub(crate) krate: CrateId, | 305 | pub(crate) krate: CrateId, |
307 | pub(crate) file_id: HirFileId, | 306 | pub(crate) call: AstId<ast::MacroCall>, |
308 | } | 307 | } |
309 | 308 | ||
310 | /// ExpansionInfo mainly describes how to map text range between src and expanded macro | 309 | /// ExpansionInfo mainly describes how to map text range between src and expanded macro |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 8392cb770..8da56cd11 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -675,7 +675,8 @@ impl GenericPredicate { | |||
675 | where_predicate: &'a WherePredicate, | 675 | where_predicate: &'a WherePredicate, |
676 | ) -> impl Iterator<Item = GenericPredicate> + 'a { | 676 | ) -> impl Iterator<Item = GenericPredicate> + 'a { |
677 | match where_predicate { | 677 | match where_predicate { |
678 | WherePredicate::TypeBound { target, bound } => { | 678 | WherePredicate::ForLifetime { target, bound, .. } |
679 | | WherePredicate::TypeBound { target, bound } => { | ||
679 | let self_ty = match target { | 680 | let self_ty = match target { |
680 | WherePredicateTypeTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref), | 681 | WherePredicateTypeTarget::TypeRef(type_ref) => Ty::from_hir(ctx, type_ref), |
681 | WherePredicateTypeTarget::TypeParam(param_id) => { | 682 | WherePredicateTypeTarget::TypeParam(param_id) => { |
@@ -888,14 +889,13 @@ pub(crate) fn generic_predicates_for_param_query( | |||
888 | .where_predicates_in_scope() | 889 | .where_predicates_in_scope() |
889 | // we have to filter out all other predicates *first*, before attempting to lower them | 890 | // we have to filter out all other predicates *first*, before attempting to lower them |
890 | .filter(|pred| match pred { | 891 | .filter(|pred| match pred { |
891 | WherePredicate::TypeBound { | 892 | WherePredicate::ForLifetime { target, .. } |
892 | target: WherePredicateTypeTarget::TypeRef(type_ref), | 893 | | WherePredicate::TypeBound { target, .. } => match target { |
893 | .. | 894 | WherePredicateTypeTarget::TypeRef(type_ref) => { |
894 | } => Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id), | 895 | Ty::from_hir_only_param(&ctx, type_ref) == Some(param_id) |
895 | WherePredicate::TypeBound { | 896 | } |
896 | target: WherePredicateTypeTarget::TypeParam(local_id), | 897 | WherePredicateTypeTarget::TypeParam(local_id) => *local_id == param_id.local_id, |
897 | .. | 898 | }, |
898 | } => *local_id == param_id.local_id, | ||
899 | WherePredicate::Lifetime { .. } => false, | 899 | WherePredicate::Lifetime { .. } => false, |
900 | }) | 900 | }) |
901 | .flat_map(|pred| { | 901 | .flat_map(|pred| { |
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs index af880c065..65b79df0d 100644 --- a/crates/hir_ty/src/utils.rs +++ b/crates/hir_ty/src/utils.rs | |||
@@ -5,7 +5,9 @@ use std::sync::Arc; | |||
5 | use hir_def::{ | 5 | use hir_def::{ |
6 | adt::VariantData, | 6 | adt::VariantData, |
7 | db::DefDatabase, | 7 | db::DefDatabase, |
8 | generics::{GenericParams, TypeParamData, TypeParamProvenance, WherePredicateTypeTarget}, | 8 | generics::{ |
9 | GenericParams, TypeParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, | ||
10 | }, | ||
9 | path::Path, | 11 | path::Path, |
10 | resolver::{HasResolver, TypeNs}, | 12 | resolver::{HasResolver, TypeNs}, |
11 | type_ref::TypeRef, | 13 | type_ref::TypeRef, |
@@ -27,7 +29,8 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | |||
27 | .where_predicates | 29 | .where_predicates |
28 | .iter() | 30 | .iter() |
29 | .filter_map(|pred| match pred { | 31 | .filter_map(|pred| match pred { |
30 | hir_def::generics::WherePredicate::TypeBound { target, bound } => match target { | 32 | WherePredicate::ForLifetime { target, bound, .. } |
33 | | WherePredicate::TypeBound { target, bound } => match target { | ||
31 | WherePredicateTypeTarget::TypeRef(TypeRef::Path(p)) | 34 | WherePredicateTypeTarget::TypeRef(TypeRef::Path(p)) |
32 | if p == &Path::from(name![Self]) => | 35 | if p == &Path::from(name![Self]) => |
33 | { | 36 | { |
@@ -38,7 +41,7 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { | |||
38 | } | 41 | } |
39 | _ => None, | 42 | _ => None, |
40 | }, | 43 | }, |
41 | hir_def::generics::WherePredicate::Lifetime { .. } => None, | 44 | WherePredicate::Lifetime { .. } => None, |
42 | }) | 45 | }) |
43 | .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { | 46 | .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { |
44 | Some(TypeNs::TraitId(t)) => Some(t), | 47 | Some(TypeNs::TraitId(t)) => Some(t), |
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 049f808dc..3ad30f0c9 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -619,6 +619,7 @@ fn test_fn() { | |||
619 | ), | 619 | ), |
620 | path: "foo.rs", | 620 | path: "foo.rs", |
621 | }, | 621 | }, |
622 | initial_contents: "", | ||
622 | }, | 623 | }, |
623 | ], | 624 | ], |
624 | is_snippet: false, | 625 | is_snippet: false, |
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index e8b896623..d79f5c170 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs | |||
@@ -40,6 +40,7 @@ impl DiagnosticWithFix for UnresolvedModule { | |||
40 | anchor: self.file.original_file(sema.db), | 40 | anchor: self.file.original_file(sema.db), |
41 | path: self.candidate.clone(), | 41 | path: self.candidate.clone(), |
42 | }, | 42 | }, |
43 | initial_contents: "".to_string(), | ||
43 | } | 44 | } |
44 | .into(), | 45 | .into(), |
45 | unresolved_module.syntax().text_range(), | 46 | unresolved_module.syntax().text_range(), |
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs index 7a12e9965..47dd85ceb 100644 --- a/crates/ide/src/goto_definition.rs +++ b/crates/ide/src/goto_definition.rs | |||
@@ -750,6 +750,31 @@ fn test() { | |||
750 | } | 750 | } |
751 | 751 | ||
752 | #[test] | 752 | #[test] |
753 | fn goto_through_included_file() { | ||
754 | check( | ||
755 | r#" | ||
756 | //- /main.rs | ||
757 | #[rustc_builtin_macro] | ||
758 | macro_rules! include {} | ||
759 | |||
760 | include!("foo.rs"); | ||
761 | //^^^^^^^^^^^^^^^^^^^ | ||
762 | |||
763 | fn f() { | ||
764 | foo<|>(); | ||
765 | } | ||
766 | |||
767 | mod confuse_index { | ||
768 | pub fn foo() {} | ||
769 | } | ||
770 | |||
771 | //- /foo.rs | ||
772 | fn foo() {} | ||
773 | "#, | ||
774 | ); | ||
775 | } | ||
776 | |||
777 | #[test] | ||
753 | fn goto_for_type_param() { | 778 | fn goto_for_type_param() { |
754 | check( | 779 | check( |
755 | r#" | 780 | r#" |
@@ -1077,4 +1102,32 @@ fn foo<'foobar>(_: &'foobar ()) { | |||
1077 | }"#, | 1102 | }"#, |
1078 | ) | 1103 | ) |
1079 | } | 1104 | } |
1105 | |||
1106 | #[test] | ||
1107 | #[ignore] // requires the HIR to somehow track these hrtb lifetimes | ||
1108 | fn goto_lifetime_hrtb() { | ||
1109 | check( | ||
1110 | r#"trait Foo<T> {} | ||
1111 | fn foo<T>() where for<'a> T: Foo<&'a<|> (u8, u16)>, {} | ||
1112 | //^^ | ||
1113 | "#, | ||
1114 | ); | ||
1115 | check( | ||
1116 | r#"trait Foo<T> {} | ||
1117 | fn foo<T>() where for<'a<|>> T: Foo<&'a (u8, u16)>, {} | ||
1118 | //^^ | ||
1119 | "#, | ||
1120 | ); | ||
1121 | } | ||
1122 | |||
1123 | #[test] | ||
1124 | #[ignore] // requires ForTypes to be implemented | ||
1125 | fn goto_lifetime_hrtb_for_type() { | ||
1126 | check( | ||
1127 | r#"trait Foo<T> {} | ||
1128 | fn foo<T>() where T: for<'a> Foo<&'a<|> (u8, u16)>, {} | ||
1129 | //^^ | ||
1130 | "#, | ||
1131 | ); | ||
1132 | } | ||
1080 | } | 1133 | } |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 18ea19305..33b7358f7 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -147,20 +147,20 @@ fn find_name( | |||
147 | ) -> Option<RangeInfo<Definition>> { | 147 | ) -> Option<RangeInfo<Definition>> { |
148 | if let Some(name) = opt_name { | 148 | if let Some(name) = opt_name { |
149 | let def = NameClass::classify(sema, &name)?.referenced_or_defined(sema.db); | 149 | let def = NameClass::classify(sema, &name)?.referenced_or_defined(sema.db); |
150 | let range = name.syntax().text_range(); | 150 | let FileRange { range, .. } = sema.original_range(name.syntax()); |
151 | return Some(RangeInfo::new(range, def)); | 151 | return Some(RangeInfo::new(range, def)); |
152 | } | 152 | } |
153 | 153 | ||
154 | let (text_range, def) = if let Some(lifetime) = | 154 | let (FileRange { range, .. }, def) = if let Some(lifetime) = |
155 | sema.find_node_at_offset_with_descend::<ast::Lifetime>(&syntax, position.offset) | 155 | sema.find_node_at_offset_with_descend::<ast::Lifetime>(&syntax, position.offset) |
156 | { | 156 | { |
157 | if let Some(def) = NameRefClass::classify_lifetime(sema, &lifetime) | 157 | if let Some(def) = NameRefClass::classify_lifetime(sema, &lifetime) |
158 | .map(|class| NameRefClass::referenced(class, sema.db)) | 158 | .map(|class| NameRefClass::referenced(class, sema.db)) |
159 | { | 159 | { |
160 | (lifetime.syntax().text_range(), def) | 160 | (sema.original_range(lifetime.syntax()), def) |
161 | } else { | 161 | } else { |
162 | ( | 162 | ( |
163 | lifetime.syntax().text_range(), | 163 | sema.original_range(lifetime.syntax()), |
164 | NameClass::classify_lifetime(sema, &lifetime)?.referenced_or_defined(sema.db), | 164 | NameClass::classify_lifetime(sema, &lifetime)?.referenced_or_defined(sema.db), |
165 | ) | 165 | ) |
166 | } | 166 | } |
@@ -168,11 +168,11 @@ fn find_name( | |||
168 | let name_ref = | 168 | let name_ref = |
169 | sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?; | 169 | sema.find_node_at_offset_with_descend::<ast::NameRef>(&syntax, position.offset)?; |
170 | ( | 170 | ( |
171 | name_ref.syntax().text_range(), | 171 | sema.original_range(name_ref.syntax()), |
172 | NameRefClass::classify(sema, &name_ref)?.referenced(sema.db), | 172 | NameRefClass::classify(sema, &name_ref)?.referenced(sema.db), |
173 | ) | 173 | ) |
174 | }; | 174 | }; |
175 | Some(RangeInfo::new(text_range, def)) | 175 | Some(RangeInfo::new(range, def)) |
176 | } | 176 | } |
177 | 177 | ||
178 | fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> { | 178 | fn decl_access(def: &Definition, syntax: &SyntaxNode, range: TextRange) -> Option<ReferenceAccess> { |
@@ -1086,4 +1086,40 @@ impl<'a> Foo<'a> for &'a () { | |||
1086 | "#]], | 1086 | "#]], |
1087 | ); | 1087 | ); |
1088 | } | 1088 | } |
1089 | |||
1090 | #[test] | ||
1091 | fn test_map_range_to_original() { | ||
1092 | check( | ||
1093 | r#" | ||
1094 | macro_rules! foo {($i:ident) => {$i} } | ||
1095 | fn main() { | ||
1096 | let a<|> = "test"; | ||
1097 | foo!(a); | ||
1098 | } | ||
1099 | "#, | ||
1100 | expect![[r#" | ||
1101 | a Local FileId(0) 59..60 Other | ||
1102 | |||
1103 | FileId(0) 80..81 Other Read | ||
1104 | "#]], | ||
1105 | ); | ||
1106 | } | ||
1107 | |||
1108 | #[test] | ||
1109 | fn test_map_range_to_original_ref() { | ||
1110 | check( | ||
1111 | r#" | ||
1112 | macro_rules! foo {($i:ident) => {$i} } | ||
1113 | fn main() { | ||
1114 | let a = "test"; | ||
1115 | foo!(a<|>); | ||
1116 | } | ||
1117 | "#, | ||
1118 | expect![[r#" | ||
1119 | a Local FileId(0) 59..60 Other | ||
1120 | |||
1121 | FileId(0) 80..81 Other Read | ||
1122 | "#]], | ||
1123 | ); | ||
1124 | } | ||
1089 | } | 1125 | } |
diff --git a/crates/ide_db/src/source_change.rs b/crates/ide_db/src/source_change.rs index e87d98dad..10c0abdac 100644 --- a/crates/ide_db/src/source_change.rs +++ b/crates/ide_db/src/source_change.rs | |||
@@ -44,7 +44,7 @@ impl From<Vec<SourceFileEdit>> for SourceChange { | |||
44 | 44 | ||
45 | #[derive(Debug, Clone)] | 45 | #[derive(Debug, Clone)] |
46 | pub enum FileSystemEdit { | 46 | pub enum FileSystemEdit { |
47 | CreateFile { dst: AnchoredPathBuf }, | 47 | CreateFile { dst: AnchoredPathBuf, initial_contents: String }, |
48 | MoveFile { src: FileId, dst: AnchoredPathBuf }, | 48 | MoveFile { src: FileId, dst: AnchoredPathBuf }, |
49 | } | 49 | } |
50 | 50 | ||
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs index f10e7a9b6..451fa1456 100644 --- a/crates/mbe/src/tests.rs +++ b/crates/mbe/src/tests.rs | |||
@@ -1004,6 +1004,18 @@ fn test_underscore() { | |||
1004 | } | 1004 | } |
1005 | 1005 | ||
1006 | #[test] | 1006 | #[test] |
1007 | fn test_vertical_bar_with_pat() { | ||
1008 | parse_macro( | ||
1009 | r#" | ||
1010 | macro_rules! foo { | ||
1011 | (| $pat:pat | ) => { 0 } | ||
1012 | } | ||
1013 | "#, | ||
1014 | ) | ||
1015 | .assert_expand_items(r#"foo! { | x | }"#, r#"0"#); | ||
1016 | } | ||
1017 | |||
1018 | #[test] | ||
1007 | fn test_lifetime() { | 1019 | fn test_lifetime() { |
1008 | parse_macro( | 1020 | parse_macro( |
1009 | r#" | 1021 | r#" |
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 1a078f6b4..f08c8bab7 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs | |||
@@ -55,7 +55,7 @@ pub(crate) mod fragments { | |||
55 | use super::*; | 55 | use super::*; |
56 | 56 | ||
57 | pub(crate) use super::{ | 57 | pub(crate) use super::{ |
58 | expressions::block_expr, paths::type_path as path, patterns::pattern, types::type_, | 58 | expressions::block_expr, paths::type_path as path, patterns::pattern_single, types::type_, |
59 | }; | 59 | }; |
60 | 60 | ||
61 | pub(crate) fn expr(p: &mut Parser) { | 61 | pub(crate) fn expr(p: &mut Parser) { |
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs index 18b63feb7..e897d5a52 100644 --- a/crates/parser/src/grammar/expressions/atom.rs +++ b/crates/parser/src/grammar/expressions/atom.rs | |||
@@ -156,11 +156,13 @@ fn tuple_expr(p: &mut Parser) -> CompletedMarker { | |||
156 | let mut saw_expr = false; | 156 | let mut saw_expr = false; |
157 | while !p.at(EOF) && !p.at(T![')']) { | 157 | while !p.at(EOF) && !p.at(T![')']) { |
158 | saw_expr = true; | 158 | saw_expr = true; |
159 | if !p.at_ts(EXPR_FIRST) { | 159 | |
160 | p.error("expected expression"); | 160 | // test tuple_attrs |
161 | // const A: (i64, i64) = (1, #[cfg(test)] 2); | ||
162 | if !expr_with_attrs(p) { | ||
161 | break; | 163 | break; |
162 | } | 164 | } |
163 | expr(p); | 165 | |
164 | if !p.at(T![')']) { | 166 | if !p.at(T![')']) { |
165 | saw_comma = true; | 167 | saw_comma = true; |
166 | p.expect(T![,]); | 168 | p.expect(T![,]); |
diff --git a/crates/parser/src/grammar/params.rs b/crates/parser/src/grammar/params.rs index 3ee4e4fca..2d006a1d5 100644 --- a/crates/parser/src/grammar/params.rs +++ b/crates/parser/src/grammar/params.rs | |||
@@ -47,20 +47,23 @@ fn list_(p: &mut Parser, flavor: Flavor) { | |||
47 | if let FnDef = flavor { | 47 | if let FnDef = flavor { |
48 | // test self_param_outer_attr | 48 | // test self_param_outer_attr |
49 | // fn f(#[must_use] self) {} | 49 | // fn f(#[must_use] self) {} |
50 | let m = p.start(); | ||
50 | attributes::outer_attrs(p); | 51 | attributes::outer_attrs(p); |
51 | opt_self_param(p); | 52 | opt_self_param(p, m); |
52 | } | 53 | } |
53 | 54 | ||
54 | while !p.at(EOF) && !p.at(ket) { | 55 | while !p.at(EOF) && !p.at(ket) { |
55 | // test param_outer_arg | 56 | // test param_outer_arg |
56 | // fn f(#[attr1] pat: Type) {} | 57 | // fn f(#[attr1] pat: Type) {} |
58 | let m = p.start(); | ||
57 | attributes::outer_attrs(p); | 59 | attributes::outer_attrs(p); |
58 | 60 | ||
59 | if !p.at_ts(PARAM_FIRST) { | 61 | if !p.at_ts(PARAM_FIRST) { |
60 | p.error("expected value parameter"); | 62 | p.error("expected value parameter"); |
63 | m.abandon(p); | ||
61 | break; | 64 | break; |
62 | } | 65 | } |
63 | let param = param(p, flavor); | 66 | let param = param(p, m, flavor); |
64 | if !p.at(ket) { | 67 | if !p.at(ket) { |
65 | p.expect(T![,]); | 68 | p.expect(T![,]); |
66 | } | 69 | } |
@@ -77,9 +80,8 @@ const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST); | |||
77 | 80 | ||
78 | struct Variadic(bool); | 81 | struct Variadic(bool); |
79 | 82 | ||
80 | fn param(p: &mut Parser, flavor: Flavor) -> Variadic { | 83 | fn param(p: &mut Parser, m: Marker, flavor: Flavor) -> Variadic { |
81 | let mut res = Variadic(false); | 84 | let mut res = Variadic(false); |
82 | let m = p.start(); | ||
83 | match flavor { | 85 | match flavor { |
84 | // test param_list_vararg | 86 | // test param_list_vararg |
85 | // extern "C" { fn printf(format: *const i8, ...) -> i32; } | 87 | // extern "C" { fn printf(format: *const i8, ...) -> i32; } |
@@ -151,10 +153,8 @@ fn variadic_param(p: &mut Parser) -> bool { | |||
151 | // fn d(&'a mut self, x: i32) {} | 153 | // fn d(&'a mut self, x: i32) {} |
152 | // fn e(mut self) {} | 154 | // fn e(mut self) {} |
153 | // } | 155 | // } |
154 | fn opt_self_param(p: &mut Parser) { | 156 | fn opt_self_param(p: &mut Parser, m: Marker) { |
155 | let m; | ||
156 | if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] { | 157 | if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] { |
157 | m = p.start(); | ||
158 | p.eat(T![mut]); | 158 | p.eat(T![mut]); |
159 | p.eat(T![self]); | 159 | p.eat(T![self]); |
160 | // test arb_self_types | 160 | // test arb_self_types |
@@ -174,9 +174,8 @@ fn opt_self_param(p: &mut Parser) { | |||
174 | (T![&], T![mut], T![self], _) => 3, | 174 | (T![&], T![mut], T![self], _) => 3, |
175 | (T![&], LIFETIME_IDENT, T![self], _) => 3, | 175 | (T![&], LIFETIME_IDENT, T![self], _) => 3, |
176 | (T![&], LIFETIME_IDENT, T![mut], T![self]) => 4, | 176 | (T![&], LIFETIME_IDENT, T![mut], T![self]) => 4, |
177 | _ => return, | 177 | _ => return m.abandon(p), |
178 | }; | 178 | }; |
179 | m = p.start(); | ||
180 | p.bump_any(); | 179 | p.bump_any(); |
181 | if p.at(LIFETIME_IDENT) { | 180 | if p.at(LIFETIME_IDENT) { |
182 | lifetime(p); | 181 | lifetime(p); |
diff --git a/crates/parser/src/grammar/type_params.rs b/crates/parser/src/grammar/type_params.rs index 9c3f7c28a..4aeccd193 100644 --- a/crates/parser/src/grammar/type_params.rs +++ b/crates/parser/src/grammar/type_params.rs | |||
@@ -113,7 +113,7 @@ fn type_bound(p: &mut Parser) -> bool { | |||
113 | p.eat(T![?]); | 113 | p.eat(T![?]); |
114 | match p.current() { | 114 | match p.current() { |
115 | LIFETIME_IDENT => lifetime(p), | 115 | LIFETIME_IDENT => lifetime(p), |
116 | T![for] => types::for_type(p), | 116 | T![for] => types::for_type(p, false), |
117 | _ if paths::is_use_path_start(p) => types::path_type_(p, false), | 117 | _ if paths::is_use_path_start(p) => types::path_type_(p, false), |
118 | _ => { | 118 | _ => { |
119 | m.abandon(p); | 119 | m.abandon(p); |
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs index 36a15eace..94cbf7d85 100644 --- a/crates/parser/src/grammar/types.rs +++ b/crates/parser/src/grammar/types.rs | |||
@@ -44,7 +44,7 @@ fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) { | |||
44 | T![&] => ref_type(p), | 44 | T![&] => ref_type(p), |
45 | T![_] => infer_type(p), | 45 | T![_] => infer_type(p), |
46 | T![fn] | T![unsafe] | T![extern] => fn_ptr_type(p), | 46 | T![fn] | T![unsafe] | T![extern] => fn_ptr_type(p), |
47 | T![for] => for_type(p), | 47 | T![for] => for_type(p, allow_bounds), |
48 | T![impl] => impl_trait_type(p), | 48 | T![impl] => impl_trait_type(p), |
49 | T![dyn] => dyn_trait_type(p), | 49 | T![dyn] => dyn_trait_type(p), |
50 | // Some path types are not allowed to have bounds (no plus) | 50 | // Some path types are not allowed to have bounds (no plus) |
@@ -227,7 +227,7 @@ pub(super) fn for_binder(p: &mut Parser) { | |||
227 | // type A = for<'a> fn() -> (); | 227 | // type A = for<'a> fn() -> (); |
228 | // type B = for<'a> unsafe extern "C" fn(&'a ()) -> (); | 228 | // type B = for<'a> unsafe extern "C" fn(&'a ()) -> (); |
229 | // type Obj = for<'a> PartialEq<&'a i32>; | 229 | // type Obj = for<'a> PartialEq<&'a i32>; |
230 | pub(super) fn for_type(p: &mut Parser) { | 230 | pub(super) fn for_type(p: &mut Parser, allow_bounds: bool) { |
231 | assert!(p.at(T![for])); | 231 | assert!(p.at(T![for])); |
232 | let m = p.start(); | 232 | let m = p.start(); |
233 | for_binder(p); | 233 | for_binder(p); |
@@ -240,7 +240,13 @@ pub(super) fn for_type(p: &mut Parser) { | |||
240 | } | 240 | } |
241 | } | 241 | } |
242 | type_no_bounds(p); | 242 | type_no_bounds(p); |
243 | m.complete(p, FOR_TYPE); | 243 | let completed = m.complete(p, FOR_TYPE); |
244 | |||
245 | // test no_dyn_trait_leading_for | ||
246 | // type A = for<'a> Test<'a> + Send; | ||
247 | if allow_bounds { | ||
248 | opt_type_bounds_as_dyn_trait_type(p, completed); | ||
249 | } | ||
244 | } | 250 | } |
245 | 251 | ||
246 | // test impl_trait_type | 252 | // test impl_trait_type |
@@ -290,7 +296,7 @@ fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) { | |||
290 | let path = m.complete(p, kind); | 296 | let path = m.complete(p, kind); |
291 | 297 | ||
292 | if allow_bounds { | 298 | if allow_bounds { |
293 | opt_path_type_bounds_as_dyn_trait_type(p, path); | 299 | opt_type_bounds_as_dyn_trait_type(p, path); |
294 | } | 300 | } |
295 | } | 301 | } |
296 | 302 | ||
@@ -304,19 +310,23 @@ pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) { | |||
304 | // fn foo() -> Box<dyn T + 'f> {} | 310 | // fn foo() -> Box<dyn T + 'f> {} |
305 | let path = m.complete(p, PATH_TYPE); | 311 | let path = m.complete(p, PATH_TYPE); |
306 | if allow_bounds { | 312 | if allow_bounds { |
307 | opt_path_type_bounds_as_dyn_trait_type(p, path); | 313 | opt_type_bounds_as_dyn_trait_type(p, path); |
308 | } | 314 | } |
309 | } | 315 | } |
310 | 316 | ||
311 | /// This turns a parsed PATH_TYPE optionally into a DYN_TRAIT_TYPE | 317 | /// This turns a parsed PATH_TYPE or FOR_TYPE optionally into a DYN_TRAIT_TYPE |
312 | /// with a TYPE_BOUND_LIST | 318 | /// with a TYPE_BOUND_LIST |
313 | fn opt_path_type_bounds_as_dyn_trait_type(p: &mut Parser, path_type_marker: CompletedMarker) { | 319 | fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser, type_marker: CompletedMarker) { |
320 | assert!(matches!( | ||
321 | type_marker.kind(), | ||
322 | SyntaxKind::PATH_TYPE | SyntaxKind::FOR_TYPE | SyntaxKind::MACRO_CALL | ||
323 | )); | ||
314 | if !p.at(T![+]) { | 324 | if !p.at(T![+]) { |
315 | return; | 325 | return; |
316 | } | 326 | } |
317 | 327 | ||
318 | // First create a TYPE_BOUND from the completed PATH_TYPE | 328 | // First create a TYPE_BOUND from the completed PATH_TYPE |
319 | let m = path_type_marker.precede(p).complete(p, TYPE_BOUND); | 329 | let m = type_marker.precede(p).complete(p, TYPE_BOUND); |
320 | 330 | ||
321 | // Next setup a marker for the TYPE_BOUND_LIST | 331 | // Next setup a marker for the TYPE_BOUND_LIST |
322 | let m = m.precede(p); | 332 | let m = m.precede(p); |
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs index ab8e4c70e..811e740f9 100644 --- a/crates/parser/src/lib.rs +++ b/crates/parser/src/lib.rs | |||
@@ -112,7 +112,7 @@ pub fn parse_fragment( | |||
112 | FragmentKind::Path => grammar::fragments::path, | 112 | FragmentKind::Path => grammar::fragments::path, |
113 | FragmentKind::Expr => grammar::fragments::expr, | 113 | FragmentKind::Expr => grammar::fragments::expr, |
114 | FragmentKind::Type => grammar::fragments::type_, | 114 | FragmentKind::Type => grammar::fragments::type_, |
115 | FragmentKind::Pattern => grammar::fragments::pattern, | 115 | FragmentKind::Pattern => grammar::fragments::pattern_single, |
116 | FragmentKind::Item => grammar::fragments::item, | 116 | FragmentKind::Item => grammar::fragments::item, |
117 | FragmentKind::Block => grammar::fragments::block_expr, | 117 | FragmentKind::Block => grammar::fragments::block_expr, |
118 | FragmentKind::Visibility => grammar::fragments::opt_visibility, | 118 | FragmentKind::Visibility => grammar::fragments::opt_visibility, |
diff --git a/crates/proc_macro_srv/Cargo.toml b/crates/proc_macro_srv/Cargo.toml index 1bfa6c3fc..df9a55c10 100644 --- a/crates/proc_macro_srv/Cargo.toml +++ b/crates/proc_macro_srv/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | object = { version = "0.23", default-features = false, features = ["std", "read_core", "elf", "macho", "pe", "unaligned"] } | 13 | object = { version = "0.23", default-features = false, features = ["std", "read_core", "elf", "macho", "pe"] } |
14 | libloading = "0.6.0" | 14 | libloading = "0.6.0" |
15 | memmap = "0.7" | 15 | memmap = "0.7" |
16 | 16 | ||
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 1f4b5c24c..1db5b4e7d 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -33,7 +33,7 @@ config_data! { | |||
33 | callInfo_full: bool = "true", | 33 | callInfo_full: bool = "true", |
34 | 34 | ||
35 | /// Automatically refresh project info via `cargo metadata` on | 35 | /// Automatically refresh project info via `cargo metadata` on |
36 | /// Cargo.toml changes. | 36 | /// `Cargo.toml` changes. |
37 | cargo_autoreload: bool = "true", | 37 | cargo_autoreload: bool = "true", |
38 | /// Activate all available features. | 38 | /// Activate all available features. |
39 | cargo_allFeatures: bool = "false", | 39 | cargo_allFeatures: bool = "false", |
@@ -52,7 +52,7 @@ config_data! { | |||
52 | /// Run specified `cargo check` command for diagnostics on save. | 52 | /// Run specified `cargo check` command for diagnostics on save. |
53 | checkOnSave_enable: bool = "true", | 53 | checkOnSave_enable: bool = "true", |
54 | /// Check with all features (will be passed as `--all-features`). | 54 | /// Check with all features (will be passed as `--all-features`). |
55 | /// Defaults to `rust-analyzer.cargo.allFeatures`. | 55 | /// Defaults to `#rust-analyzer.cargo.allFeatures#`. |
56 | checkOnSave_allFeatures: Option<bool> = "null", | 56 | checkOnSave_allFeatures: Option<bool> = "null", |
57 | /// Check all targets and tests (will be passed as `--all-targets`). | 57 | /// Check all targets and tests (will be passed as `--all-targets`). |
58 | checkOnSave_allTargets: bool = "true", | 58 | checkOnSave_allTargets: bool = "true", |
@@ -61,12 +61,12 @@ config_data! { | |||
61 | /// Do not activate the `default` feature. | 61 | /// Do not activate the `default` feature. |
62 | checkOnSave_noDefaultFeatures: Option<bool> = "null", | 62 | checkOnSave_noDefaultFeatures: Option<bool> = "null", |
63 | /// Check for a specific target. Defaults to | 63 | /// Check for a specific target. Defaults to |
64 | /// `rust-analyzer.cargo.target`. | 64 | /// `#rust-analyzer.cargo.target#`. |
65 | checkOnSave_target: Option<String> = "null", | 65 | checkOnSave_target: Option<String> = "null", |
66 | /// Extra arguments for `cargo check`. | 66 | /// Extra arguments for `cargo check`. |
67 | checkOnSave_extraArgs: Vec<String> = "[]", | 67 | checkOnSave_extraArgs: Vec<String> = "[]", |
68 | /// List of features to activate. Defaults to | 68 | /// List of features to activate. Defaults to |
69 | /// `rust-analyzer.cargo.features`. | 69 | /// `#rust-analyzer.cargo.features#`. |
70 | checkOnSave_features: Option<Vec<String>> = "null", | 70 | checkOnSave_features: Option<Vec<String>> = "null", |
71 | /// Advanced option, fully override the command rust-analyzer uses for | 71 | /// Advanced option, fully override the command rust-analyzer uses for |
72 | /// checking. The command should include `--message-format=json` or | 72 | /// checking. The command should include `--message-format=json` or |
@@ -80,7 +80,7 @@ config_data! { | |||
80 | /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc. | 80 | /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc. |
81 | completion_postfix_enable: bool = "true", | 81 | completion_postfix_enable: bool = "true", |
82 | /// Toggles the additional completions that automatically add imports when completed. | 82 | /// Toggles the additional completions that automatically add imports when completed. |
83 | /// Note that your client have to specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. | 83 | /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. |
84 | completion_autoimport_enable: bool = "true", | 84 | completion_autoimport_enable: bool = "true", |
85 | 85 | ||
86 | /// Whether to show native rust-analyzer diagnostics. | 86 | /// Whether to show native rust-analyzer diagnostics. |
@@ -90,13 +90,13 @@ config_data! { | |||
90 | diagnostics_enableExperimental: bool = "true", | 90 | diagnostics_enableExperimental: bool = "true", |
91 | /// List of rust-analyzer diagnostics to disable. | 91 | /// List of rust-analyzer diagnostics to disable. |
92 | diagnostics_disabled: FxHashSet<String> = "[]", | 92 | diagnostics_disabled: FxHashSet<String> = "[]", |
93 | /// List of warnings that should be displayed with info severity.\nThe | 93 | /// List of warnings that should be displayed with info severity.\n\nThe |
94 | /// warnings will be indicated by a blue squiggly underline in code and | 94 | /// warnings will be indicated by a blue squiggly underline in code and |
95 | /// a blue icon in the problems panel. | 95 | /// a blue icon in the `Problems Panel`. |
96 | diagnostics_warningsAsHint: Vec<String> = "[]", | 96 | diagnostics_warningsAsHint: Vec<String> = "[]", |
97 | /// List of warnings that should be displayed with hint severity.\nThe | 97 | /// List of warnings that should be displayed with hint severity.\n\nThe |
98 | /// warnings will be indicated by faded text or three dots in code and | 98 | /// warnings will be indicated by faded text or three dots in code and |
99 | /// will not show up in the problems panel. | 99 | /// will not show up in the `Problems Panel`. |
100 | diagnostics_warningsAsInfo: Vec<String> = "[]", | 100 | diagnostics_warningsAsInfo: Vec<String> = "[]", |
101 | 101 | ||
102 | /// Controls file watching implementation. | 102 | /// Controls file watching implementation. |
@@ -121,7 +121,7 @@ config_data! { | |||
121 | 121 | ||
122 | /// Whether to show inlay type hints for method chains. | 122 | /// Whether to show inlay type hints for method chains. |
123 | inlayHints_chainingHints: bool = "true", | 123 | inlayHints_chainingHints: bool = "true", |
124 | /// Maximum length for inlay hints. | 124 | /// Maximum length for inlay hints. Default is unlimited. |
125 | inlayHints_maxLength: Option<usize> = "null", | 125 | inlayHints_maxLength: Option<usize> = "null", |
126 | /// Whether to show function parameter name inlay hints at the call | 126 | /// Whether to show function parameter name inlay hints at the call |
127 | /// site. | 127 | /// site. |
@@ -145,27 +145,27 @@ config_data! { | |||
145 | lens_methodReferences: bool = "false", | 145 | lens_methodReferences: bool = "false", |
146 | 146 | ||
147 | /// Disable project auto-discovery in favor of explicitly specified set | 147 | /// Disable project auto-discovery in favor of explicitly specified set |
148 | /// of projects. \nElements must be paths pointing to Cargo.toml, | 148 | /// of projects.\n\nElements must be paths pointing to `Cargo.toml`, |
149 | /// rust-project.json, or JSON objects in rust-project.json format. | 149 | /// `rust-project.json`, or JSON objects in `rust-project.json` format. |
150 | linkedProjects: Vec<ManifestOrProjectJson> = "[]", | 150 | linkedProjects: Vec<ManifestOrProjectJson> = "[]", |
151 | /// Number of syntax trees rust-analyzer keeps in memory. | 151 | /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. |
152 | lruCapacity: Option<usize> = "null", | 152 | lruCapacity: Option<usize> = "null", |
153 | /// Whether to show `can't find Cargo.toml` error message. | 153 | /// Whether to show `can't find Cargo.toml` error message. |
154 | notifications_cargoTomlNotFound: bool = "true", | 154 | notifications_cargoTomlNotFound: bool = "true", |
155 | /// Enable Proc macro support, cargo.loadOutDirsFromCheck must be | 155 | /// Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be |
156 | /// enabled. | 156 | /// enabled. |
157 | procMacro_enable: bool = "false", | 157 | procMacro_enable: bool = "false", |
158 | 158 | ||
159 | /// Command to be executed instead of 'cargo' for runnables. | 159 | /// Command to be executed instead of 'cargo' for runnables. |
160 | runnables_overrideCargo: Option<String> = "null", | 160 | runnables_overrideCargo: Option<String> = "null", |
161 | /// Additional arguments to be passed to cargo for runnables such as | 161 | /// Additional arguments to be passed to cargo for runnables such as |
162 | /// tests or binaries.\nFor example, it may be '--release'. | 162 | /// tests or binaries.\nFor example, it may be `--release`. |
163 | runnables_cargoExtraArgs: Vec<String> = "[]", | 163 | runnables_cargoExtraArgs: Vec<String> = "[]", |
164 | 164 | ||
165 | /// Path to the rust compiler sources, for usage in rustc_private projects. | 165 | /// Path to the rust compiler sources, for usage in rustc_private projects. |
166 | rustcSource : Option<String> = "null", | 166 | rustcSource : Option<String> = "null", |
167 | 167 | ||
168 | /// Additional arguments to rustfmt. | 168 | /// Additional arguments to `rustfmt`. |
169 | rustfmt_extraArgs: Vec<String> = "[]", | 169 | rustfmt_extraArgs: Vec<String> = "[]", |
170 | /// Advanced option, fully override the command rust-analyzer uses for | 170 | /// Advanced option, fully override the command rust-analyzer uses for |
171 | /// formatting. | 171 | /// formatting. |
@@ -349,12 +349,12 @@ impl Config { | |||
349 | res | 349 | res |
350 | } | 350 | } |
351 | pub fn update(&mut self, json: serde_json::Value) { | 351 | pub fn update(&mut self, json: serde_json::Value) { |
352 | log::info!("Config::update({:#})", json); | 352 | log::info!("updating config from JSON: {:#}", json); |
353 | if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { | 353 | if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { |
354 | return; | 354 | return; |
355 | } | 355 | } |
356 | self.do_update(json); | 356 | self.do_update(json); |
357 | log::info!("Config::update() = {:#?}", self); | 357 | log::info!("updated config: {:#?}", self); |
358 | } | 358 | } |
359 | fn do_update(&mut self, json: serde_json::Value) { | 359 | fn do_update(&mut self, json: serde_json::Value) { |
360 | let data = ConfigData::from_json(json); | 360 | let data = ConfigData::from_json(json); |
@@ -758,7 +758,7 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json | |||
758 | ], | 758 | ], |
759 | "enumDescriptions": [ | 759 | "enumDescriptions": [ |
760 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", | 760 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", |
761 | "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name", | 761 | "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name.", |
762 | "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." | 762 | "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." |
763 | ], | 763 | ], |
764 | }, | 764 | }, |
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs index f16f97131..540759198 100644 --- a/crates/rust-analyzer/src/diagnostics/to_proto.rs +++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs | |||
@@ -319,6 +319,10 @@ pub(crate) fn map_rust_diagnostic_to_lsp( | |||
319 | message: "original diagnostic".to_string(), | 319 | message: "original diagnostic".to_string(), |
320 | }; | 320 | }; |
321 | for info in &related_information { | 321 | for info in &related_information { |
322 | // Filter out empty/non-existent messages, as they greatly confuse VS Code. | ||
323 | if info.message.is_empty() { | ||
324 | continue; | ||
325 | } | ||
322 | diagnostics.push(MappedRustDiagnostic { | 326 | diagnostics.push(MappedRustDiagnostic { |
323 | url: info.location.uri.clone(), | 327 | url: info.location.uri.clone(), |
324 | fixes: fixes.clone(), // share fixes to make them easier to apply | 328 | fixes: fixes.clone(), // share fixes to make them easier to apply |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index e0561b5a7..5a1ae96aa 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -634,30 +634,47 @@ pub(crate) fn snippet_text_document_edit( | |||
634 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) | 634 | Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) |
635 | } | 635 | } |
636 | 636 | ||
637 | pub(crate) fn resource_op( | 637 | pub(crate) fn snippet_text_document_ops( |
638 | snap: &GlobalStateSnapshot, | 638 | snap: &GlobalStateSnapshot, |
639 | file_system_edit: FileSystemEdit, | 639 | file_system_edit: FileSystemEdit, |
640 | ) -> lsp_types::ResourceOp { | 640 | ) -> Vec<lsp_ext::SnippetDocumentChangeOperation> { |
641 | let mut ops = Vec::new(); | ||
641 | match file_system_edit { | 642 | match file_system_edit { |
642 | FileSystemEdit::CreateFile { dst } => { | 643 | FileSystemEdit::CreateFile { dst, initial_contents } => { |
643 | let uri = snap.anchored_path(&dst); | 644 | let uri = snap.anchored_path(&dst); |
644 | lsp_types::ResourceOp::Create(lsp_types::CreateFile { | 645 | let create_file = lsp_types::ResourceOp::Create(lsp_types::CreateFile { |
645 | uri, | 646 | uri: uri.clone(), |
646 | options: None, | 647 | options: None, |
647 | annotation_id: None, | 648 | annotation_id: None, |
648 | }) | 649 | }); |
650 | ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(create_file)); | ||
651 | if !initial_contents.is_empty() { | ||
652 | let text_document = | ||
653 | lsp_types::OptionalVersionedTextDocumentIdentifier { uri, version: None }; | ||
654 | let range = range(&LineIndex::new(""), TextRange::empty(TextSize::from(0))); | ||
655 | let text_edit = lsp_ext::SnippetTextEdit { | ||
656 | range, | ||
657 | new_text: initial_contents, | ||
658 | insert_text_format: Some(lsp_types::InsertTextFormat::PlainText), | ||
659 | }; | ||
660 | let edit_file = | ||
661 | lsp_ext::SnippetTextDocumentEdit { text_document, edits: vec![text_edit] }; | ||
662 | ops.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit_file)); | ||
663 | } | ||
649 | } | 664 | } |
650 | FileSystemEdit::MoveFile { src, dst } => { | 665 | FileSystemEdit::MoveFile { src, dst } => { |
651 | let old_uri = snap.file_id_to_url(src); | 666 | let old_uri = snap.file_id_to_url(src); |
652 | let new_uri = snap.anchored_path(&dst); | 667 | let new_uri = snap.anchored_path(&dst); |
653 | lsp_types::ResourceOp::Rename(lsp_types::RenameFile { | 668 | let rename_file = lsp_types::ResourceOp::Rename(lsp_types::RenameFile { |
654 | old_uri, | 669 | old_uri, |
655 | new_uri, | 670 | new_uri, |
656 | options: None, | 671 | options: None, |
657 | annotation_id: None, | 672 | annotation_id: None, |
658 | }) | 673 | }); |
674 | ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(rename_file)) | ||
659 | } | 675 | } |
660 | } | 676 | } |
677 | ops | ||
661 | } | 678 | } |
662 | 679 | ||
663 | pub(crate) fn snippet_workspace_edit( | 680 | pub(crate) fn snippet_workspace_edit( |
@@ -666,8 +683,8 @@ pub(crate) fn snippet_workspace_edit( | |||
666 | ) -> Result<lsp_ext::SnippetWorkspaceEdit> { | 683 | ) -> Result<lsp_ext::SnippetWorkspaceEdit> { |
667 | let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new(); | 684 | let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new(); |
668 | for op in source_change.file_system_edits { | 685 | for op in source_change.file_system_edits { |
669 | let op = resource_op(&snap, op); | 686 | let ops = snippet_text_document_ops(snap, op); |
670 | document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Op(op)); | 687 | document_changes.extend_from_slice(&ops); |
671 | } | 688 | } |
672 | for edit in source_change.source_file_edits { | 689 | for edit in source_change.source_file_edits { |
673 | let edit = snippet_text_document_edit(&snap, source_change.is_snippet, edit)?; | 690 | let edit = snippet_text_document_edit(&snap, source_change.is_snippet, edit)?; |
diff --git a/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast b/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast index 6403ff8d5..d3219f0b2 100644 --- a/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast +++ b/crates/syntax/test_data/parser/inline/ok/0138_self_param_outer_attr.rast | |||
@@ -6,16 +6,16 @@ [email protected] | |||
6 | [email protected] "f" | 6 | [email protected] "f" |
7 | [email protected] | 7 | [email protected] |
8 | [email protected] "(" | 8 | [email protected] "(" |
9 | ATT[email protected]6 | 9 | SELF_PARAM@5..21 |
10 | POUND@5..6 "#" | 10 | ATTR@5..16 |
11 | L_BRACK@6..7 "[" | 11 | POUND@5..6 "#" |
12 | PATH@7..15 | 12 | L_BRACK@6..7 "[" |
13 | PATH_SEGMENT@7..15 | 13 | [email protected] |
14 | NAME_REF@7..15 | 14 | PATH_SEGMENT@7..15 |
15 | IDENT@7..15 "must_use" | 15 | NAME_REF@7..15 |
16 | R_BRACK@15..16 "]" | 16 | IDENT@7..15 "must_use" |
17 | WHITESPACE@16..17 " " | 17 | R_BRACK@15..16 "]" |
18 | SELF_PARAM@17..21 | 18 | WHITESPACE@16..17 " " |
19 | [email protected] "self" | 19 | [email protected] "self" |
20 | [email protected] ")" | 20 | [email protected] ")" |
21 | [email protected] " " | 21 | [email protected] " " |
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast new file mode 100644 index 000000000..edfcb288c --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast | |||
@@ -0,0 +1,43 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "type" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "A" | ||
7 | [email protected] " " | ||
8 | [email protected] "=" | ||
9 | [email protected] " " | ||
10 | [email protected] | ||
11 | [email protected] | ||
12 | [email protected] | ||
13 | [email protected] | ||
14 | [email protected] "for" | ||
15 | [email protected] | ||
16 | [email protected] "<" | ||
17 | [email protected] | ||
18 | [email protected] | ||
19 | [email protected] "\'a" | ||
20 | [email protected] ">" | ||
21 | [email protected] " " | ||
22 | [email protected] | ||
23 | [email protected] | ||
24 | [email protected] | ||
25 | [email protected] | ||
26 | [email protected] "Test" | ||
27 | [email protected] | ||
28 | [email protected] "<" | ||
29 | [email protected] | ||
30 | [email protected] | ||
31 | [email protected] "\'a" | ||
32 | [email protected] ">" | ||
33 | [email protected] " " | ||
34 | [email protected] "+" | ||
35 | [email protected] " " | ||
36 | [email protected] | ||
37 | [email protected] | ||
38 | [email protected] | ||
39 | [email protected] | ||
40 | [email protected] | ||
41 | [email protected] "Send" | ||
42 | [email protected] ";" | ||
43 | [email protected] "\n" | ||
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs new file mode 100644 index 000000000..47a71fd19 --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs | |||
@@ -0,0 +1 @@ | |||
type A = for<'a> Test<'a> + Send; | |||
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast new file mode 100644 index 000000000..d34b21abe --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rast | |||
@@ -0,0 +1,50 @@ | |||
1 | [email protected] | ||
2 | [email protected] | ||
3 | [email protected] "const" | ||
4 | [email protected] " " | ||
5 | [email protected] | ||
6 | [email protected] "A" | ||
7 | [email protected] ":" | ||
8 | [email protected] " " | ||
9 | [email protected] | ||
10 | [email protected] "(" | ||
11 | [email protected] | ||
12 | [email protected] | ||
13 | [email protected] | ||
14 | [email protected] | ||
15 | [email protected] "i64" | ||
16 | [email protected] "," | ||
17 | [email protected] " " | ||
18 | [email protected] | ||
19 | [email protected] | ||
20 | [email protected] | ||
21 | [email protected] | ||
22 | [email protected] "i64" | ||
23 | [email protected] ")" | ||
24 | [email protected] " " | ||
25 | [email protected] "=" | ||
26 | [email protected] " " | ||
27 | [email protected] | ||
28 | [email protected] "(" | ||
29 | [email protected] | ||
30 | [email protected] "1" | ||
31 | [email protected] "," | ||
32 | [email protected] " " | ||
33 | [email protected] | ||
34 | [email protected] | ||
35 | [email protected] "#" | ||
36 | [email protected] "[" | ||
37 | [email protected] | ||
38 | [email protected] | ||
39 | [email protected] | ||
40 | [email protected] "cfg" | ||
41 | [email protected] | ||
42 | [email protected] "(" | ||
43 | [email protected] "test" | ||
44 | [email protected] ")" | ||
45 | [email protected] "]" | ||
46 | [email protected] " " | ||
47 | [email protected] "2" | ||
48 | [email protected] ")" | ||
49 | [email protected] ";" | ||
50 | [email protected] "\n" | ||
diff --git a/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rs b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rs new file mode 100644 index 000000000..f84b7ab31 --- /dev/null +++ b/crates/syntax/test_data/parser/inline/ok/0154_tuple_attrs.rs | |||
@@ -0,0 +1 @@ | |||
const A: (i64, i64) = (1, #[cfg(test)] 2); | |||
diff --git a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast index 8974f9e40..3fed11838 100644 --- a/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast +++ b/crates/syntax/test_data/parser/ok/0051_parameter_attrs.rast | |||
@@ -107,16 +107,16 @@ [email protected] | |||
107 | [email protected] "i8" | 107 | [email protected] "i8" |
108 | [email protected] "," | 108 | [email protected] "," |
109 | [email protected] " " | 109 | [email protected] " " |
110 | ATT[email protected]3 | 110 | PARAM@106..117 |
111 | POUND@106..107 "#" | 111 | ATTR@106..113 |
112 | L_BRACK@107..108 "[" | 112 | POUND@106..107 "#" |
113 | PATH@108..112 | 113 | L_BRACK@107..108 "[" |
114 | PATH_SEGMENT@108..112 | 114 | [email protected] |
115 | NAME_REF@108..112 | 115 | PATH_SEGMENT@108..112 |
116 | IDENT@108..112 "attr" | 116 | NAME_REF@108..112 |
117 | R_BRACK@112..113 "]" | 117 | IDENT@108..112 "attr" |
118 | WHITESPACE@113..114 " " | 118 | R_BRACK@112..113 "]" |
119 | PARAM@114..117 | 119 | WHITESPACE@113..114 " " |
120 | [email protected] "..." | 120 | [email protected] "..." |
121 | [email protected] ")" | 121 | [email protected] ")" |
122 | [email protected] " " | 122 | [email protected] " " |
@@ -153,16 +153,16 @@ [email protected] | |||
153 | [email protected] "FnMut" | 153 | [email protected] "FnMut" |
154 | [email protected] | 154 | [email protected] |
155 | [email protected] "(" | 155 | [email protected] "(" |
156 | ATT[email protected]53 | 156 | PARAM@146..166 |
157 | POUND@146..147 "#" | 157 | ATTR@146..153 |
158 | L_BRACK@147..148 "[" | 158 | POUND@146..147 "#" |
159 | PATH@148..152 | 159 | L_BRACK@147..148 "[" |
160 | PATH_SEGMENT@148..152 | 160 | [email protected] |
161 | NAME_REF@148..152 | 161 | PATH_SEGMENT@148..152 |
162 | IDENT@148..152 "attr" | 162 | NAME_REF@148..152 |
163 | R_BRACK@152..153 "]" | 163 | IDENT@148..152 "attr" |
164 | WHITESPACE@153..154 " " | 164 | R_BRACK@152..153 "]" |
165 | PARAM@154..166 | 165 | WHITESPACE@153..154 " " |
166 | [email protected] | 166 | [email protected] |
167 | [email protected] "&" | 167 | [email protected] "&" |
168 | [email protected] "mut" | 168 | [email protected] "mut" |
@@ -224,17 +224,17 @@ [email protected] | |||
224 | [email protected] "u64" | 224 | [email protected] "u64" |
225 | [email protected] "," | 225 | [email protected] "," |
226 | [email protected] " " | 226 | [email protected] " " |
227 | ATT[email protected]1 | 227 | PARAM@213..232 |
228 | POUND@213..214 "#" | 228 | ATTR@213..221 |
229 | WHITESPACE@214..215 " " | 229 | POUND@213..214 "#" |
230 | L_BRACK@215..216 "[" | 230 | WHITESPACE@214..215 " " |
231 | PATH@216..220 | 231 | L_BRACK@215..216 "[" |
232 | PATH_SEGMENT@216..220 | 232 | [email protected] |
233 | NAME_REF@216..220 | 233 | PATH_SEGMENT@216..220 |
234 | IDENT@216..220 "attr" | 234 | NAME_REF@216..220 |
235 | R_BRACK@220..221 "]" | 235 | IDENT@216..220 "attr" |
236 | WHITESPACE@221..222 " " | 236 | R_BRACK@220..221 "]" |
237 | PARAM@222..232 | 237 | WHITESPACE@221..222 " " |
238 | [email protected] | 238 | [email protected] |
239 | [email protected] "mut" | 239 | [email protected] "mut" |
240 | [email protected] " " | 240 | [email protected] " " |
@@ -271,16 +271,16 @@ [email protected] | |||
271 | [email protected] "f" | 271 | [email protected] "f" |
272 | [email protected] | 272 | [email protected] |
273 | [email protected] "(" | 273 | [email protected] "(" |
274 | ATT[email protected]68 | 274 | SELF_PARAM@257..273 |
275 | POUND@257..258 "#" | 275 | ATTR@257..268 |
276 | L_BRACK@258..259 "[" | 276 | POUND@257..258 "#" |
277 | PATH@259..267 | 277 | L_BRACK@258..259 "[" |
278 | PATH_SEGMENT@259..267 | 278 | [email protected] |
279 | NAME_REF@259..267 | 279 | PATH_SEGMENT@259..267 |
280 | IDENT@259..267 "must_use" | 280 | NAME_REF@259..267 |
281 | R_BRACK@267..268 "]" | 281 | IDENT@259..267 "must_use" |
282 | WHITESPACE@268..269 " " | 282 | R_BRACK@267..268 "]" |
283 | SELF_PARAM@269..273 | 283 | WHITESPACE@268..269 " " |
284 | [email protected] "self" | 284 | [email protected] "self" |
285 | [email protected] ")" | 285 | [email protected] ")" |
286 | [email protected] " " | 286 | [email protected] " " |
@@ -295,16 +295,16 @@ [email protected] | |||
295 | [email protected] "g1" | 295 | [email protected] "g1" |
296 | [email protected] | 296 | [email protected] |
297 | [email protected] "(" | 297 | [email protected] "(" |
298 | ATTR@289..296 | 298 | SELF_PARAM@289..301 |
299 | POUND@289..290 "#" | 299 | ATTR@289..296 |
300 | L_BRACK@290..291 "[" | 300 | POUND@289..290 "#" |
301 | PATH@291..295 | 301 | L_BRACK@290..291 "[" |
302 | PATH_SEGMENT@291..295 | 302 | [email protected] |
303 | NAME_REF@291..295 | 303 | PATH_SEGMENT@291..295 |
304 | IDENT@291..295 "attr" | 304 | NAME_REF@291..295 |
305 | R_BRACK@295..296 "]" | 305 | IDENT@291..295 "attr" |
306 | WHITESPACE@296..297 " " | 306 | R_BRACK@295..296 "]" |
307 | SELF_PARAM@297..301 | 307 | WHITESPACE@296..297 " " |
308 | [email protected] "self" | 308 | [email protected] "self" |
309 | [email protected] ")" | 309 | [email protected] ")" |
310 | [email protected] " " | 310 | [email protected] " " |
@@ -319,16 +319,16 @@ [email protected] | |||
319 | [email protected] "g2" | 319 | [email protected] "g2" |
320 | [email protected] | 320 | [email protected] |
321 | [email protected] "(" | 321 | [email protected] "(" |
322 | ATT[email protected]24 | 322 | SELF_PARAM@317..330 |
323 | POUND@317..318 "#" | 323 | ATTR@317..324 |
324 | L_BRACK@318..319 "[" | 324 | POUND@317..318 "#" |
325 | PATH@319..323 | 325 | L_BRACK@318..319 "[" |
326 | PATH_SEGMENT@319..323 | 326 | [email protected] |
327 | NAME_REF@319..323 | 327 | PATH_SEGMENT@319..323 |
328 | IDENT@319..323 "attr" | 328 | NAME_REF@319..323 |
329 | R_BRACK@323..324 "]" | 329 | IDENT@319..323 "attr" |
330 | WHITESPACE@324..325 " " | 330 | R_BRACK@323..324 "]" |
331 | SELF_PARAM@325..330 | 331 | WHITESPACE@324..325 " " |
332 | [email protected] "&" | 332 | [email protected] "&" |
333 | [email protected] "self" | 333 | [email protected] "self" |
334 | [email protected] ")" | 334 | [email protected] ")" |
@@ -350,16 +350,16 @@ [email protected] | |||
350 | [email protected] ">" | 350 | [email protected] ">" |
351 | [email protected] | 351 | [email protected] |
352 | [email protected] "(" | 352 | [email protected] "(" |
353 | ATT[email protected]57 | 353 | SELF_PARAM@350..367 |
354 | POUND@350..351 "#" | 354 | ATTR@350..357 |
355 | L_BRACK@351..352 "[" | 355 | POUND@350..351 "#" |
356 | PATH@352..356 | 356 | L_BRACK@351..352 "[" |
357 | PATH_SEGMENT@352..356 | 357 | [email protected] |
358 | NAME_REF@352..356 | 358 | PATH_SEGMENT@352..356 |
359 | IDENT@352..356 "attr" | 359 | NAME_REF@352..356 |
360 | R_BRACK@356..357 "]" | 360 | IDENT@352..356 "attr" |
361 | WHITESPACE@357..358 " " | 361 | R_BRACK@356..357 "]" |
362 | SELF_PARAM@358..367 | 362 | WHITESPACE@357..358 " " |
363 | [email protected] "&" | 363 | [email protected] "&" |
364 | [email protected] "mut" | 364 | [email protected] "mut" |
365 | [email protected] " " | 365 | [email protected] " " |
@@ -383,16 +383,16 @@ [email protected] | |||
383 | [email protected] ">" | 383 | [email protected] ">" |
384 | [email protected] | 384 | [email protected] |
385 | [email protected] "(" | 385 | [email protected] "(" |
386 | ATTR@387..394 | 386 | SELF_PARAM@387..403 |
387 | POUND@387..388 "#" | 387 | ATTR@387..394 |
388 | L_BRACK@388..389 "[" | 388 | POUND@387..388 "#" |
389 | PATH@389..393 | 389 | L_BRACK@388..389 "[" |
390 | PATH_SEGMENT@389..393 | 390 | [email protected] |
391 | NAME_REF@389..393 | 391 | PATH_SEGMENT@389..393 |
392 | IDENT@389..393 "attr" | 392 | NAME_REF@389..393 |
393 | R_BRACK@393..394 "]" | 393 | IDENT@389..393 "attr" |
394 | WHITESPACE@394..395 " " | 394 | R_BRACK@393..394 "]" |
395 | SELF_PARAM@395..403 | 395 | WHITESPACE@394..395 " " |
396 | [email protected] "&" | 396 | [email protected] "&" |
397 | [email protected] | 397 | [email protected] |
398 | [email protected] "\'a" | 398 | [email protected] "\'a" |
@@ -417,16 +417,16 @@ [email protected] | |||
417 | [email protected] ">" | 417 | [email protected] ">" |
418 | [email protected] | 418 | [email protected] |
419 | [email protected] "(" | 419 | [email protected] "(" |
420 | ATT[email protected]0 | 420 | SELF_PARAM@423..443 |
421 | POUND@423..424 "#" | 421 | ATTR@423..430 |
422 | L_BRACK@424..425 "[" | 422 | POUND@423..424 "#" |
423 | PATH@425..429 | 423 | L_BRACK@424..425 "[" |
424 | PATH_SEGMENT@425..429 | 424 | [email protected] |
425 | NAME_REF@425..429 | 425 | PATH_SEGMENT@425..429 |
426 | IDENT@425..429 "attr" | 426 | NAME_REF@425..429 |
427 | R_BRACK@429..430 "]" | 427 | IDENT@425..429 "attr" |
428 | WHITESPACE@430..431 " " | 428 | R_BRACK@429..430 "]" |
429 | SELF_PARAM@431..443 | 429 | WHITESPACE@430..431 " " |
430 | [email protected] "&" | 430 | [email protected] "&" |
431 | [email protected] | 431 | [email protected] |
432 | [email protected] "\'a" | 432 | [email protected] "\'a" |
@@ -447,16 +447,16 @@ [email protected] | |||
447 | [email protected] "c" | 447 | [email protected] "c" |
448 | [email protected] | 448 | [email protected] |
449 | [email protected] "(" | 449 | [email protected] "(" |
450 | ATT[email protected]5 | 450 | SELF_PARAM@458..476 |
451 | POUND@458..459 "#" | 451 | ATTR@458..465 |
452 | L_BRACK@459..460 "[" | 452 | POUND@458..459 "#" |
453 | PATH@460..464 | 453 | L_BRACK@459..460 "[" |
454 | PATH_SEGMENT@460..464 | 454 | [email protected] |
455 | NAME_REF@460..464 | 455 | PATH_SEGMENT@460..464 |
456 | IDENT@460..464 "attr" | 456 | NAME_REF@460..464 |
457 | R_BRACK@464..465 "]" | 457 | IDENT@460..464 "attr" |
458 | WHITESPACE@465..466 " " | 458 | R_BRACK@464..465 "]" |
459 | SELF_PARAM@466..476 | 459 | WHITESPACE@465..466 " " |
460 | [email protected] "self" | 460 | [email protected] "self" |
461 | [email protected] ":" | 461 | [email protected] ":" |
462 | [email protected] " " | 462 | [email protected] " " |
@@ -478,16 +478,16 @@ [email protected] | |||
478 | [email protected] "d" | 478 | [email protected] "d" |
479 | [email protected] | 479 | [email protected] |
480 | [email protected] "(" | 480 | [email protected] "(" |
481 | ATTR@491..498 | 481 | SELF_PARAM@491..513 |
482 | POUND@491..492 "#" | 482 | ATTR@491..498 |
483 | L_BRACK@492..493 "[" | 483 | POUND@491..492 "#" |
484 | PATH@493..497 | 484 | L_BRACK@492..493 "[" |
485 | PATH_SEGMENT@493..497 | 485 | [email protected] |
486 | NAME_REF@493..497 | 486 | PATH_SEGMENT@493..497 |
487 | IDENT@493..497 "attr" | 487 | NAME_REF@493..497 |
488 | R_BRACK@497..498 "]" | 488 | IDENT@493..497 "attr" |
489 | WHITESPACE@498..499 " " | 489 | R_BRACK@497..498 "]" |
490 | SELF_PARAM@499..513 | 490 | WHITESPACE@498..499 " " |
491 | [email protected] "self" | 491 | [email protected] "self" |
492 | [email protected] ":" | 492 | [email protected] ":" |
493 | [email protected] " " | 493 | [email protected] " " |
diff --git a/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast b/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast index 4009b3ff8..f7c094898 100644 --- a/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast +++ b/crates/syntax/test_data/parser/ok/0063_variadic_fun.rast | |||
@@ -92,20 +92,20 @@ [email protected] | |||
92 | [email protected] "u8" | 92 | [email protected] "u8" |
93 | [email protected] "," | 93 | [email protected] "," |
94 | [email protected] " " | 94 | [email protected] " " |
95 | ATT[email protected]5 | 95 | PARAM@92..120 |
96 | POUND@92..93 "#" | 96 | ATTR@92..105 |
97 | L_BRACK@93..94 "[" | 97 | POUND@92..93 "#" |
98 | PATH@94..97 | 98 | L_BRACK@93..94 "[" |
99 | PATH_SEGMENT@94..97 | 99 | [email protected] |
100 | NAME_REF@94..97 | 100 | PATH_SEGMENT@94..97 |
101 | IDENT@94..97 "cfg" | 101 | NAME_REF@94..97 |
102 | TOKEN_TREE@97..104 | 102 | IDENT@94..97 "cfg" |
103 | L_PAREN@97..98 "(" | 103 | TOKEN_TREE@97..104 |
104 | IDENT@98..103 "never" | 104 | L_PAREN@97..98 "(" |
105 | R_PAREN@103..104 ")" | 105 | IDENT@98..103 "never" |
106 | R_BRACK@104..105 "]" | 106 | R_PAREN@103..104 ")" |
107 | WHITESPACE@105..106 " " | 107 | R_BRACK@104..105 "]" |
108 | PARAM@106..120 | 108 | WHITESPACE@105..106 " " |
109 | [email protected] | 109 | [email protected] |
110 | [email protected] "[" | 110 | [email protected] "[" |
111 | [email protected] | 111 | [email protected] |