diff options
90 files changed, 1402 insertions, 331 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7b9fbe6b8..889ada401 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml | |||
@@ -124,10 +124,10 @@ jobs: | |||
124 | - name: Checkout repository | 124 | - name: Checkout repository |
125 | uses: actions/checkout@v2 | 125 | uses: actions/checkout@v2 |
126 | 126 | ||
127 | - name: Install Rust toolchain (beta) | 127 | - name: Install Rust toolchain |
128 | uses: actions-rs/toolchain@v1 | 128 | uses: actions-rs/toolchain@v1 |
129 | with: | 129 | with: |
130 | toolchain: beta | 130 | toolchain: stable |
131 | target: aarch64-apple-darwin | 131 | target: aarch64-apple-darwin |
132 | profile: minimal | 132 | profile: minimal |
133 | override: true | 133 | override: true |
diff --git a/Cargo.lock b/Cargo.lock index 1aa0c072d..4aaee3ab1 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -386,11 +386,11 @@ dependencies = [ | |||
386 | 386 | ||
387 | [[package]] | 387 | [[package]] |
388 | name = "expect-test" | 388 | name = "expect-test" |
389 | version = "1.0.2" | 389 | version = "1.1.0" |
390 | source = "registry+https://github.com/rust-lang/crates.io-index" | 390 | source = "registry+https://github.com/rust-lang/crates.io-index" |
391 | checksum = "eab78d4c727fa879de40951ffc01ed781a231b28786b19d6bfbdc0d1ec92eb3e" | 391 | checksum = "2300477aab3a378f2ca00a4fbd4dc713654ab7ed790e4017493cb33656280633" |
392 | dependencies = [ | 392 | dependencies = [ |
393 | "difference", | 393 | "dissimilar", |
394 | "once_cell", | 394 | "once_cell", |
395 | ] | 395 | ] |
396 | 396 | ||
diff --git a/crates/assists/src/ast_transform.rs b/crates/assists/src/ast_transform.rs index da94e9987..4a3ed7783 100644 --- a/crates/assists/src/ast_transform.rs +++ b/crates/assists/src/ast_transform.rs | |||
@@ -204,7 +204,8 @@ impl<'a> AstTransform<'a> for QualifyPaths<'a> { | |||
204 | } | 204 | } |
205 | PathResolution::Local(_) | 205 | PathResolution::Local(_) |
206 | | PathResolution::TypeParam(_) | 206 | | PathResolution::TypeParam(_) |
207 | | PathResolution::SelfType(_) => None, | 207 | | PathResolution::SelfType(_) |
208 | | PathResolution::ConstParam(_) => None, | ||
208 | PathResolution::Macro(_) => None, | 209 | PathResolution::Macro(_) => None, |
209 | PathResolution::AssocItem(_) => None, | 210 | PathResolution::AssocItem(_) => None, |
210 | } | 211 | } |
diff --git a/crates/assists/src/handlers/extract_assignment.rs b/crates/assists/src/handlers/extract_assignment.rs new file mode 100644 index 000000000..ae99598c0 --- /dev/null +++ b/crates/assists/src/handlers/extract_assignment.rs | |||
@@ -0,0 +1,400 @@ | |||
1 | use syntax::{ | ||
2 | ast::{self, edit::AstNodeEdit, make}, | ||
3 | AstNode, | ||
4 | }; | ||
5 | use test_utils::mark; | ||
6 | |||
7 | use crate::{ | ||
8 | assist_context::{AssistContext, Assists}, | ||
9 | AssistId, AssistKind, | ||
10 | }; | ||
11 | |||
12 | // Assist: extract_assignment | ||
13 | // | ||
14 | // Extracts variable assigment to outside an if or match statement. | ||
15 | // | ||
16 | // ``` | ||
17 | // fn main() { | ||
18 | // let mut foo = 6; | ||
19 | // | ||
20 | // if true { | ||
21 | // <|>foo = 5; | ||
22 | // } else { | ||
23 | // foo = 4; | ||
24 | // } | ||
25 | // } | ||
26 | // ``` | ||
27 | // -> | ||
28 | // ``` | ||
29 | // fn main() { | ||
30 | // let mut foo = 6; | ||
31 | // | ||
32 | // foo = if true { | ||
33 | // 5 | ||
34 | // } else { | ||
35 | // 4 | ||
36 | // }; | ||
37 | // } | ||
38 | // ``` | ||
39 | pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
40 | let assign_expr = ctx.find_node_at_offset::<ast::BinExpr>()?; | ||
41 | let name_expr = if assign_expr.op_kind()? == ast::BinOp::Assignment { | ||
42 | assign_expr.lhs()? | ||
43 | } else { | ||
44 | return None; | ||
45 | }; | ||
46 | |||
47 | let (old_stmt, new_stmt) = if let Some(if_expr) = ctx.find_node_at_offset::<ast::IfExpr>() { | ||
48 | ( | ||
49 | ast::Expr::cast(if_expr.syntax().to_owned())?, | ||
50 | exprify_if(&if_expr, &ctx.sema, &name_expr)?.indent(if_expr.indent_level()), | ||
51 | ) | ||
52 | } else if let Some(match_expr) = ctx.find_node_at_offset::<ast::MatchExpr>() { | ||
53 | ( | ||
54 | ast::Expr::cast(match_expr.syntax().to_owned())?, | ||
55 | exprify_match(&match_expr, &ctx.sema, &name_expr)?, | ||
56 | ) | ||
57 | } else { | ||
58 | return None; | ||
59 | }; | ||
60 | |||
61 | let expr_stmt = make::expr_stmt(new_stmt); | ||
62 | |||
63 | acc.add( | ||
64 | AssistId("extract_assignment", AssistKind::RefactorExtract), | ||
65 | "Extract assignment", | ||
66 | old_stmt.syntax().text_range(), | ||
67 | move |edit| { | ||
68 | edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name_expr, expr_stmt)); | ||
69 | }, | ||
70 | ) | ||
71 | } | ||
72 | |||
73 | fn exprify_match( | ||
74 | match_expr: &ast::MatchExpr, | ||
75 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
76 | name: &ast::Expr, | ||
77 | ) -> Option<ast::Expr> { | ||
78 | let new_arm_list = match_expr | ||
79 | .match_arm_list()? | ||
80 | .arms() | ||
81 | .map(|arm| { | ||
82 | if let ast::Expr::BlockExpr(block) = arm.expr()? { | ||
83 | let new_block = exprify_block(&block, sema, name)?.indent(block.indent_level()); | ||
84 | Some(arm.replace_descendant(block, new_block)) | ||
85 | } else { | ||
86 | None | ||
87 | } | ||
88 | }) | ||
89 | .collect::<Option<Vec<_>>>()?; | ||
90 | let new_arm_list = match_expr | ||
91 | .match_arm_list()? | ||
92 | .replace_descendants(match_expr.match_arm_list()?.arms().zip(new_arm_list)); | ||
93 | Some(make::expr_match(match_expr.expr()?, new_arm_list)) | ||
94 | } | ||
95 | |||
96 | fn exprify_if( | ||
97 | statement: &ast::IfExpr, | ||
98 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
99 | name: &ast::Expr, | ||
100 | ) -> Option<ast::Expr> { | ||
101 | let then_branch = exprify_block(&statement.then_branch()?, sema, name)?; | ||
102 | let else_branch = match statement.else_branch()? { | ||
103 | ast::ElseBranch::Block(ref block) => { | ||
104 | ast::ElseBranch::Block(exprify_block(block, sema, name)?) | ||
105 | } | ||
106 | ast::ElseBranch::IfExpr(expr) => { | ||
107 | mark::hit!(test_extract_assigment_chained_if); | ||
108 | ast::ElseBranch::IfExpr(ast::IfExpr::cast( | ||
109 | exprify_if(&expr, sema, name)?.syntax().to_owned(), | ||
110 | )?) | ||
111 | } | ||
112 | }; | ||
113 | Some(make::expr_if(statement.condition()?, then_branch, Some(else_branch))) | ||
114 | } | ||
115 | |||
116 | fn exprify_block( | ||
117 | block: &ast::BlockExpr, | ||
118 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
119 | name: &ast::Expr, | ||
120 | ) -> Option<ast::BlockExpr> { | ||
121 | if block.expr().is_some() { | ||
122 | return None; | ||
123 | } | ||
124 | |||
125 | let mut stmts: Vec<_> = block.statements().collect(); | ||
126 | let stmt = stmts.pop()?; | ||
127 | |||
128 | if let ast::Stmt::ExprStmt(stmt) = stmt { | ||
129 | if let ast::Expr::BinExpr(expr) = stmt.expr()? { | ||
130 | if expr.op_kind()? == ast::BinOp::Assignment && is_equivalent(sema, &expr.lhs()?, name) | ||
131 | { | ||
132 | // The last statement in the block is an assignment to the name we want | ||
133 | return Some(make::block_expr(stmts, Some(expr.rhs()?))); | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | None | ||
138 | } | ||
139 | |||
140 | fn is_equivalent( | ||
141 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
142 | expr0: &ast::Expr, | ||
143 | expr1: &ast::Expr, | ||
144 | ) -> bool { | ||
145 | match (expr0, expr1) { | ||
146 | (ast::Expr::FieldExpr(field_expr0), ast::Expr::FieldExpr(field_expr1)) => { | ||
147 | mark::hit!(test_extract_assignment_field_assignment); | ||
148 | sema.resolve_field(field_expr0) == sema.resolve_field(field_expr1) | ||
149 | } | ||
150 | (ast::Expr::PathExpr(path0), ast::Expr::PathExpr(path1)) => { | ||
151 | let path0 = path0.path(); | ||
152 | let path1 = path1.path(); | ||
153 | if let (Some(path0), Some(path1)) = (path0, path1) { | ||
154 | sema.resolve_path(&path0) == sema.resolve_path(&path1) | ||
155 | } else { | ||
156 | false | ||
157 | } | ||
158 | } | ||
159 | _ => false, | ||
160 | } | ||
161 | } | ||
162 | |||
163 | #[cfg(test)] | ||
164 | mod tests { | ||
165 | use super::*; | ||
166 | |||
167 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
168 | |||
169 | #[test] | ||
170 | fn test_extract_assignment_if() { | ||
171 | check_assist( | ||
172 | extract_assigment, | ||
173 | r#" | ||
174 | fn foo() { | ||
175 | let mut a = 1; | ||
176 | |||
177 | if true { | ||
178 | <|>a = 2; | ||
179 | } else { | ||
180 | a = 3; | ||
181 | } | ||
182 | }"#, | ||
183 | r#" | ||
184 | fn foo() { | ||
185 | let mut a = 1; | ||
186 | |||
187 | a = if true { | ||
188 | 2 | ||
189 | } else { | ||
190 | 3 | ||
191 | }; | ||
192 | }"#, | ||
193 | ); | ||
194 | } | ||
195 | |||
196 | #[test] | ||
197 | fn test_extract_assignment_match() { | ||
198 | check_assist( | ||
199 | extract_assigment, | ||
200 | r#" | ||
201 | fn foo() { | ||
202 | let mut a = 1; | ||
203 | |||
204 | match 1 { | ||
205 | 1 => { | ||
206 | <|>a = 2; | ||
207 | }, | ||
208 | 2 => { | ||
209 | a = 3; | ||
210 | }, | ||
211 | 3 => { | ||
212 | a = 4; | ||
213 | } | ||
214 | } | ||
215 | }"#, | ||
216 | r#" | ||
217 | fn foo() { | ||
218 | let mut a = 1; | ||
219 | |||
220 | a = match 1 { | ||
221 | 1 => { | ||
222 | 2 | ||
223 | }, | ||
224 | 2 => { | ||
225 | 3 | ||
226 | }, | ||
227 | 3 => { | ||
228 | 4 | ||
229 | } | ||
230 | }; | ||
231 | }"#, | ||
232 | ); | ||
233 | } | ||
234 | |||
235 | #[test] | ||
236 | fn test_extract_assignment_not_last_not_applicable() { | ||
237 | check_assist_not_applicable( | ||
238 | extract_assigment, | ||
239 | r#" | ||
240 | fn foo() { | ||
241 | let mut a = 1; | ||
242 | |||
243 | if true { | ||
244 | <|>a = 2; | ||
245 | b = a; | ||
246 | } else { | ||
247 | a = 3; | ||
248 | } | ||
249 | }"#, | ||
250 | ) | ||
251 | } | ||
252 | |||
253 | #[test] | ||
254 | fn test_extract_assignment_chained_if() { | ||
255 | mark::check!(test_extract_assigment_chained_if); | ||
256 | check_assist( | ||
257 | extract_assigment, | ||
258 | r#" | ||
259 | fn foo() { | ||
260 | let mut a = 1; | ||
261 | |||
262 | if true { | ||
263 | <|>a = 2; | ||
264 | } else if false { | ||
265 | a = 3; | ||
266 | } else { | ||
267 | a = 4; | ||
268 | } | ||
269 | }"#, | ||
270 | r#" | ||
271 | fn foo() { | ||
272 | let mut a = 1; | ||
273 | |||
274 | a = if true { | ||
275 | 2 | ||
276 | } else if false { | ||
277 | 3 | ||
278 | } else { | ||
279 | 4 | ||
280 | }; | ||
281 | }"#, | ||
282 | ); | ||
283 | } | ||
284 | |||
285 | #[test] | ||
286 | fn test_extract_assigment_retains_stmts() { | ||
287 | check_assist( | ||
288 | extract_assigment, | ||
289 | r#" | ||
290 | fn foo() { | ||
291 | let mut a = 1; | ||
292 | |||
293 | if true { | ||
294 | let b = 2; | ||
295 | <|>a = 2; | ||
296 | } else { | ||
297 | let b = 3; | ||
298 | a = 3; | ||
299 | } | ||
300 | }"#, | ||
301 | r#" | ||
302 | fn foo() { | ||
303 | let mut a = 1; | ||
304 | |||
305 | a = if true { | ||
306 | let b = 2; | ||
307 | 2 | ||
308 | } else { | ||
309 | let b = 3; | ||
310 | 3 | ||
311 | }; | ||
312 | }"#, | ||
313 | ) | ||
314 | } | ||
315 | |||
316 | #[test] | ||
317 | fn extract_assignment_let_stmt_not_applicable() { | ||
318 | check_assist_not_applicable( | ||
319 | extract_assigment, | ||
320 | r#" | ||
321 | fn foo() { | ||
322 | let mut a = 1; | ||
323 | |||
324 | let b = if true { | ||
325 | <|>a = 2 | ||
326 | } else { | ||
327 | a = 3 | ||
328 | }; | ||
329 | }"#, | ||
330 | ) | ||
331 | } | ||
332 | |||
333 | #[test] | ||
334 | fn extract_assignment_if_missing_assigment_not_applicable() { | ||
335 | check_assist_not_applicable( | ||
336 | extract_assigment, | ||
337 | r#" | ||
338 | fn foo() { | ||
339 | let mut a = 1; | ||
340 | |||
341 | if true { | ||
342 | <|>a = 2; | ||
343 | } else {} | ||
344 | }"#, | ||
345 | ) | ||
346 | } | ||
347 | |||
348 | #[test] | ||
349 | fn extract_assignment_match_missing_assigment_not_applicable() { | ||
350 | check_assist_not_applicable( | ||
351 | extract_assigment, | ||
352 | r#" | ||
353 | fn foo() { | ||
354 | let mut a = 1; | ||
355 | |||
356 | match 1 { | ||
357 | 1 => { | ||
358 | <|>a = 2; | ||
359 | }, | ||
360 | 2 => { | ||
361 | a = 3; | ||
362 | }, | ||
363 | 3 => {}, | ||
364 | } | ||
365 | }"#, | ||
366 | ) | ||
367 | } | ||
368 | |||
369 | #[test] | ||
370 | fn test_extract_assignment_field_assignment() { | ||
371 | mark::check!(test_extract_assignment_field_assignment); | ||
372 | check_assist( | ||
373 | extract_assigment, | ||
374 | r#" | ||
375 | struct A(usize); | ||
376 | |||
377 | fn foo() { | ||
378 | let mut a = A(1); | ||
379 | |||
380 | if true { | ||
381 | <|>a.0 = 2; | ||
382 | } else { | ||
383 | a.0 = 3; | ||
384 | } | ||
385 | }"#, | ||
386 | r#" | ||
387 | struct A(usize); | ||
388 | |||
389 | fn foo() { | ||
390 | let mut a = A(1); | ||
391 | |||
392 | a.0 = if true { | ||
393 | 2 | ||
394 | } else { | ||
395 | 3 | ||
396 | }; | ||
397 | }"#, | ||
398 | ) | ||
399 | } | ||
400 | } | ||
diff --git a/crates/assists/src/handlers/fill_match_arms.rs b/crates/assists/src/handlers/fill_match_arms.rs index cb60a3128..f9a62b9fa 100644 --- a/crates/assists/src/handlers/fill_match_arms.rs +++ b/crates/assists/src/handlers/fill_match_arms.rs | |||
@@ -196,7 +196,7 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::Variant) -> Optio | |||
196 | let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?); | 196 | let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?); |
197 | 197 | ||
198 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though | 198 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though |
199 | let pat: ast::Pat = match var.source(db).value.kind() { | 199 | let pat: ast::Pat = match var.source(db)?.value.kind() { |
200 | ast::StructKind::Tuple(field_list) => { | 200 | ast::StructKind::Tuple(field_list) => { |
201 | let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count()); | 201 | let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count()); |
202 | make::tuple_struct_pat(path, pats).into() | 202 | make::tuple_struct_pat(path, pats).into() |
diff --git a/crates/assists/src/handlers/fix_visibility.rs b/crates/assists/src/handlers/fix_visibility.rs index 8558a8ff0..de1e8f0bf 100644 --- a/crates/assists/src/handlers/fix_visibility.rs +++ b/crates/assists/src/handlers/fix_visibility.rs | |||
@@ -97,7 +97,8 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> | |||
97 | let parent_name = parent.name(ctx.db()); | 97 | let parent_name = parent.name(ctx.db()); |
98 | let target_module = parent.module(ctx.db()); | 98 | let target_module = parent.module(ctx.db()); |
99 | 99 | ||
100 | let in_file_source = record_field_def.source(ctx.db()); | 100 | #[allow(deprecated)] |
101 | let in_file_source = record_field_def.source(ctx.db())?; | ||
101 | let (offset, current_visibility, target) = match in_file_source.value { | 102 | let (offset, current_visibility, target) = match in_file_source.value { |
102 | hir::FieldSource::Named(it) => { | 103 | hir::FieldSource::Named(it) => { |
103 | let s = it.syntax(); | 104 | let s = it.syntax(); |
@@ -145,53 +146,53 @@ fn target_data_for_def( | |||
145 | fn offset_target_and_file_id<S, Ast>( | 146 | fn offset_target_and_file_id<S, Ast>( |
146 | db: &dyn HirDatabase, | 147 | db: &dyn HirDatabase, |
147 | x: S, | 148 | x: S, |
148 | ) -> (TextSize, Option<ast::Visibility>, TextRange, FileId) | 149 | ) -> Option<(TextSize, Option<ast::Visibility>, TextRange, FileId)> |
149 | where | 150 | where |
150 | S: HasSource<Ast = Ast>, | 151 | S: HasSource<Ast = Ast>, |
151 | Ast: AstNode + ast::VisibilityOwner, | 152 | Ast: AstNode + ast::VisibilityOwner, |
152 | { | 153 | { |
153 | let source = x.source(db); | 154 | let source = x.source(db)?; |
154 | let in_file_syntax = source.syntax(); | 155 | let in_file_syntax = source.syntax(); |
155 | let file_id = in_file_syntax.file_id; | 156 | let file_id = in_file_syntax.file_id; |
156 | let syntax = in_file_syntax.value; | 157 | let syntax = in_file_syntax.value; |
157 | let current_visibility = source.value.visibility(); | 158 | let current_visibility = source.value.visibility(); |
158 | ( | 159 | Some(( |
159 | vis_offset(syntax), | 160 | vis_offset(syntax), |
160 | current_visibility, | 161 | current_visibility, |
161 | syntax.text_range(), | 162 | syntax.text_range(), |
162 | file_id.original_file(db.upcast()), | 163 | file_id.original_file(db.upcast()), |
163 | ) | 164 | )) |
164 | } | 165 | } |
165 | 166 | ||
166 | let target_name; | 167 | let target_name; |
167 | let (offset, current_visibility, target, target_file) = match def { | 168 | let (offset, current_visibility, target, target_file) = match def { |
168 | hir::ModuleDef::Function(f) => { | 169 | hir::ModuleDef::Function(f) => { |
169 | target_name = Some(f.name(db)); | 170 | target_name = Some(f.name(db)); |
170 | offset_target_and_file_id(db, f) | 171 | offset_target_and_file_id(db, f)? |
171 | } | 172 | } |
172 | hir::ModuleDef::Adt(adt) => { | 173 | hir::ModuleDef::Adt(adt) => { |
173 | target_name = Some(adt.name(db)); | 174 | target_name = Some(adt.name(db)); |
174 | match adt { | 175 | match adt { |
175 | hir::Adt::Struct(s) => offset_target_and_file_id(db, s), | 176 | hir::Adt::Struct(s) => offset_target_and_file_id(db, s)?, |
176 | hir::Adt::Union(u) => offset_target_and_file_id(db, u), | 177 | hir::Adt::Union(u) => offset_target_and_file_id(db, u)?, |
177 | hir::Adt::Enum(e) => offset_target_and_file_id(db, e), | 178 | hir::Adt::Enum(e) => offset_target_and_file_id(db, e)?, |
178 | } | 179 | } |
179 | } | 180 | } |
180 | hir::ModuleDef::Const(c) => { | 181 | hir::ModuleDef::Const(c) => { |
181 | target_name = c.name(db); | 182 | target_name = c.name(db); |
182 | offset_target_and_file_id(db, c) | 183 | offset_target_and_file_id(db, c)? |
183 | } | 184 | } |
184 | hir::ModuleDef::Static(s) => { | 185 | hir::ModuleDef::Static(s) => { |
185 | target_name = s.name(db); | 186 | target_name = s.name(db); |
186 | offset_target_and_file_id(db, s) | 187 | offset_target_and_file_id(db, s)? |
187 | } | 188 | } |
188 | hir::ModuleDef::Trait(t) => { | 189 | hir::ModuleDef::Trait(t) => { |
189 | target_name = Some(t.name(db)); | 190 | target_name = Some(t.name(db)); |
190 | offset_target_and_file_id(db, t) | 191 | offset_target_and_file_id(db, t)? |
191 | } | 192 | } |
192 | hir::ModuleDef::TypeAlias(t) => { | 193 | hir::ModuleDef::TypeAlias(t) => { |
193 | target_name = Some(t.name(db)); | 194 | target_name = Some(t.name(db)); |
194 | offset_target_and_file_id(db, t) | 195 | offset_target_and_file_id(db, t)? |
195 | } | 196 | } |
196 | hir::ModuleDef::Module(m) => { | 197 | hir::ModuleDef::Module(m) => { |
197 | target_name = m.name(db); | 198 | target_name = m.name(db); |
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs index fdec886e9..212464f85 100644 --- a/crates/assists/src/lib.rs +++ b/crates/assists/src/lib.rs | |||
@@ -116,6 +116,7 @@ mod handlers { | |||
116 | mod convert_integer_literal; | 116 | mod convert_integer_literal; |
117 | mod early_return; | 117 | mod early_return; |
118 | mod expand_glob_import; | 118 | mod expand_glob_import; |
119 | mod extract_assignment; | ||
119 | mod extract_module_to_file; | 120 | mod extract_module_to_file; |
120 | mod extract_struct_from_enum_variant; | 121 | mod extract_struct_from_enum_variant; |
121 | mod extract_variable; | 122 | mod extract_variable; |
@@ -167,6 +168,7 @@ mod handlers { | |||
167 | convert_integer_literal::convert_integer_literal, | 168 | convert_integer_literal::convert_integer_literal, |
168 | early_return::convert_to_guarded_return, | 169 | early_return::convert_to_guarded_return, |
169 | expand_glob_import::expand_glob_import, | 170 | expand_glob_import::expand_glob_import, |
171 | extract_assignment::extract_assigment, | ||
170 | extract_module_to_file::extract_module_to_file, | 172 | extract_module_to_file::extract_module_to_file, |
171 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, | 173 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, |
172 | extract_variable::extract_variable, | 174 | extract_variable::extract_variable, |
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs index d3dfe24e7..b91a816e8 100644 --- a/crates/assists/src/tests/generated.rs +++ b/crates/assists/src/tests/generated.rs | |||
@@ -238,6 +238,35 @@ fn qux(bar: Bar, baz: Baz) {} | |||
238 | } | 238 | } |
239 | 239 | ||
240 | #[test] | 240 | #[test] |
241 | fn doctest_extract_assignment() { | ||
242 | check_doc_test( | ||
243 | "extract_assignment", | ||
244 | r#####" | ||
245 | fn main() { | ||
246 | let mut foo = 6; | ||
247 | |||
248 | if true { | ||
249 | <|>foo = 5; | ||
250 | } else { | ||
251 | foo = 4; | ||
252 | } | ||
253 | } | ||
254 | "#####, | ||
255 | r#####" | ||
256 | fn main() { | ||
257 | let mut foo = 6; | ||
258 | |||
259 | foo = if true { | ||
260 | 5 | ||
261 | } else { | ||
262 | 4 | ||
263 | }; | ||
264 | } | ||
265 | "#####, | ||
266 | ) | ||
267 | } | ||
268 | |||
269 | #[test] | ||
241 | fn doctest_extract_module_to_file() { | 270 | fn doctest_extract_module_to_file() { |
242 | check_doc_test( | 271 | check_doc_test( |
243 | "extract_module_to_file", | 272 | "extract_module_to_file", |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index d41084b59..b05596446 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -94,14 +94,18 @@ pub fn filter_assoc_items( | |||
94 | ast::AssocItem::MacroCall(_) => None, | 94 | ast::AssocItem::MacroCall(_) => None, |
95 | } | 95 | } |
96 | .is_some() | 96 | .is_some() |
97 | }; | 97 | } |
98 | 98 | ||
99 | items | 99 | items |
100 | .iter() | 100 | .iter() |
101 | .map(|i| match i { | 101 | // Note: This throws away items with no source. |
102 | hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db).value), | 102 | .filter_map(|i| { |
103 | hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db).value), | 103 | let item = match i { |
104 | hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db).value), | 104 | hir::AssocItem::Function(i) => ast::AssocItem::Fn(i.source(db)?.value), |
105 | hir::AssocItem::TypeAlias(i) => ast::AssocItem::TypeAlias(i.source(db)?.value), | ||
106 | hir::AssocItem::Const(i) => ast::AssocItem::Const(i.source(db)?.value), | ||
107 | }; | ||
108 | Some(item) | ||
105 | }) | 109 | }) |
106 | .filter(has_def_name) | 110 | .filter(has_def_name) |
107 | .filter(|it| match it { | 111 | .filter(|it| match it { |
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs index 9567bcc42..2dd8fbe67 100644 --- a/crates/base_db/src/input.rs +++ b/crates/base_db/src/input.rs | |||
@@ -190,10 +190,11 @@ pub struct CrateData { | |||
190 | pub proc_macro: Vec<ProcMacro>, | 190 | pub proc_macro: Vec<ProcMacro>, |
191 | } | 191 | } |
192 | 192 | ||
193 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 193 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
194 | pub enum Edition { | 194 | pub enum Edition { |
195 | Edition2018, | ||
196 | Edition2015, | 195 | Edition2015, |
196 | Edition2018, | ||
197 | Edition2021, | ||
197 | } | 198 | } |
198 | 199 | ||
199 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | 200 | #[derive(Default, Debug, Clone, PartialEq, Eq)] |
@@ -393,6 +394,7 @@ impl FromStr for Edition { | |||
393 | let res = match s { | 394 | let res = match s { |
394 | "2015" => Edition::Edition2015, | 395 | "2015" => Edition::Edition2015, |
395 | "2018" => Edition::Edition2018, | 396 | "2018" => Edition::Edition2018, |
397 | "2021" => Edition::Edition2021, | ||
396 | _ => return Err(ParseEditionError { invalid_input: s.to_string() }), | 398 | _ => return Err(ParseEditionError { invalid_input: s.to_string() }), |
397 | }; | 399 | }; |
398 | Ok(res) | 400 | Ok(res) |
@@ -404,6 +406,7 @@ impl fmt::Display for Edition { | |||
404 | f.write_str(match self { | 406 | f.write_str(match self { |
405 | Edition::Edition2015 => "2015", | 407 | Edition::Edition2015 => "2015", |
406 | Edition::Edition2018 => "2018", | 408 | Edition::Edition2018 => "2018", |
409 | Edition::Edition2021 => "2021", | ||
407 | }) | 410 | }) |
408 | } | 411 | } |
409 | } | 412 | } |
diff --git a/crates/cfg/Cargo.toml b/crates/cfg/Cargo.toml index c68e391c1..73247d130 100644 --- a/crates/cfg/Cargo.toml +++ b/crates/cfg/Cargo.toml | |||
@@ -17,4 +17,4 @@ tt = { path = "../tt", version = "0.0.0" } | |||
17 | [dev-dependencies] | 17 | [dev-dependencies] |
18 | mbe = { path = "../mbe" } | 18 | mbe = { path = "../mbe" } |
19 | syntax = { path = "../syntax" } | 19 | syntax = { path = "../syntax" } |
20 | expect-test = "1.0" | 20 | expect-test = "1.1" |
diff --git a/crates/completion/Cargo.toml b/crates/completion/Cargo.toml index 78e93e78e..99a1bdd54 100644 --- a/crates/completion/Cargo.toml +++ b/crates/completion/Cargo.toml | |||
@@ -28,4 +28,4 @@ test_utils = { path = "../test_utils", version = "0.0.0" } | |||
28 | hir = { path = "../hir", version = "0.0.0" } | 28 | hir = { path = "../hir", version = "0.0.0" } |
29 | 29 | ||
30 | [dev-dependencies] | 30 | [dev-dependencies] |
31 | expect-test = "1.0" | 31 | expect-test = "1.1" |
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs index d9fe13485..00c9e76f0 100644 --- a/crates/completion/src/completions.rs +++ b/crates/completion/src/completions.rs | |||
@@ -106,8 +106,9 @@ impl Completions { | |||
106 | func: hir::Function, | 106 | func: hir::Function, |
107 | local_name: Option<String>, | 107 | local_name: Option<String>, |
108 | ) { | 108 | ) { |
109 | let item = render_fn(RenderContext::new(ctx), None, local_name, func); | 109 | if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) { |
110 | self.add(item) | 110 | self.add(item) |
111 | } | ||
111 | } | 112 | } |
112 | 113 | ||
113 | pub(crate) fn add_variant_pat( | 114 | pub(crate) fn add_variant_pat( |
diff --git a/crates/completion/src/completions/record.rs b/crates/completion/src/completions/record.rs index 91bf4a8ad..e58b9a274 100644 --- a/crates/completion/src/completions/record.rs +++ b/crates/completion/src/completions/record.rs | |||
@@ -20,13 +20,17 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> | |||
20 | 20 | ||
21 | let missing_fields = ctx.sema.record_literal_missing_fields(record_lit); | 21 | let missing_fields = ctx.sema.record_literal_missing_fields(record_lit); |
22 | if impl_default_trait && !missing_fields.is_empty() { | 22 | if impl_default_trait && !missing_fields.is_empty() { |
23 | let completion_text = "..Default::default()"; | ||
24 | let completion_text = completion_text | ||
25 | .strip_prefix(ctx.token.to_string().as_str()) | ||
26 | .unwrap_or(completion_text); | ||
23 | acc.add( | 27 | acc.add( |
24 | CompletionItem::new( | 28 | CompletionItem::new( |
25 | CompletionKind::Snippet, | 29 | CompletionKind::Snippet, |
26 | ctx.source_range(), | 30 | ctx.source_range(), |
27 | "..Default::default()", | 31 | "..Default::default()", |
28 | ) | 32 | ) |
29 | .insert_text("..Default::default()") | 33 | .insert_text(completion_text) |
30 | .kind(CompletionItemKind::Field) | 34 | .kind(CompletionItemKind::Field) |
31 | .build(), | 35 | .build(), |
32 | ); | 36 | ); |
@@ -48,7 +52,10 @@ mod tests { | |||
48 | use expect_test::{expect, Expect}; | 52 | use expect_test::{expect, Expect}; |
49 | use ide_db::helpers::FamousDefs; | 53 | use ide_db::helpers::FamousDefs; |
50 | 54 | ||
51 | use crate::{test_utils::completion_list, CompletionKind}; | 55 | use crate::{ |
56 | test_utils::{self, completion_list}, | ||
57 | CompletionKind, | ||
58 | }; | ||
52 | 59 | ||
53 | fn check(ra_fixture: &str, expect: Expect) { | 60 | fn check(ra_fixture: &str, expect: Expect) { |
54 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | 61 | let actual = completion_list(ra_fixture, CompletionKind::Reference); |
@@ -63,6 +70,18 @@ mod tests { | |||
63 | expect.assert_eq(&actual); | 70 | expect.assert_eq(&actual); |
64 | } | 71 | } |
65 | 72 | ||
73 | fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | ||
74 | test_utils::check_edit( | ||
75 | what, | ||
76 | &format!( | ||
77 | "//- /main.rs crate:main deps:core{}\n{}", | ||
78 | ra_fixture_before, | ||
79 | FamousDefs::FIXTURE, | ||
80 | ), | ||
81 | &(ra_fixture_after.to_owned() + "\n"), | ||
82 | ); | ||
83 | } | ||
84 | |||
66 | #[test] | 85 | #[test] |
67 | fn test_record_literal_field_default() { | 86 | fn test_record_literal_field_default() { |
68 | let test_code = r#" | 87 | let test_code = r#" |
@@ -102,6 +121,51 @@ fn process(f: S) { | |||
102 | } | 121 | } |
103 | 122 | ||
104 | #[test] | 123 | #[test] |
124 | fn test_record_literal_field_default_completion() { | ||
125 | check_edit( | ||
126 | "..Default::default()", | ||
127 | r#" | ||
128 | struct S { foo: u32, bar: usize } | ||
129 | |||
130 | impl core::default::Default for S { | ||
131 | fn default() -> Self { | ||
132 | S { | ||
133 | foo: 0, | ||
134 | bar: 0, | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | |||
139 | fn process(f: S) { | ||
140 | let other = S { | ||
141 | foo: 5, | ||
142 | .<|> | ||
143 | }; | ||
144 | } | ||
145 | "#, | ||
146 | r#" | ||
147 | struct S { foo: u32, bar: usize } | ||
148 | |||
149 | impl core::default::Default for S { | ||
150 | fn default() -> Self { | ||
151 | S { | ||
152 | foo: 0, | ||
153 | bar: 0, | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | |||
158 | fn process(f: S) { | ||
159 | let other = S { | ||
160 | foo: 5, | ||
161 | ..Default::default() | ||
162 | }; | ||
163 | } | ||
164 | "#, | ||
165 | ); | ||
166 | } | ||
167 | |||
168 | #[test] | ||
105 | fn test_record_literal_field_without_default() { | 169 | fn test_record_literal_field_without_default() { |
106 | let test_code = r#" | 170 | let test_code = r#" |
107 | struct S { foo: u32, bar: usize } | 171 | struct S { foo: u32, bar: usize } |
diff --git a/crates/completion/src/completions/trait_impl.rs b/crates/completion/src/completions/trait_impl.rs index c4e0d0669..54bb897e9 100644 --- a/crates/completion/src/completions/trait_impl.rs +++ b/crates/completion/src/completions/trait_impl.rs | |||
@@ -156,19 +156,21 @@ fn add_function_impl( | |||
156 | }; | 156 | }; |
157 | let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); | 157 | let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); |
158 | 158 | ||
159 | let function_decl = function_declaration(&func.source(ctx.db).value); | 159 | if let Some(src) = func.source(ctx.db) { |
160 | match ctx.config.snippet_cap { | 160 | let function_decl = function_declaration(&src.value); |
161 | Some(cap) => { | 161 | match ctx.config.snippet_cap { |
162 | let snippet = format!("{} {{\n $0\n}}", function_decl); | 162 | Some(cap) => { |
163 | builder.snippet_edit(cap, TextEdit::replace(range, snippet)) | 163 | let snippet = format!("{} {{\n $0\n}}", function_decl); |
164 | } | 164 | builder.snippet_edit(cap, TextEdit::replace(range, snippet)) |
165 | None => { | 165 | } |
166 | let header = format!("{} {{", function_decl); | 166 | None => { |
167 | builder.text_edit(TextEdit::replace(range, header)) | 167 | let header = format!("{} {{", function_decl); |
168 | builder.text_edit(TextEdit::replace(range, header)) | ||
169 | } | ||
168 | } | 170 | } |
171 | .kind(completion_kind) | ||
172 | .add_to(acc); | ||
169 | } | 173 | } |
170 | .kind(completion_kind) | ||
171 | .add_to(acc); | ||
172 | } | 174 | } |
173 | 175 | ||
174 | fn add_type_alias_impl( | 176 | fn add_type_alias_impl( |
@@ -200,16 +202,19 @@ fn add_const_impl( | |||
200 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); | 202 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); |
201 | 203 | ||
202 | if let Some(const_name) = const_name { | 204 | if let Some(const_name) = const_name { |
203 | let snippet = make_const_compl_syntax(&const_.source(ctx.db).value); | 205 | if let Some(source) = const_.source(ctx.db) { |
204 | 206 | let snippet = make_const_compl_syntax(&source.value); | |
205 | let range = TextRange::new(const_def_node.text_range().start(), ctx.source_range().end()); | 207 | |
206 | 208 | let range = | |
207 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) | 209 | TextRange::new(const_def_node.text_range().start(), ctx.source_range().end()); |
208 | .text_edit(TextEdit::replace(range, snippet)) | 210 | |
209 | .lookup_by(const_name) | 211 | CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) |
210 | .kind(CompletionItemKind::Const) | 212 | .text_edit(TextEdit::replace(range, snippet)) |
211 | .set_documentation(const_.docs(ctx.db)) | 213 | .lookup_by(const_name) |
212 | .add_to(acc); | 214 | .kind(CompletionItemKind::Const) |
215 | .set_documentation(const_.docs(ctx.db)) | ||
216 | .add_to(acc); | ||
217 | } | ||
213 | } | 218 | } |
214 | } | 219 | } |
215 | 220 | ||
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs index 1ba7201a1..ac0b2a513 100644 --- a/crates/completion/src/render.rs +++ b/crates/completion/src/render.rs | |||
@@ -157,8 +157,7 @@ impl<'a> Render<'a> { | |||
157 | 157 | ||
158 | let kind = match resolution { | 158 | let kind = match resolution { |
159 | ScopeDef::ModuleDef(Function(func)) => { | 159 | ScopeDef::ModuleDef(Function(func)) => { |
160 | let item = render_fn(self.ctx, import_to_add, Some(local_name), *func); | 160 | return render_fn(self.ctx, import_to_add, Some(local_name), *func); |
161 | return Some(item); | ||
162 | } | 161 | } |
163 | ScopeDef::ModuleDef(Variant(_)) | 162 | ScopeDef::ModuleDef(Variant(_)) |
164 | if self.ctx.completion.is_pat_binding_or_const | 163 | if self.ctx.completion.is_pat_binding_or_const |
diff --git a/crates/completion/src/render/const_.rs b/crates/completion/src/render/const_.rs index 039bdabc0..ce924f309 100644 --- a/crates/completion/src/render/const_.rs +++ b/crates/completion/src/render/const_.rs | |||
@@ -15,7 +15,7 @@ pub(crate) fn render_const<'a>( | |||
15 | ctx: RenderContext<'a>, | 15 | ctx: RenderContext<'a>, |
16 | const_: hir::Const, | 16 | const_: hir::Const, |
17 | ) -> Option<CompletionItem> { | 17 | ) -> Option<CompletionItem> { |
18 | ConstRender::new(ctx, const_).render() | 18 | ConstRender::new(ctx, const_)?.render() |
19 | } | 19 | } |
20 | 20 | ||
21 | #[derive(Debug)] | 21 | #[derive(Debug)] |
@@ -26,9 +26,9 @@ struct ConstRender<'a> { | |||
26 | } | 26 | } |
27 | 27 | ||
28 | impl<'a> ConstRender<'a> { | 28 | impl<'a> ConstRender<'a> { |
29 | fn new(ctx: RenderContext<'a>, const_: hir::Const) -> ConstRender<'a> { | 29 | fn new(ctx: RenderContext<'a>, const_: hir::Const) -> Option<ConstRender<'a>> { |
30 | let ast_node = const_.source(ctx.db()).value; | 30 | let ast_node = const_.source(ctx.db())?.value; |
31 | ConstRender { ctx, const_, ast_node } | 31 | Some(ConstRender { ctx, const_, ast_node }) |
32 | } | 32 | } |
33 | 33 | ||
34 | fn render(self) -> Option<CompletionItem> { | 34 | fn render(self) -> Option<CompletionItem> { |
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs index 316e05b52..081be14f4 100644 --- a/crates/completion/src/render/function.rs +++ b/crates/completion/src/render/function.rs | |||
@@ -14,9 +14,9 @@ pub(crate) fn render_fn<'a>( | |||
14 | import_to_add: Option<ImportEdit>, | 14 | import_to_add: Option<ImportEdit>, |
15 | local_name: Option<String>, | 15 | local_name: Option<String>, |
16 | fn_: hir::Function, | 16 | fn_: hir::Function, |
17 | ) -> CompletionItem { | 17 | ) -> Option<CompletionItem> { |
18 | let _p = profile::span("render_fn"); | 18 | let _p = profile::span("render_fn"); |
19 | FunctionRender::new(ctx, local_name, fn_).render(import_to_add) | 19 | Some(FunctionRender::new(ctx, local_name, fn_)?.render(import_to_add)) |
20 | } | 20 | } |
21 | 21 | ||
22 | #[derive(Debug)] | 22 | #[derive(Debug)] |
@@ -32,11 +32,11 @@ impl<'a> FunctionRender<'a> { | |||
32 | ctx: RenderContext<'a>, | 32 | ctx: RenderContext<'a>, |
33 | local_name: Option<String>, | 33 | local_name: Option<String>, |
34 | fn_: hir::Function, | 34 | fn_: hir::Function, |
35 | ) -> FunctionRender<'a> { | 35 | ) -> Option<FunctionRender<'a>> { |
36 | let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); | 36 | let name = local_name.unwrap_or_else(|| fn_.name(ctx.db()).to_string()); |
37 | let ast_node = fn_.source(ctx.db()).value; | 37 | let ast_node = fn_.source(ctx.db())?.value; |
38 | 38 | ||
39 | FunctionRender { ctx, name, func: fn_, ast_node } | 39 | Some(FunctionRender { ctx, name, func: fn_, ast_node }) |
40 | } | 40 | } |
41 | 41 | ||
42 | fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { | 42 | fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem { |
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs index dac79592f..6f4f9945c 100644 --- a/crates/completion/src/render/macro_.rs +++ b/crates/completion/src/render/macro_.rs | |||
@@ -39,20 +39,13 @@ impl<'a> MacroRender<'a> { | |||
39 | } | 39 | } |
40 | 40 | ||
41 | fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> { | 41 | fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> { |
42 | // FIXME: Currently proc-macro do not have ast-node, | ||
43 | // such that it does not have source | ||
44 | // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913 | ||
45 | if self.macro_.is_proc_macro() { | ||
46 | return None; | ||
47 | } | ||
48 | |||
49 | let mut builder = | 42 | let mut builder = |
50 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label()) | 43 | CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label()) |
51 | .kind(CompletionItemKind::Macro) | 44 | .kind(CompletionItemKind::Macro) |
52 | .set_documentation(self.docs.clone()) | 45 | .set_documentation(self.docs.clone()) |
53 | .set_deprecated(self.ctx.is_deprecated(self.macro_)) | 46 | .set_deprecated(self.ctx.is_deprecated(self.macro_)) |
54 | .add_import(import_to_add) | 47 | .add_import(import_to_add) |
55 | .detail(self.detail()); | 48 | .set_detail(self.detail()); |
56 | 49 | ||
57 | let needs_bang = self.needs_bang(); | 50 | let needs_bang = self.needs_bang(); |
58 | builder = match self.ctx.snippet_cap() { | 51 | builder = match self.ctx.snippet_cap() { |
@@ -95,9 +88,9 @@ impl<'a> MacroRender<'a> { | |||
95 | format!("{}!", self.name) | 88 | format!("{}!", self.name) |
96 | } | 89 | } |
97 | 90 | ||
98 | fn detail(&self) -> String { | 91 | fn detail(&self) -> Option<String> { |
99 | let ast_node = self.macro_.source(self.ctx.db()).value; | 92 | let ast_node = self.macro_.source(self.ctx.db())?.value; |
100 | macro_label(&ast_node) | 93 | Some(macro_label(&ast_node)) |
101 | } | 94 | } |
102 | } | 95 | } |
103 | 96 | ||
diff --git a/crates/completion/src/render/type_alias.rs b/crates/completion/src/render/type_alias.rs index 9605c7fa9..69b445b9c 100644 --- a/crates/completion/src/render/type_alias.rs +++ b/crates/completion/src/render/type_alias.rs | |||
@@ -15,7 +15,7 @@ pub(crate) fn render_type_alias<'a>( | |||
15 | ctx: RenderContext<'a>, | 15 | ctx: RenderContext<'a>, |
16 | type_alias: hir::TypeAlias, | 16 | type_alias: hir::TypeAlias, |
17 | ) -> Option<CompletionItem> { | 17 | ) -> Option<CompletionItem> { |
18 | TypeAliasRender::new(ctx, type_alias).render() | 18 | TypeAliasRender::new(ctx, type_alias)?.render() |
19 | } | 19 | } |
20 | 20 | ||
21 | #[derive(Debug)] | 21 | #[derive(Debug)] |
@@ -26,9 +26,9 @@ struct TypeAliasRender<'a> { | |||
26 | } | 26 | } |
27 | 27 | ||
28 | impl<'a> TypeAliasRender<'a> { | 28 | impl<'a> TypeAliasRender<'a> { |
29 | fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> TypeAliasRender<'a> { | 29 | fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> Option<TypeAliasRender<'a>> { |
30 | let ast_node = type_alias.source(ctx.db()).value; | 30 | let ast_node = type_alias.source(ctx.db())?.value; |
31 | TypeAliasRender { ctx, type_alias, ast_node } | 31 | Some(TypeAliasRender { ctx, type_alias, ast_node }) |
32 | } | 32 | } |
33 | 33 | ||
34 | fn render(self) -> Option<CompletionItem> { | 34 | fn render(self) -> Option<CompletionItem> { |
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index d32ce37ed..99fb65bac 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs | |||
@@ -3,15 +3,15 @@ use hir_def::{ | |||
3 | attr::{Attrs, Documentation}, | 3 | attr::{Attrs, Documentation}, |
4 | path::ModPath, | 4 | path::ModPath, |
5 | resolver::HasResolver, | 5 | resolver::HasResolver, |
6 | AttrDefId, ModuleDefId, | 6 | AttrDefId, GenericParamId, ModuleDefId, |
7 | }; | 7 | }; |
8 | use hir_expand::hygiene::Hygiene; | 8 | use hir_expand::hygiene::Hygiene; |
9 | use hir_ty::db::HirDatabase; | 9 | use hir_ty::db::HirDatabase; |
10 | use syntax::ast; | 10 | use syntax::ast; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | Adt, Const, Enum, Field, Function, MacroDef, Module, ModuleDef, Static, Struct, Trait, | 13 | Adt, Const, ConstParam, Enum, Field, Function, GenericParam, LifetimeParam, MacroDef, Module, |
14 | TypeAlias, Union, Variant, | 14 | ModuleDef, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | pub trait HasAttrs { | 17 | pub trait HasAttrs { |
@@ -62,25 +62,27 @@ impl_has_attrs![ | |||
62 | (Function, FunctionId), | 62 | (Function, FunctionId), |
63 | (Adt, AdtId), | 63 | (Adt, AdtId), |
64 | (Module, ModuleId), | 64 | (Module, ModuleId), |
65 | (GenericParam, GenericParamId), | ||
65 | ]; | 66 | ]; |
66 | 67 | ||
67 | macro_rules! impl_has_attrs_adt { | 68 | macro_rules! impl_has_attrs_enum { |
68 | ($($adt:ident),*) => {$( | 69 | ($($variant:ident),* for $enum:ident) => {$( |
69 | impl HasAttrs for $adt { | 70 | impl HasAttrs for $variant { |
70 | fn attrs(self, db: &dyn HirDatabase) -> Attrs { | 71 | fn attrs(self, db: &dyn HirDatabase) -> Attrs { |
71 | Adt::$adt(self).attrs(db) | 72 | $enum::$variant(self).attrs(db) |
72 | } | 73 | } |
73 | fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> { | 74 | fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> { |
74 | Adt::$adt(self).docs(db) | 75 | $enum::$variant(self).docs(db) |
75 | } | 76 | } |
76 | fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<ModuleDef> { | 77 | fn resolve_doc_path(self, db: &dyn HirDatabase, link: &str, ns: Option<Namespace>) -> Option<ModuleDef> { |
77 | Adt::$adt(self).resolve_doc_path(db, link, ns) | 78 | $enum::$variant(self).resolve_doc_path(db, link, ns) |
78 | } | 79 | } |
79 | } | 80 | } |
80 | )*}; | 81 | )*}; |
81 | } | 82 | } |
82 | 83 | ||
83 | impl_has_attrs_adt![Struct, Union, Enum]; | 84 | impl_has_attrs_enum![Struct, Union, Enum for Adt]; |
85 | impl_has_attrs_enum![TypeParam, ConstParam, LifetimeParam for GenericParam]; | ||
84 | 86 | ||
85 | fn resolve_doc_path( | 87 | fn resolve_doc_path( |
86 | db: &dyn HirDatabase, | 88 | db: &dyn HirDatabase, |
@@ -99,6 +101,12 @@ fn resolve_doc_path( | |||
99 | AttrDefId::TraitId(it) => it.resolver(db.upcast()), | 101 | AttrDefId::TraitId(it) => it.resolver(db.upcast()), |
100 | AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()), | 102 | AttrDefId::TypeAliasId(it) => it.resolver(db.upcast()), |
101 | AttrDefId::ImplId(it) => it.resolver(db.upcast()), | 103 | AttrDefId::ImplId(it) => it.resolver(db.upcast()), |
104 | AttrDefId::GenericParamId(it) => match it { | ||
105 | GenericParamId::TypeParamId(it) => it.parent, | ||
106 | GenericParamId::LifetimeParamId(it) => it.parent, | ||
107 | GenericParamId::ConstParamId(it) => it.parent, | ||
108 | } | ||
109 | .resolver(db.upcast()), | ||
102 | AttrDefId::MacroDefId(_) => return None, | 110 | AttrDefId::MacroDefId(_) => return None, |
103 | }; | 111 | }; |
104 | let path = ast::Path::parse(link).ok()?; | 112 | let path = ast::Path::parse(link).ok()?; |
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index b7ded3478..62eccf475 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -18,10 +18,10 @@ use hir_def::{ | |||
18 | resolver::{HasResolver, Resolver}, | 18 | resolver::{HasResolver, Resolver}, |
19 | src::HasSource as _, | 19 | src::HasSource as _, |
20 | type_ref::{Mutability, TypeRef}, | 20 | type_ref::{Mutability, TypeRef}, |
21 | AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, DefWithBodyId, EnumId, | 21 | AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, |
22 | FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, LocalEnumVariantId, LocalFieldId, | 22 | DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, |
23 | LocalModuleId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, | 23 | LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, TraitId, |
24 | UnionId, | 24 | TypeAliasId, TypeParamId, UnionId, |
25 | }; | 25 | }; |
26 | use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility}; | 26 | use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility}; |
27 | use hir_expand::{ | 27 | use hir_expand::{ |
@@ -39,7 +39,7 @@ use hir_ty::{ | |||
39 | TyDefId, TyKind, TypeCtor, | 39 | TyDefId, TyKind, TypeCtor, |
40 | }; | 40 | }; |
41 | use rustc_hash::FxHashSet; | 41 | use rustc_hash::FxHashSet; |
42 | use stdx::impl_from; | 42 | use stdx::{format_to, impl_from}; |
43 | use syntax::{ | 43 | use syntax::{ |
44 | ast::{self, AttrsOwner, NameOwner}, | 44 | ast::{self, AttrsOwner, NameOwner}, |
45 | AstNode, SmolStr, | 45 | AstNode, SmolStr, |
@@ -797,6 +797,19 @@ impl Function { | |||
797 | pub fn has_body(self, db: &dyn HirDatabase) -> bool { | 797 | pub fn has_body(self, db: &dyn HirDatabase) -> bool { |
798 | db.function_data(self.id).has_body | 798 | db.function_data(self.id).has_body |
799 | } | 799 | } |
800 | |||
801 | /// A textual representation of the HIR of this function for debugging purposes. | ||
802 | pub fn debug_hir(self, db: &dyn HirDatabase) -> String { | ||
803 | let body = db.body(self.id.into()); | ||
804 | |||
805 | let mut result = String::new(); | ||
806 | format_to!(result, "HIR expressions in the body of `{}`:\n", self.name(db)); | ||
807 | for (id, expr) in body.exprs.iter() { | ||
808 | format_to!(result, "{:?}: {:?}\n", id, expr); | ||
809 | } | ||
810 | |||
811 | result | ||
812 | } | ||
800 | } | 813 | } |
801 | 814 | ||
802 | // Note: logically, this belongs to `hir_ty`, but we are not using it there yet. | 815 | // Note: logically, this belongs to `hir_ty`, but we are not using it there yet. |
@@ -983,13 +996,7 @@ impl MacroDef { | |||
983 | 996 | ||
984 | /// XXX: this parses the file | 997 | /// XXX: this parses the file |
985 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { | 998 | pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { |
986 | // FIXME: Currently proc-macro do not have ast-node, | 999 | self.source(db)?.value.name().map(|it| it.as_name()) |
987 | // such that it does not have source | ||
988 | // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913 | ||
989 | if self.is_proc_macro() { | ||
990 | return None; | ||
991 | } | ||
992 | self.source(db).value.name().map(|it| it.as_name()) | ||
993 | } | 1000 | } |
994 | 1001 | ||
995 | /// Indicate it is a proc-macro | 1002 | /// Indicate it is a proc-macro |
@@ -1125,7 +1132,12 @@ impl GenericDef { | |||
1125 | id: LifetimeParamId { parent: self.into(), local_id }, | 1132 | id: LifetimeParamId { parent: self.into(), local_id }, |
1126 | }) | 1133 | }) |
1127 | .map(GenericParam::LifetimeParam); | 1134 | .map(GenericParam::LifetimeParam); |
1128 | ty_params.chain(lt_params).collect() | 1135 | let const_params = generics |
1136 | .consts | ||
1137 | .iter() | ||
1138 | .map(|(local_id, _)| ConstParam { id: ConstParamId { parent: self.into(), local_id } }) | ||
1139 | .map(GenericParam::ConstParam); | ||
1140 | ty_params.chain(lt_params).chain(const_params).collect() | ||
1129 | } | 1141 | } |
1130 | 1142 | ||
1131 | pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> { | 1143 | pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> { |
@@ -1237,8 +1249,9 @@ impl Label { | |||
1237 | pub enum GenericParam { | 1249 | pub enum GenericParam { |
1238 | TypeParam(TypeParam), | 1250 | TypeParam(TypeParam), |
1239 | LifetimeParam(LifetimeParam), | 1251 | LifetimeParam(LifetimeParam), |
1252 | ConstParam(ConstParam), | ||
1240 | } | 1253 | } |
1241 | impl_from!(TypeParam, LifetimeParam for GenericParam); | 1254 | impl_from!(TypeParam, LifetimeParam, ConstParam for GenericParam); |
1242 | 1255 | ||
1243 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 1256 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
1244 | pub struct TypeParam { | 1257 | pub struct TypeParam { |
@@ -1300,6 +1313,26 @@ impl LifetimeParam { | |||
1300 | } | 1313 | } |
1301 | } | 1314 | } |
1302 | 1315 | ||
1316 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
1317 | pub struct ConstParam { | ||
1318 | pub(crate) id: ConstParamId, | ||
1319 | } | ||
1320 | |||
1321 | impl ConstParam { | ||
1322 | pub fn name(self, db: &dyn HirDatabase) -> Name { | ||
1323 | let params = db.generic_params(self.id.parent); | ||
1324 | params.consts[self.id.local_id].name.clone() | ||
1325 | } | ||
1326 | |||
1327 | pub fn module(self, db: &dyn HirDatabase) -> Module { | ||
1328 | self.id.parent.module(db.upcast()).into() | ||
1329 | } | ||
1330 | |||
1331 | pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { | ||
1332 | self.id.parent.into() | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1303 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 1336 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
1304 | pub struct Impl { | 1337 | pub struct Impl { |
1305 | pub(crate) id: ImplId, | 1338 | pub(crate) id: ImplId, |
@@ -1352,7 +1385,7 @@ impl Impl { | |||
1352 | } | 1385 | } |
1353 | 1386 | ||
1354 | pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { | 1387 | pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { |
1355 | let src = self.source(db); | 1388 | let src = self.source(db)?; |
1356 | let item = src.file_id.is_builtin_derive(db.upcast())?; | 1389 | let item = src.file_id.is_builtin_derive(db.upcast())?; |
1357 | let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id); | 1390 | let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id); |
1358 | 1391 | ||
diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index a0792b9a6..3e47a5e9d 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs | |||
@@ -6,13 +6,13 @@ | |||
6 | use hir_def::{ | 6 | use hir_def::{ |
7 | expr::{LabelId, PatId}, | 7 | expr::{LabelId, PatId}, |
8 | item_scope::ItemInNs, | 8 | item_scope::ItemInNs, |
9 | AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, ModuleDefId, | 9 | AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, GenericParamId, |
10 | VariantId, | 10 | ModuleDefId, VariantId, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | Adt, AssocItem, DefWithBody, Field, GenericDef, Label, Local, MacroDef, ModuleDef, Variant, | 14 | code_model::GenericParam, Adt, AssocItem, DefWithBody, Field, GenericDef, Label, Local, |
15 | VariantDef, | 15 | MacroDef, ModuleDef, Variant, VariantDef, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | macro_rules! from_id { | 18 | macro_rules! from_id { |
@@ -44,6 +44,7 @@ from_id![ | |||
44 | (hir_def::ImplId, crate::Impl), | 44 | (hir_def::ImplId, crate::Impl), |
45 | (hir_def::TypeParamId, crate::TypeParam), | 45 | (hir_def::TypeParamId, crate::TypeParam), |
46 | (hir_def::LifetimeParamId, crate::LifetimeParam), | 46 | (hir_def::LifetimeParamId, crate::LifetimeParam), |
47 | (hir_def::ConstParamId, crate::ConstParam), | ||
47 | (hir_expand::MacroDefId, crate::MacroDef) | 48 | (hir_expand::MacroDefId, crate::MacroDef) |
48 | ]; | 49 | ]; |
49 | 50 | ||
@@ -67,6 +68,26 @@ impl From<Adt> for AdtId { | |||
67 | } | 68 | } |
68 | } | 69 | } |
69 | 70 | ||
71 | impl From<GenericParamId> for GenericParam { | ||
72 | fn from(id: GenericParamId) -> Self { | ||
73 | match id { | ||
74 | GenericParamId::TypeParamId(it) => GenericParam::TypeParam(it.into()), | ||
75 | GenericParamId::LifetimeParamId(it) => GenericParam::LifetimeParam(it.into()), | ||
76 | GenericParamId::ConstParamId(it) => GenericParam::ConstParam(it.into()), | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | impl From<GenericParam> for GenericParamId { | ||
82 | fn from(id: GenericParam) -> Self { | ||
83 | match id { | ||
84 | GenericParam::TypeParam(it) => GenericParamId::TypeParamId(it.id), | ||
85 | GenericParam::LifetimeParam(it) => GenericParamId::LifetimeParamId(it.id), | ||
86 | GenericParam::ConstParam(it) => GenericParamId::ConstParamId(it.id), | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | |||
70 | impl From<EnumVariantId> for Variant { | 91 | impl From<EnumVariantId> for Variant { |
71 | fn from(id: EnumVariantId) -> Self { | 92 | fn from(id: EnumVariantId) -> Self { |
72 | Variant { parent: id.parent.into(), id: id.local_id } | 93 | Variant { parent: id.parent.into(), id: id.local_id } |
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index 0dc07c33e..7c57d8378 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs | |||
@@ -10,13 +10,13 @@ use hir_expand::InFile; | |||
10 | use syntax::ast; | 10 | use syntax::ast; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | db::HirDatabase, Const, Enum, Field, FieldSource, Function, Impl, LifetimeParam, MacroDef, | 13 | db::HirDatabase, Const, ConstParam, Enum, Field, FieldSource, Function, Impl, LifetimeParam, |
14 | Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, | 14 | MacroDef, Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | pub trait HasSource { | 17 | pub trait HasSource { |
18 | type Ast; | 18 | type Ast; |
19 | fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast>; | 19 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>>; |
20 | } | 20 | } |
21 | 21 | ||
22 | /// NB: Module is !HasSource, because it has two source nodes at the same time: | 22 | /// NB: Module is !HasSource, because it has two source nodes at the same time: |
@@ -46,97 +46,104 @@ impl Module { | |||
46 | 46 | ||
47 | impl HasSource for Field { | 47 | impl HasSource for Field { |
48 | type Ast = FieldSource; | 48 | type Ast = FieldSource; |
49 | fn source(self, db: &dyn HirDatabase) -> InFile<FieldSource> { | 49 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
50 | let var = VariantId::from(self.parent); | 50 | let var = VariantId::from(self.parent); |
51 | let src = var.child_source(db.upcast()); | 51 | let src = var.child_source(db.upcast()); |
52 | src.map(|it| match it[self.id].clone() { | 52 | let field_source = src.map(|it| match it[self.id].clone() { |
53 | Either::Left(it) => FieldSource::Pos(it), | 53 | Either::Left(it) => FieldSource::Pos(it), |
54 | Either::Right(it) => FieldSource::Named(it), | 54 | Either::Right(it) => FieldSource::Named(it), |
55 | }) | 55 | }); |
56 | Some(field_source) | ||
56 | } | 57 | } |
57 | } | 58 | } |
58 | impl HasSource for Struct { | 59 | impl HasSource for Struct { |
59 | type Ast = ast::Struct; | 60 | type Ast = ast::Struct; |
60 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Struct> { | 61 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
61 | self.id.lookup(db.upcast()).source(db.upcast()) | 62 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
62 | } | 63 | } |
63 | } | 64 | } |
64 | impl HasSource for Union { | 65 | impl HasSource for Union { |
65 | type Ast = ast::Union; | 66 | type Ast = ast::Union; |
66 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Union> { | 67 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
67 | self.id.lookup(db.upcast()).source(db.upcast()) | 68 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
68 | } | 69 | } |
69 | } | 70 | } |
70 | impl HasSource for Enum { | 71 | impl HasSource for Enum { |
71 | type Ast = ast::Enum; | 72 | type Ast = ast::Enum; |
72 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Enum> { | 73 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
73 | self.id.lookup(db.upcast()).source(db.upcast()) | 74 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
74 | } | 75 | } |
75 | } | 76 | } |
76 | impl HasSource for Variant { | 77 | impl HasSource for Variant { |
77 | type Ast = ast::Variant; | 78 | type Ast = ast::Variant; |
78 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Variant> { | 79 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<ast::Variant>> { |
79 | self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone()) | 80 | Some(self.parent.id.child_source(db.upcast()).map(|map| map[self.id].clone())) |
80 | } | 81 | } |
81 | } | 82 | } |
82 | impl HasSource for Function { | 83 | impl HasSource for Function { |
83 | type Ast = ast::Fn; | 84 | type Ast = ast::Fn; |
84 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Fn> { | 85 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
85 | self.id.lookup(db.upcast()).source(db.upcast()) | 86 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
86 | } | 87 | } |
87 | } | 88 | } |
88 | impl HasSource for Const { | 89 | impl HasSource for Const { |
89 | type Ast = ast::Const; | 90 | type Ast = ast::Const; |
90 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Const> { | 91 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
91 | self.id.lookup(db.upcast()).source(db.upcast()) | 92 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
92 | } | 93 | } |
93 | } | 94 | } |
94 | impl HasSource for Static { | 95 | impl HasSource for Static { |
95 | type Ast = ast::Static; | 96 | type Ast = ast::Static; |
96 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Static> { | 97 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
97 | self.id.lookup(db.upcast()).source(db.upcast()) | 98 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
98 | } | 99 | } |
99 | } | 100 | } |
100 | impl HasSource for Trait { | 101 | impl HasSource for Trait { |
101 | type Ast = ast::Trait; | 102 | type Ast = ast::Trait; |
102 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Trait> { | 103 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
103 | self.id.lookup(db.upcast()).source(db.upcast()) | 104 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
104 | } | 105 | } |
105 | } | 106 | } |
106 | impl HasSource for TypeAlias { | 107 | impl HasSource for TypeAlias { |
107 | type Ast = ast::TypeAlias; | 108 | type Ast = ast::TypeAlias; |
108 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::TypeAlias> { | 109 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
109 | self.id.lookup(db.upcast()).source(db.upcast()) | 110 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
110 | } | 111 | } |
111 | } | 112 | } |
112 | impl HasSource for MacroDef { | 113 | impl HasSource for MacroDef { |
113 | type Ast = ast::Macro; | 114 | type Ast = ast::Macro; |
114 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Macro> { | 115 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
115 | InFile { | 116 | let ast_id = self.id.ast_id?; |
116 | file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id, | 117 | Some(InFile { file_id: ast_id.file_id, value: ast_id.to_node(db.upcast()) }) |
117 | value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db.upcast()), | ||
118 | } | ||
119 | } | 118 | } |
120 | } | 119 | } |
121 | impl HasSource for Impl { | 120 | impl HasSource for Impl { |
122 | type Ast = ast::Impl; | 121 | type Ast = ast::Impl; |
123 | fn source(self, db: &dyn HirDatabase) -> InFile<ast::Impl> { | 122 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
124 | self.id.lookup(db.upcast()).source(db.upcast()) | 123 | Some(self.id.lookup(db.upcast()).source(db.upcast())) |
125 | } | 124 | } |
126 | } | 125 | } |
127 | 126 | ||
128 | impl HasSource for TypeParam { | 127 | impl HasSource for TypeParam { |
129 | type Ast = Either<ast::Trait, ast::TypeParam>; | 128 | type Ast = Either<ast::Trait, ast::TypeParam>; |
130 | fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> { | 129 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
131 | let child_source = self.id.parent.child_source(db.upcast()); | 130 | let child_source = self.id.parent.child_source(db.upcast()); |
132 | child_source.map(|it| it[self.id.local_id].clone()) | 131 | Some(child_source.map(|it| it[self.id.local_id].clone())) |
133 | } | 132 | } |
134 | } | 133 | } |
135 | 134 | ||
136 | impl HasSource for LifetimeParam { | 135 | impl HasSource for LifetimeParam { |
137 | type Ast = ast::LifetimeParam; | 136 | type Ast = ast::LifetimeParam; |
138 | fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> { | 137 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { |
138 | let child_source = self.id.parent.child_source(db.upcast()); | ||
139 | Some(child_source.map(|it| it[self.id.local_id].clone())) | ||
140 | } | ||
141 | } | ||
142 | |||
143 | impl HasSource for ConstParam { | ||
144 | type Ast = ast::ConstParam; | ||
145 | fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> { | ||
139 | let child_source = self.id.parent.child_source(db.upcast()); | 146 | let child_source = self.id.parent.child_source(db.upcast()); |
140 | child_source.map(|it| it[self.id.local_id].clone()) | 147 | Some(child_source.map(|it| it[self.id.local_id].clone())) |
141 | } | 148 | } |
142 | } | 149 | } |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 7ac9fd507..769945c47 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -34,9 +34,10 @@ pub use crate::{ | |||
34 | attrs::{HasAttrs, Namespace}, | 34 | attrs::{HasAttrs, Namespace}, |
35 | code_model::{ | 35 | code_model::{ |
36 | Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const, | 36 | Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const, |
37 | Crate, CrateDependency, DefWithBody, Enum, Field, FieldSource, Function, GenericDef, | 37 | ConstParam, Crate, CrateDependency, DefWithBody, Enum, Field, FieldSource, Function, |
38 | HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, ScopeDef, | 38 | GenericDef, GenericParam, HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, |
39 | Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef, | 39 | Module, ModuleDef, ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, |
40 | Variant, VariantDef, | ||
40 | }, | 41 | }, |
41 | has_source::HasSource, | 42 | has_source::HasSource, |
42 | semantics::{PathResolution, Semantics, SemanticsScope}, | 43 | semantics::{PathResolution, Semantics, SemanticsScope}, |
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 67cd16e31..cd689c869 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -25,9 +25,9 @@ use crate::{ | |||
25 | diagnostics::Diagnostic, | 25 | diagnostics::Diagnostic, |
26 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 26 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, |
27 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, | 27 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, |
28 | AssocItem, Callable, Crate, Field, Function, HirFileId, Impl, InFile, Label, LifetimeParam, | 28 | AssocItem, Callable, ConstParam, Crate, Field, Function, HirFileId, Impl, InFile, Label, |
29 | Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, | 29 | LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, |
30 | VariantDef, | 30 | TypeAlias, TypeParam, VariantDef, |
31 | }; | 31 | }; |
32 | 32 | ||
33 | #[derive(Debug, Clone, PartialEq, Eq)] | 33 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -38,6 +38,7 @@ pub enum PathResolution { | |||
38 | Local(Local), | 38 | Local(Local), |
39 | /// A generic parameter | 39 | /// A generic parameter |
40 | TypeParam(TypeParam), | 40 | TypeParam(TypeParam), |
41 | ConstParam(ConstParam), | ||
41 | SelfType(Impl), | 42 | SelfType(Impl), |
42 | Macro(MacroDef), | 43 | Macro(MacroDef), |
43 | AssocItem(AssocItem), | 44 | AssocItem(AssocItem), |
@@ -59,7 +60,9 @@ impl PathResolution { | |||
59 | PathResolution::Def(ModuleDef::TypeAlias(alias)) => { | 60 | PathResolution::Def(ModuleDef::TypeAlias(alias)) => { |
60 | Some(TypeNs::TypeAliasId((*alias).into())) | 61 | Some(TypeNs::TypeAliasId((*alias).into())) |
61 | } | 62 | } |
62 | PathResolution::Local(_) | PathResolution::Macro(_) => None, | 63 | PathResolution::Local(_) | PathResolution::Macro(_) | PathResolution::ConstParam(_) => { |
64 | None | ||
65 | } | ||
63 | PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())), | 66 | PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())), |
64 | PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())), | 67 | PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())), |
65 | PathResolution::AssocItem(AssocItem::Const(_)) | 68 | PathResolution::AssocItem(AssocItem::Const(_)) |
@@ -744,6 +747,7 @@ to_def_impls![ | |||
744 | (crate::Variant, ast::Variant, enum_variant_to_def), | 747 | (crate::Variant, ast::Variant, enum_variant_to_def), |
745 | (crate::TypeParam, ast::TypeParam, type_param_to_def), | 748 | (crate::TypeParam, ast::TypeParam, type_param_to_def), |
746 | (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), | 749 | (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def), |
750 | (crate::ConstParam, ast::ConstParam, const_param_to_def), | ||
747 | (crate::MacroDef, ast::MacroRules, macro_rules_to_def), | 751 | (crate::MacroDef, ast::MacroRules, macro_rules_to_def), |
748 | (crate::Local, ast::IdentPat, bind_pat_to_def), | 752 | (crate::Local, ast::IdentPat, bind_pat_to_def), |
749 | (crate::Label, ast::Label, label_to_def), | 753 | (crate::Label, ast::Label, label_to_def), |
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 424e6e8a9..4b9ebff72 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs | |||
@@ -6,9 +6,9 @@ use hir_def::{ | |||
6 | dyn_map::DynMap, | 6 | dyn_map::DynMap, |
7 | expr::{LabelId, PatId}, | 7 | expr::{LabelId, PatId}, |
8 | keys::{self, Key}, | 8 | keys::{self, Key}, |
9 | ConstId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, ImplId, | 9 | ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, |
10 | LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, | 10 | ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, |
11 | VariantId, | 11 | UnionId, VariantId, |
12 | }; | 12 | }; |
13 | use hir_expand::{name::AsName, AstId, MacroDefKind}; | 13 | use hir_expand::{name::AsName, AstId, MacroDefKind}; |
14 | use rustc_hash::FxHashMap; | 14 | use rustc_hash::FxHashMap; |
@@ -157,6 +157,18 @@ impl SourceToDefCtx<'_, '_> { | |||
157 | dyn_map[keys::LIFETIME_PARAM].get(&src).copied() | 157 | dyn_map[keys::LIFETIME_PARAM].get(&src).copied() |
158 | } | 158 | } |
159 | 159 | ||
160 | pub(super) fn const_param_to_def( | ||
161 | &mut self, | ||
162 | src: InFile<ast::ConstParam>, | ||
163 | ) -> Option<ConstParamId> { | ||
164 | let container: ChildContainer = | ||
165 | self.find_generic_param_container(src.as_ref().map(|it| it.syntax()))?.into(); | ||
166 | let db = self.db; | ||
167 | let dyn_map = | ||
168 | &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db)); | ||
169 | dyn_map[keys::CONST_PARAM].get(&src).copied() | ||
170 | } | ||
171 | |||
160 | // FIXME: use DynMap as well? | 172 | // FIXME: use DynMap as well? |
161 | pub(super) fn macro_rules_to_def( | 173 | pub(super) fn macro_rules_to_def( |
162 | &mut self, | 174 | &mut self, |
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index bddc49c05..30a8e513d 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs | |||
@@ -479,6 +479,7 @@ pub(crate) fn resolve_hir_path( | |||
479 | ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), | 479 | ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), |
480 | ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), | 480 | ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()), |
481 | ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()), | 481 | ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()), |
482 | ValueNs::GenericParam(it) => PathResolution::ConstParam(it.into()), | ||
482 | }; | 483 | }; |
483 | Some(res) | 484 | Some(res) |
484 | }); | 485 | }); |
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml index e8b581e2f..7ef966cd2 100644 --- a/crates/hir_def/Cargo.toml +++ b/crates/hir_def/Cargo.toml | |||
@@ -33,4 +33,4 @@ cfg = { path = "../cfg", version = "0.0.0" } | |||
33 | tt = { path = "../tt", version = "0.0.0" } | 33 | tt = { path = "../tt", version = "0.0.0" } |
34 | 34 | ||
35 | [dev-dependencies] | 35 | [dev-dependencies] |
36 | expect-test = "1.0" | 36 | expect-test = "1.1" |
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 042e119b1..6b79e7bad 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -21,7 +21,7 @@ use crate::{ | |||
21 | nameres::ModuleSource, | 21 | nameres::ModuleSource, |
22 | path::{ModPath, PathKind}, | 22 | path::{ModPath, PathKind}, |
23 | src::HasChildSource, | 23 | src::HasChildSource, |
24 | AdtId, AttrDefId, Lookup, | 24 | AdtId, AttrDefId, GenericParamId, Lookup, |
25 | }; | 25 | }; |
26 | 26 | ||
27 | /// Holds documentation | 27 | /// Holds documentation |
@@ -235,6 +235,25 @@ impl Attrs { | |||
235 | AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 235 | AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
236 | AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 236 | AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
237 | AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 237 | AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
238 | AttrDefId::GenericParamId(it) => match it { | ||
239 | GenericParamId::TypeParamId(it) => { | ||
240 | let src = it.parent.child_source(db); | ||
241 | RawAttrs::from_attrs_owner( | ||
242 | db, | ||
243 | src.with_value( | ||
244 | src.value[it.local_id].as_ref().either(|it| it as _, |it| it as _), | ||
245 | ), | ||
246 | ) | ||
247 | } | ||
248 | GenericParamId::LifetimeParamId(it) => { | ||
249 | let src = it.parent.child_source(db); | ||
250 | RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id])) | ||
251 | } | ||
252 | GenericParamId::ConstParamId(it) => { | ||
253 | let src = it.parent.child_source(db); | ||
254 | RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id])) | ||
255 | } | ||
256 | }, | ||
238 | }; | 257 | }; |
239 | 258 | ||
240 | raw_attrs.filter(db, def.krate(db)) | 259 | raw_attrs.filter(db, def.krate(db)) |
@@ -260,14 +279,13 @@ impl Attrs { | |||
260 | } | 279 | } |
261 | 280 | ||
262 | pub fn docs(&self) -> Option<Documentation> { | 281 | pub fn docs(&self) -> Option<Documentation> { |
263 | let docs = self | 282 | let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? { |
264 | .by_key("doc") | 283 | AttrInput::Literal(s) => Some(s), |
265 | .attrs() | 284 | AttrInput::TokenTree(_) => None, |
266 | .flat_map(|attr| match attr.input.as_ref()? { | 285 | }); |
267 | AttrInput::Literal(s) => Some(s), | 286 | // FIXME: Replace `Itertools::intersperse` with `Iterator::intersperse[_with]` until the |
268 | AttrInput::TokenTree(_) => None, | 287 | // libstd api gets stabilized (https://github.com/rust-lang/rust/issues/79524). |
269 | }) | 288 | let docs = Itertools::intersperse(docs, &SmolStr::new_inline("\n")) |
270 | .intersperse(&SmolStr::new_inline("\n")) | ||
271 | .map(|it| it.as_str()) | 289 | .map(|it| it.as_str()) |
272 | .collect::<String>(); | 290 | .collect::<String>(); |
273 | if docs.is_empty() { | 291 | if docs.is_empty() { |
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index bb8fca009..9b5b886c2 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs | |||
@@ -21,11 +21,11 @@ use crate::{ | |||
21 | keys, | 21 | keys, |
22 | src::{HasChildSource, HasSource}, | 22 | src::{HasChildSource, HasSource}, |
23 | type_ref::{LifetimeRef, TypeBound, TypeRef}, | 23 | type_ref::{LifetimeRef, TypeBound, TypeRef}, |
24 | AdtId, GenericDefId, LifetimeParamId, LocalLifetimeParamId, LocalTypeParamId, Lookup, | 24 | AdtId, ConstParamId, GenericDefId, LifetimeParamId, LocalConstParamId, LocalLifetimeParamId, |
25 | TypeParamId, | 25 | LocalTypeParamId, Lookup, TypeParamId, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | /// Data about a generic parameter (to a function, struct, impl, ...). | 28 | /// Data about a generic type parameter (to a function, struct, impl, ...). |
29 | #[derive(Clone, PartialEq, Eq, Debug)] | 29 | #[derive(Clone, PartialEq, Eq, Debug)] |
30 | pub struct TypeParamData { | 30 | pub struct TypeParamData { |
31 | pub name: Option<Name>, | 31 | pub name: Option<Name>, |
@@ -33,12 +33,19 @@ pub struct TypeParamData { | |||
33 | pub provenance: TypeParamProvenance, | 33 | pub provenance: TypeParamProvenance, |
34 | } | 34 | } |
35 | 35 | ||
36 | /// Data about a generic parameter (to a function, struct, impl, ...). | 36 | /// Data about a generic lifetime parameter (to a function, struct, impl, ...). |
37 | #[derive(Clone, PartialEq, Eq, Debug)] | 37 | #[derive(Clone, PartialEq, Eq, Debug)] |
38 | pub struct LifetimeParamData { | 38 | pub struct LifetimeParamData { |
39 | pub name: Name, | 39 | pub name: Name, |
40 | } | 40 | } |
41 | 41 | ||
42 | /// Data about a generic const parameter (to a function, struct, impl, ...). | ||
43 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
44 | pub struct ConstParamData { | ||
45 | pub name: Name, | ||
46 | pub ty: TypeRef, | ||
47 | } | ||
48 | |||
42 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | 49 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] |
43 | pub enum TypeParamProvenance { | 50 | pub enum TypeParamProvenance { |
44 | TypeParamList, | 51 | TypeParamList, |
@@ -51,6 +58,7 @@ pub enum TypeParamProvenance { | |||
51 | pub struct GenericParams { | 58 | pub struct GenericParams { |
52 | pub types: Arena<TypeParamData>, | 59 | pub types: Arena<TypeParamData>, |
53 | pub lifetimes: Arena<LifetimeParamData>, | 60 | pub lifetimes: Arena<LifetimeParamData>, |
61 | pub consts: Arena<ConstParamData>, | ||
54 | pub where_predicates: Vec<WherePredicate>, | 62 | pub where_predicates: Vec<WherePredicate>, |
55 | } | 63 | } |
56 | 64 | ||
@@ -76,6 +84,7 @@ pub enum WherePredicateTypeTarget { | |||
76 | pub(crate) struct SourceMap { | 84 | pub(crate) struct SourceMap { |
77 | pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>, | 85 | pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>, |
78 | lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>, | 86 | lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>, |
87 | const_params: ArenaMap<LocalConstParamId, ast::ConstParam>, | ||
79 | } | 88 | } |
80 | 89 | ||
81 | impl GenericParams { | 90 | impl GenericParams { |
@@ -268,6 +277,13 @@ impl GenericParams { | |||
268 | let lifetime_ref = LifetimeRef::new_name(name); | 277 | let lifetime_ref = LifetimeRef::new_name(name); |
269 | self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); | 278 | self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); |
270 | } | 279 | } |
280 | for const_param in params.const_params() { | ||
281 | let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); | ||
282 | let ty = const_param.ty().map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it)); | ||
283 | let param = ConstParamData { name, ty }; | ||
284 | let param_id = self.consts.alloc(param); | ||
285 | sm.const_params.insert(param_id, const_param.clone()); | ||
286 | } | ||
271 | } | 287 | } |
272 | 288 | ||
273 | fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) { | 289 | fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) { |
@@ -353,12 +369,16 @@ impl GenericParams { | |||
353 | }); | 369 | }); |
354 | } | 370 | } |
355 | 371 | ||
356 | pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { | 372 | pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { |
357 | self.types | 373 | self.types |
358 | .iter() | 374 | .iter() |
359 | .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None }) | 375 | .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None }) |
360 | } | 376 | } |
361 | 377 | ||
378 | pub fn find_const_by_name(&self, name: &Name) -> Option<LocalConstParamId> { | ||
379 | self.consts.iter().find_map(|(id, p)| if p.name == *name { Some(id) } else { None }) | ||
380 | } | ||
381 | |||
362 | pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> { | 382 | pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> { |
363 | self.types.iter().find_map(|(id, p)| { | 383 | self.types.iter().find_map(|(id, p)| { |
364 | if p.provenance == TypeParamProvenance::TraitSelf { | 384 | if p.provenance == TypeParamProvenance::TraitSelf { |
@@ -390,6 +410,16 @@ impl HasChildSource<LocalLifetimeParamId> for GenericDefId { | |||
390 | } | 410 | } |
391 | } | 411 | } |
392 | 412 | ||
413 | impl HasChildSource<LocalConstParamId> for GenericDefId { | ||
414 | type Value = ast::ConstParam; | ||
415 | fn child_source( | ||
416 | &self, | ||
417 | db: &dyn DefDatabase, | ||
418 | ) -> InFile<ArenaMap<LocalConstParamId, Self::Value>> { | ||
419 | GenericParams::new(db, *self).1.map(|source_maps| source_maps.const_params) | ||
420 | } | ||
421 | } | ||
422 | |||
393 | impl ChildBySource for GenericDefId { | 423 | impl ChildBySource for GenericDefId { |
394 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { | 424 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { |
395 | let mut res = DynMap::default(); | 425 | let mut res = DynMap::default(); |
@@ -406,6 +436,10 @@ impl ChildBySource for GenericDefId { | |||
406 | let id = LifetimeParamId { parent: *self, local_id }; | 436 | let id = LifetimeParamId { parent: *self, local_id }; |
407 | res[keys::LIFETIME_PARAM].insert(sm.with_value(src.clone()), id); | 437 | res[keys::LIFETIME_PARAM].insert(sm.with_value(src.clone()), id); |
408 | } | 438 | } |
439 | for (local_id, src) in sm.value.const_params.iter() { | ||
440 | let id = ConstParamId { parent: *self, local_id }; | ||
441 | res[keys::CONST_PARAM].insert(sm.with_value(src.clone()), id); | ||
442 | } | ||
409 | res | 443 | res |
410 | } | 444 | } |
411 | } | 445 | } |
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 100dbf5d6..b6f510731 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -260,6 +260,7 @@ impl GenericParamsStorage { | |||
260 | fn alloc(&mut self, params: GenericParams) -> GenericParamsId { | 260 | fn alloc(&mut self, params: GenericParams) -> GenericParamsId { |
261 | if params.types.is_empty() | 261 | if params.types.is_empty() |
262 | && params.lifetimes.is_empty() | 262 | && params.lifetimes.is_empty() |
263 | && params.consts.is_empty() | ||
263 | && params.where_predicates.is_empty() | 264 | && params.where_predicates.is_empty() |
264 | { | 265 | { |
265 | return GenericParamsId::EMPTY; | 266 | return GenericParamsId::EMPTY; |
@@ -269,8 +270,12 @@ impl GenericParamsStorage { | |||
269 | } | 270 | } |
270 | } | 271 | } |
271 | 272 | ||
272 | static EMPTY_GENERICS: GenericParams = | 273 | static EMPTY_GENERICS: GenericParams = GenericParams { |
273 | GenericParams { types: Arena::new(), lifetimes: Arena::new(), where_predicates: Vec::new() }; | 274 | types: Arena::new(), |
275 | lifetimes: Arena::new(), | ||
276 | consts: Arena::new(), | ||
277 | where_predicates: Vec::new(), | ||
278 | }; | ||
274 | 279 | ||
275 | #[derive(Default, Debug, Eq, PartialEq)] | 280 | #[derive(Default, Debug, Eq, PartialEq)] |
276 | struct ItemTreeData { | 281 | struct ItemTreeData { |
diff --git a/crates/hir_def/src/keys.rs b/crates/hir_def/src/keys.rs index 9c585de2c..89b3ed868 100644 --- a/crates/hir_def/src/keys.rs +++ b/crates/hir_def/src/keys.rs | |||
@@ -8,8 +8,8 @@ use syntax::{ast, AstNode, AstPtr}; | |||
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | dyn_map::{DynMap, Policy}, | 10 | dyn_map::{DynMap, Policy}, |
11 | ConstId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId, StaticId, | 11 | ConstId, ConstParamId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId, |
12 | StructId, TraitId, TypeAliasId, TypeParamId, UnionId, | 12 | StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>; | 15 | pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>; |
@@ -29,6 +29,7 @@ pub const TUPLE_FIELD: Key<ast::TupleField, FieldId> = Key::new(); | |||
29 | pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new(); | 29 | pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new(); |
30 | pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new(); | 30 | pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new(); |
31 | pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new(); | 31 | pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new(); |
32 | pub const CONST_PARAM: Key<ast::ConstParam, ConstParamId> = Key::new(); | ||
32 | 33 | ||
33 | pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new(); | 34 | pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new(); |
34 | 35 | ||
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index ba09a9126..211cb2faf 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -232,6 +232,13 @@ pub struct LifetimeParamId { | |||
232 | pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>; | 232 | pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>; |
233 | 233 | ||
234 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 234 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
235 | pub struct ConstParamId { | ||
236 | pub parent: GenericDefId, | ||
237 | pub local_id: LocalConstParamId, | ||
238 | } | ||
239 | pub type LocalConstParamId = Idx<generics::ConstParamData>; | ||
240 | |||
241 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
235 | pub enum ContainerId { | 242 | pub enum ContainerId { |
236 | ModuleId(ModuleId), | 243 | ModuleId(ModuleId), |
237 | DefWithBodyId(DefWithBodyId), | 244 | DefWithBodyId(DefWithBodyId), |
@@ -254,6 +261,15 @@ pub enum AdtId { | |||
254 | } | 261 | } |
255 | impl_from!(StructId, UnionId, EnumId for AdtId); | 262 | impl_from!(StructId, UnionId, EnumId for AdtId); |
256 | 263 | ||
264 | /// A generic param | ||
265 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
266 | pub enum GenericParamId { | ||
267 | TypeParamId(TypeParamId), | ||
268 | LifetimeParamId(LifetimeParamId), | ||
269 | ConstParamId(ConstParamId), | ||
270 | } | ||
271 | impl_from!(TypeParamId, LifetimeParamId, ConstParamId for GenericParamId); | ||
272 | |||
257 | /// The defs which can be visible in the module. | 273 | /// The defs which can be visible in the module. |
258 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 274 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
259 | pub enum ModuleDefId { | 275 | pub enum ModuleDefId { |
@@ -350,6 +366,7 @@ pub enum AttrDefId { | |||
350 | TypeAliasId(TypeAliasId), | 366 | TypeAliasId(TypeAliasId), |
351 | MacroDefId(MacroDefId), | 367 | MacroDefId(MacroDefId), |
352 | ImplId(ImplId), | 368 | ImplId(ImplId), |
369 | GenericParamId(GenericParamId), | ||
353 | } | 370 | } |
354 | 371 | ||
355 | impl_from!( | 372 | impl_from!( |
@@ -363,7 +380,8 @@ impl_from!( | |||
363 | TraitId, | 380 | TraitId, |
364 | TypeAliasId, | 381 | TypeAliasId, |
365 | MacroDefId, | 382 | MacroDefId, |
366 | ImplId | 383 | ImplId, |
384 | GenericParamId | ||
367 | for AttrDefId | 385 | for AttrDefId |
368 | ); | 386 | ); |
369 | 387 | ||
@@ -488,6 +506,15 @@ impl AttrDefId { | |||
488 | AttrDefId::TraitId(it) => it.lookup(db).container.module(db).krate, | 506 | AttrDefId::TraitId(it) => it.lookup(db).container.module(db).krate, |
489 | AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate, | 507 | AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate, |
490 | AttrDefId::ImplId(it) => it.lookup(db).container.module(db).krate, | 508 | AttrDefId::ImplId(it) => it.lookup(db).container.module(db).krate, |
509 | AttrDefId::GenericParamId(it) => { | ||
510 | match it { | ||
511 | GenericParamId::TypeParamId(it) => it.parent, | ||
512 | GenericParamId::LifetimeParamId(it) => it.parent, | ||
513 | GenericParamId::ConstParamId(it) => it.parent, | ||
514 | } | ||
515 | .module(db) | ||
516 | .krate | ||
517 | } | ||
491 | // FIXME: `MacroDefId` should store the defining module, then this can implement | 518 | // FIXME: `MacroDefId` should store the defining module, then this can implement |
492 | // `HasModule` | 519 | // `HasModule` |
493 | AttrDefId::MacroDefId(it) => it.krate, | 520 | AttrDefId::MacroDefId(it) => it.krate, |
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index f8cc5e075..129f1dbac 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs | |||
@@ -20,9 +20,9 @@ use crate::{ | |||
20 | path::{ModPath, PathKind}, | 20 | path::{ModPath, PathKind}, |
21 | per_ns::PerNs, | 21 | per_ns::PerNs, |
22 | visibility::{RawVisibility, Visibility}, | 22 | visibility::{RawVisibility, Visibility}, |
23 | AdtId, AssocContainerId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, | 23 | AdtId, AssocContainerId, ConstId, ConstParamId, ContainerId, DefWithBodyId, EnumId, |
24 | FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, | 24 | EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, |
25 | StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId, | 25 | ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | #[derive(Debug, Clone, Default)] | 28 | #[derive(Debug, Clone, Default)] |
@@ -93,6 +93,7 @@ pub enum ValueNs { | |||
93 | StaticId(StaticId), | 93 | StaticId(StaticId), |
94 | StructId(StructId), | 94 | StructId(StructId), |
95 | EnumVariantId(EnumVariantId), | 95 | EnumVariantId(EnumVariantId), |
96 | GenericParam(ConstParamId), | ||
96 | } | 97 | } |
97 | 98 | ||
98 | impl Resolver { | 99 | impl Resolver { |
@@ -163,7 +164,7 @@ impl Resolver { | |||
163 | } | 164 | } |
164 | 165 | ||
165 | Scope::GenericParams { params, def } => { | 166 | Scope::GenericParams { params, def } => { |
166 | if let Some(local_id) = params.find_by_name(first_name) { | 167 | if let Some(local_id) = params.find_type_by_name(first_name) { |
167 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; | 168 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; |
168 | return Some(( | 169 | return Some(( |
169 | TypeNs::GenericParam(TypeParamId { local_id, parent: *def }), | 170 | TypeNs::GenericParam(TypeParamId { local_id, parent: *def }), |
@@ -285,11 +286,17 @@ impl Resolver { | |||
285 | Scope::ExprScope(_) => continue, | 286 | Scope::ExprScope(_) => continue, |
286 | 287 | ||
287 | Scope::GenericParams { params, def } if n_segments > 1 => { | 288 | Scope::GenericParams { params, def } if n_segments > 1 => { |
288 | if let Some(local_id) = params.find_by_name(first_name) { | 289 | if let Some(local_id) = params.find_type_by_name(first_name) { |
289 | let ty = TypeNs::GenericParam(TypeParamId { local_id, parent: *def }); | 290 | let ty = TypeNs::GenericParam(TypeParamId { local_id, parent: *def }); |
290 | return Some(ResolveValueResult::Partial(ty, 1)); | 291 | return Some(ResolveValueResult::Partial(ty, 1)); |
291 | } | 292 | } |
292 | } | 293 | } |
294 | Scope::GenericParams { params, def } if n_segments == 1 => { | ||
295 | if let Some(local_id) = params.find_const_by_name(first_name) { | ||
296 | let val = ValueNs::GenericParam(ConstParamId { local_id, parent: *def }); | ||
297 | return Some(ResolveValueResult::ValueNs(val)); | ||
298 | } | ||
299 | } | ||
293 | Scope::GenericParams { .. } => continue, | 300 | Scope::GenericParams { .. } => continue, |
294 | 301 | ||
295 | Scope::ImplDefScope(impl_) => { | 302 | Scope::ImplDefScope(impl_) => { |
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 06f0a3ed9..0a0d021e0 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -404,7 +404,7 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind { | |||
404 | TRY_EXPR => FragmentKind::Expr, | 404 | TRY_EXPR => FragmentKind::Expr, |
405 | TUPLE_EXPR => FragmentKind::Expr, | 405 | TUPLE_EXPR => FragmentKind::Expr, |
406 | PAREN_EXPR => FragmentKind::Expr, | 406 | PAREN_EXPR => FragmentKind::Expr, |
407 | 407 | ARRAY_EXPR => FragmentKind::Expr, | |
408 | FOR_EXPR => FragmentKind::Expr, | 408 | FOR_EXPR => FragmentKind::Expr, |
409 | PATH_EXPR => FragmentKind::Expr, | 409 | PATH_EXPR => FragmentKind::Expr, |
410 | CLOSURE_EXPR => FragmentKind::Expr, | 410 | CLOSURE_EXPR => FragmentKind::Expr, |
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index 6354b090d..ae7b51a08 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs | |||
@@ -218,6 +218,12 @@ fn eager_macro_recur( | |||
218 | } | 218 | } |
219 | }; | 219 | }; |
220 | 220 | ||
221 | // check if the whole original sytnax is replaced | ||
222 | // Note that SyntaxRewriter cannot replace the root node itself | ||
223 | if child.syntax() == &original { | ||
224 | return Ok(insert); | ||
225 | } | ||
226 | |||
221 | rewriter.replace(child.syntax(), &insert); | 227 | rewriter.replace(child.syntax(), &insert); |
222 | } | 228 | } |
223 | 229 | ||
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index 2dfccd191..3d1778590 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -31,7 +31,7 @@ syntax = { path = "../syntax", version = "0.0.0" } | |||
31 | test_utils = { path = "../test_utils", version = "0.0.0" } | 31 | test_utils = { path = "../test_utils", version = "0.0.0" } |
32 | 32 | ||
33 | [dev-dependencies] | 33 | [dev-dependencies] |
34 | expect-test = "1.0" | 34 | expect-test = "1.1" |
35 | tracing = "0.1" | 35 | tracing = "0.1" |
36 | tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } | 36 | tracing-subscriber = { version = "0.2", default-features = false, features = ["env-filter", "registry"] } |
37 | tracing-tree = { version = "0.1.4" } | 37 | tracing-tree = { version = "0.1.4" } |
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs index 66bdb8e88..f3567c49e 100644 --- a/crates/hir_ty/src/db.rs +++ b/crates/hir_ty/src/db.rs | |||
@@ -5,8 +5,8 @@ use std::sync::Arc; | |||
5 | use arena::map::ArenaMap; | 5 | use arena::map::ArenaMap; |
6 | use base_db::{impl_intern_key, salsa, CrateId, Upcast}; | 6 | use base_db::{impl_intern_key, salsa, CrateId, Upcast}; |
7 | use hir_def::{ | 7 | use hir_def::{ |
8 | db::DefDatabase, expr::ExprId, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, | 8 | db::DefDatabase, expr::ExprId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId, ImplId, |
9 | TypeParamId, VariantId, | 9 | LocalFieldId, TypeParamId, VariantId, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
@@ -37,6 +37,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
37 | #[salsa::cycle(crate::lower::impl_self_ty_recover)] | 37 | #[salsa::cycle(crate::lower::impl_self_ty_recover)] |
38 | fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>; | 38 | fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>; |
39 | 39 | ||
40 | #[salsa::invoke(crate::lower::const_param_ty_query)] | ||
41 | fn const_param_ty(&self, def: ConstParamId) -> Ty; | ||
42 | |||
40 | #[salsa::invoke(crate::lower::impl_trait_query)] | 43 | #[salsa::invoke(crate::lower::impl_trait_query)] |
41 | fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>; | 44 | fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>; |
42 | 45 | ||
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index 849415706..b4e453411 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs | |||
@@ -156,7 +156,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
156 | // FIXME: Due to shortcomings in the current type system implementation, only emit this | 156 | // FIXME: Due to shortcomings in the current type system implementation, only emit this |
157 | // diagnostic if there are no type mismatches in the containing function. | 157 | // diagnostic if there are no type mismatches in the containing function. |
158 | if self.infer.type_mismatches.iter().next().is_some() { | 158 | if self.infer.type_mismatches.iter().next().is_some() { |
159 | return Some(()); | 159 | return None; |
160 | } | 160 | } |
161 | 161 | ||
162 | let is_method_call = matches!(expr, Expr::MethodCall { .. }); | 162 | let is_method_call = matches!(expr, Expr::MethodCall { .. }); |
@@ -170,6 +170,14 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
170 | let mut args = args.clone(); | 170 | let mut args = args.clone(); |
171 | args.insert(0, *receiver); | 171 | args.insert(0, *receiver); |
172 | 172 | ||
173 | let receiver = &self.infer.type_of_expr[*receiver]; | ||
174 | if receiver.strip_references().is_unknown() { | ||
175 | // if the receiver is of unknown type, it's very likely we | ||
176 | // don't know enough to correctly resolve the method call. | ||
177 | // This is kind of a band-aid for #6975. | ||
178 | return None; | ||
179 | } | ||
180 | |||
173 | // FIXME: note that we erase information about substs here. This | 181 | // FIXME: note that we erase information about substs here. This |
174 | // is not right, but, luckily, doesn't matter as we care only | 182 | // is not right, but, luckily, doesn't matter as we care only |
175 | // about the number of params | 183 | // about the number of params |
@@ -505,6 +513,22 @@ fn f() { | |||
505 | } | 513 | } |
506 | 514 | ||
507 | #[test] | 515 | #[test] |
516 | fn method_unknown_receiver() { | ||
517 | // note: this is incorrect code, so there might be errors on this in the | ||
518 | // future, but we shouldn't emit an argument count diagnostic here | ||
519 | check_diagnostics( | ||
520 | r#" | ||
521 | trait Foo { fn method(&self, arg: usize) {} } | ||
522 | |||
523 | fn f() { | ||
524 | let x; | ||
525 | x.method(); | ||
526 | } | ||
527 | "#, | ||
528 | ); | ||
529 | } | ||
530 | |||
531 | #[test] | ||
508 | fn tuple_struct() { | 532 | fn tuple_struct() { |
509 | check_diagnostics( | 533 | check_diagnostics( |
510 | r#" | 534 | r#" |
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs index 80d7ed10e..5d541104e 100644 --- a/crates/hir_ty/src/infer/path.rs +++ b/crates/hir_ty/src/infer/path.rs | |||
@@ -89,6 +89,7 @@ impl<'a> InferenceContext<'a> { | |||
89 | return None; | 89 | return None; |
90 | } | 90 | } |
91 | } | 91 | } |
92 | ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)), | ||
92 | }; | 93 | }; |
93 | 94 | ||
94 | let ty = self.db.value_ty(typable); | 95 | let ty = self.db.value_ty(typable); |
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index 357bd92f9..e00c7e176 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs | |||
@@ -791,6 +791,10 @@ impl Ty { | |||
791 | matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) | 791 | matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) |
792 | } | 792 | } |
793 | 793 | ||
794 | pub fn is_unknown(&self) -> bool { | ||
795 | matches!(self, Ty::Unknown) | ||
796 | } | ||
797 | |||
794 | /// If this is a `dyn Trait` type, this returns the `Trait` part. | 798 | /// If this is a `dyn Trait` type, this returns the `Trait` part. |
795 | pub fn dyn_trait_ref(&self) -> Option<&TraitRef> { | 799 | pub fn dyn_trait_ref(&self) -> Option<&TraitRef> { |
796 | match self { | 800 | match self { |
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs index 8da56cd11..222f61a11 100644 --- a/crates/hir_ty/src/lower.rs +++ b/crates/hir_ty/src/lower.rs | |||
@@ -16,9 +16,9 @@ use hir_def::{ | |||
16 | path::{GenericArg, Path, PathSegment, PathSegments}, | 16 | path::{GenericArg, Path, PathSegment, PathSegments}, |
17 | resolver::{HasResolver, Resolver, TypeNs}, | 17 | resolver::{HasResolver, Resolver, TypeNs}, |
18 | type_ref::{TypeBound, TypeRef}, | 18 | type_ref::{TypeBound, TypeRef}, |
19 | AdtId, AssocContainerId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, | 19 | AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, |
20 | HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, | 20 | GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, |
21 | UnionId, VariantId, | 21 | TypeAliasId, TypeParamId, UnionId, VariantId, |
22 | }; | 22 | }; |
23 | use hir_expand::name::Name; | 23 | use hir_expand::name::Name; |
24 | use smallvec::SmallVec; | 24 | use smallvec::SmallVec; |
@@ -1221,6 +1221,15 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde | |||
1221 | Binders::new(generics.len(), Ty::from_hir(&ctx, &impl_data.target_type)) | 1221 | Binders::new(generics.len(), Ty::from_hir(&ctx, &impl_data.target_type)) |
1222 | } | 1222 | } |
1223 | 1223 | ||
1224 | pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { | ||
1225 | let parent_data = db.generic_params(def.parent); | ||
1226 | let data = &parent_data.consts[def.local_id]; | ||
1227 | let resolver = def.parent.resolver(db.upcast()); | ||
1228 | let ctx = TyLoweringContext::new(db, &resolver); | ||
1229 | |||
1230 | Ty::from_hir(&ctx, &data.ty) | ||
1231 | } | ||
1232 | |||
1224 | pub(crate) fn impl_self_ty_recover( | 1233 | pub(crate) fn impl_self_ty_recover( |
1225 | db: &dyn HirDatabase, | 1234 | db: &dyn HirDatabase, |
1226 | _cycle: &[String], | 1235 | _cycle: &[String], |
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index a7656b864..1953da7be 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs | |||
@@ -540,6 +540,52 @@ fn bar() -> u32 {0} | |||
540 | } | 540 | } |
541 | 541 | ||
542 | #[test] | 542 | #[test] |
543 | fn infer_builtin_macros_include_str() { | ||
544 | check_types( | ||
545 | r#" | ||
546 | //- /main.rs | ||
547 | #[rustc_builtin_macro] | ||
548 | macro_rules! include_str {() => {}} | ||
549 | |||
550 | fn main() { | ||
551 | let a = include_str!("foo.rs"); | ||
552 | a; | ||
553 | } //^ &str | ||
554 | |||
555 | //- /foo.rs | ||
556 | hello | ||
557 | "#, | ||
558 | ); | ||
559 | } | ||
560 | |||
561 | #[test] | ||
562 | fn infer_builtin_macros_include_str_with_lazy_nested() { | ||
563 | check_types( | ||
564 | r#" | ||
565 | //- /main.rs | ||
566 | #[rustc_builtin_macro] | ||
567 | macro_rules! concat {() => {}} | ||
568 | #[rustc_builtin_macro] | ||
569 | macro_rules! include_str {() => {}} | ||
570 | |||
571 | macro_rules! m { | ||
572 | ($x:expr) => { | ||
573 | concat!("foo", $x) | ||
574 | }; | ||
575 | } | ||
576 | |||
577 | fn main() { | ||
578 | let a = include_str!(m!(".rs")); | ||
579 | a; | ||
580 | } //^ &str | ||
581 | |||
582 | //- /foo.rs | ||
583 | hello | ||
584 | "#, | ||
585 | ); | ||
586 | } | ||
587 | |||
588 | #[test] | ||
543 | #[ignore] | 589 | #[ignore] |
544 | fn include_accidentally_quadratic() { | 590 | fn include_accidentally_quadratic() { |
545 | let file = project_dir().join("crates/syntax/test_data/accidentally_quadratic"); | 591 | let file = project_dir().join("crates/syntax/test_data/accidentally_quadratic"); |
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs index 307a257b1..cffe8630b 100644 --- a/crates/hir_ty/src/tests/regression.rs +++ b/crates/hir_ty/src/tests/regression.rs | |||
@@ -326,6 +326,24 @@ fn infer_paren_macro_call() { | |||
326 | } | 326 | } |
327 | 327 | ||
328 | #[test] | 328 | #[test] |
329 | fn infer_array_macro_call() { | ||
330 | check_infer( | ||
331 | r#" | ||
332 | macro_rules! bar { () => {0u32} } | ||
333 | fn test() { | ||
334 | let a = [bar!()]; | ||
335 | } | ||
336 | "#, | ||
337 | expect![[r#" | ||
338 | !0..4 '0u32': u32 | ||
339 | 44..69 '{ ...()]; }': () | ||
340 | 54..55 'a': [u32; _] | ||
341 | 58..66 '[bar!()]': [u32; _] | ||
342 | "#]], | ||
343 | ); | ||
344 | } | ||
345 | |||
346 | #[test] | ||
329 | fn bug_1030() { | 347 | fn bug_1030() { |
330 | check_infer( | 348 | check_infer( |
331 | r#" | 349 | r#" |
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index a61282d5a..8d431b920 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs | |||
@@ -2375,3 +2375,19 @@ fn infer_operator_overload() { | |||
2375 | "#]], | 2375 | "#]], |
2376 | ); | 2376 | ); |
2377 | } | 2377 | } |
2378 | |||
2379 | #[test] | ||
2380 | fn infer_const_params() { | ||
2381 | check_infer( | ||
2382 | r#" | ||
2383 | fn foo<const FOO: usize>() { | ||
2384 | let bar = FOO; | ||
2385 | } | ||
2386 | "#, | ||
2387 | expect![[r#" | ||
2388 | 27..49 '{ ...FOO; }': () | ||
2389 | 37..40 'bar': usize | ||
2390 | 43..46 'FOO': usize | ||
2391 | "#]], | ||
2392 | ); | ||
2393 | } | ||
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml index f1544dbe0..bb28cca4d 100644 --- a/crates/ide/Cargo.toml +++ b/crates/ide/Cargo.toml | |||
@@ -36,4 +36,4 @@ completion = { path = "../completion", version = "0.0.0" } | |||
36 | hir = { path = "../hir", version = "0.0.0" } | 36 | hir = { path = "../hir", version = "0.0.0" } |
37 | 37 | ||
38 | [dev-dependencies] | 38 | [dev-dependencies] |
39 | expect-test = "1.0" | 39 | expect-test = "1.1" |
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs index 60e0cd4ad..3c2d39f5d 100644 --- a/crates/ide/src/call_hierarchy.rs +++ b/crates/ide/src/call_hierarchy.rs | |||
@@ -8,7 +8,7 @@ use ide_db::RootDatabase; | |||
8 | use syntax::{ast, match_ast, AstNode, TextRange}; | 8 | use syntax::{ast, match_ast, AstNode, TextRange}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | display::ToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo, | 11 | display::TryToNav, goto_definition, references, FilePosition, NavigationTarget, RangeInfo, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | #[derive(Debug, Clone)] | 14 | #[derive(Debug, Clone)] |
@@ -61,7 +61,7 @@ pub(crate) fn incoming_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
61 | match node { | 61 | match node { |
62 | ast::Fn(it) => { | 62 | ast::Fn(it) => { |
63 | let def = sema.to_def(&it)?; | 63 | let def = sema.to_def(&it)?; |
64 | Some(def.to_nav(sema.db)) | 64 | def.try_to_nav(sema.db) |
65 | }, | 65 | }, |
66 | _ => None, | 66 | _ => None, |
67 | } | 67 | } |
@@ -99,7 +99,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
99 | match callable.kind() { | 99 | match callable.kind() { |
100 | hir::CallableKind::Function(it) => { | 100 | hir::CallableKind::Function(it) => { |
101 | let fn_def: hir::Function = it.into(); | 101 | let fn_def: hir::Function = it.into(); |
102 | let nav = fn_def.to_nav(db); | 102 | let nav = fn_def.try_to_nav(db)?; |
103 | Some(nav) | 103 | Some(nav) |
104 | } | 104 | } |
105 | _ => None, | 105 | _ => None, |
@@ -107,7 +107,7 @@ pub(crate) fn outgoing_calls(db: &RootDatabase, position: FilePosition) -> Optio | |||
107 | } | 107 | } |
108 | FnCallNode::MethodCallExpr(expr) => { | 108 | FnCallNode::MethodCallExpr(expr) => { |
109 | let function = sema.resolve_method_call(&expr)?; | 109 | let function = sema.resolve_method_call(&expr)?; |
110 | Some(function.to_nav(db)) | 110 | function.try_to_nav(db) |
111 | } | 111 | } |
112 | } { | 112 | } { |
113 | Some((func_target, name_ref.syntax().text_range())) | 113 | Some((func_target, name_ref.syntax().text_range())) |
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs index d79f5c170..ec0f840e9 100644 --- a/crates/ide/src/diagnostics/fixes.rs +++ b/crates/ide/src/diagnostics/fixes.rs | |||
@@ -156,20 +156,23 @@ fn missing_record_expr_field_fix( | |||
156 | let record_fields = match VariantDef::from(def_id) { | 156 | let record_fields = match VariantDef::from(def_id) { |
157 | VariantDef::Struct(s) => { | 157 | VariantDef::Struct(s) => { |
158 | module = s.module(sema.db); | 158 | module = s.module(sema.db); |
159 | let source = s.source(sema.db); | 159 | #[allow(deprecated)] |
160 | let source = s.source(sema.db)?; | ||
160 | def_file_id = source.file_id; | 161 | def_file_id = source.file_id; |
161 | let fields = source.value.field_list()?; | 162 | let fields = source.value.field_list()?; |
162 | record_field_list(fields)? | 163 | record_field_list(fields)? |
163 | } | 164 | } |
164 | VariantDef::Union(u) => { | 165 | VariantDef::Union(u) => { |
165 | module = u.module(sema.db); | 166 | module = u.module(sema.db); |
166 | let source = u.source(sema.db); | 167 | #[allow(deprecated)] |
168 | let source = u.source(sema.db)?; | ||
167 | def_file_id = source.file_id; | 169 | def_file_id = source.file_id; |
168 | source.value.record_field_list()? | 170 | source.value.record_field_list()? |
169 | } | 171 | } |
170 | VariantDef::Variant(e) => { | 172 | VariantDef::Variant(e) => { |
171 | module = e.module(sema.db); | 173 | module = e.module(sema.db); |
172 | let source = e.source(sema.db); | 174 | #[allow(deprecated)] |
175 | let source = e.source(sema.db)?; | ||
173 | def_file_id = source.file_id; | 176 | def_file_id = source.file_id; |
174 | let fields = source.value.field_list()?; | 177 | let fields = source.value.field_list()?; |
175 | record_field_list(fields)? | 178 | record_field_list(fields)? |
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs index 6431e7d6d..e24c78301 100644 --- a/crates/ide/src/display/navigation_target.rs +++ b/crates/ide/src/display/navigation_target.rs | |||
@@ -24,6 +24,7 @@ pub enum SymbolKind { | |||
24 | Impl, | 24 | Impl, |
25 | Field, | 25 | Field, |
26 | TypeParam, | 26 | TypeParam, |
27 | ConstParam, | ||
27 | LifetimeParam, | 28 | LifetimeParam, |
28 | ValueParam, | 29 | ValueParam, |
29 | SelfParam, | 30 | SelfParam, |
@@ -209,40 +210,32 @@ impl ToNav for FileSymbol { | |||
209 | impl TryToNav for Definition { | 210 | impl TryToNav for Definition { |
210 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | 211 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
211 | match self { | 212 | match self { |
212 | Definition::Macro(it) => { | 213 | Definition::Macro(it) => it.try_to_nav(db), |
213 | // FIXME: Currently proc-macro do not have ast-node, | 214 | Definition::Field(it) => it.try_to_nav(db), |
214 | // such that it does not have source | ||
215 | // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913 | ||
216 | if it.is_proc_macro() { | ||
217 | return None; | ||
218 | } | ||
219 | Some(it.to_nav(db)) | ||
220 | } | ||
221 | Definition::Field(it) => Some(it.to_nav(db)), | ||
222 | Definition::ModuleDef(it) => it.try_to_nav(db), | 215 | Definition::ModuleDef(it) => it.try_to_nav(db), |
223 | Definition::SelfType(it) => Some(it.to_nav(db)), | 216 | Definition::SelfType(it) => it.try_to_nav(db), |
224 | Definition::Local(it) => Some(it.to_nav(db)), | 217 | Definition::Local(it) => Some(it.to_nav(db)), |
225 | Definition::TypeParam(it) => Some(it.to_nav(db)), | 218 | Definition::TypeParam(it) => it.try_to_nav(db), |
226 | Definition::LifetimeParam(it) => Some(it.to_nav(db)), | 219 | Definition::LifetimeParam(it) => it.try_to_nav(db), |
227 | Definition::Label(it) => Some(it.to_nav(db)), | 220 | Definition::Label(it) => Some(it.to_nav(db)), |
221 | Definition::ConstParam(it) => it.try_to_nav(db), | ||
228 | } | 222 | } |
229 | } | 223 | } |
230 | } | 224 | } |
231 | 225 | ||
232 | impl TryToNav for hir::ModuleDef { | 226 | impl TryToNav for hir::ModuleDef { |
233 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | 227 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
234 | let res = match self { | 228 | match self { |
235 | hir::ModuleDef::Module(it) => it.to_nav(db), | 229 | hir::ModuleDef::Module(it) => Some(it.to_nav(db)), |
236 | hir::ModuleDef::Function(it) => it.to_nav(db), | 230 | hir::ModuleDef::Function(it) => it.try_to_nav(db), |
237 | hir::ModuleDef::Adt(it) => it.to_nav(db), | 231 | hir::ModuleDef::Adt(it) => it.try_to_nav(db), |
238 | hir::ModuleDef::Variant(it) => it.to_nav(db), | 232 | hir::ModuleDef::Variant(it) => it.try_to_nav(db), |
239 | hir::ModuleDef::Const(it) => it.to_nav(db), | 233 | hir::ModuleDef::Const(it) => it.try_to_nav(db), |
240 | hir::ModuleDef::Static(it) => it.to_nav(db), | 234 | hir::ModuleDef::Static(it) => it.try_to_nav(db), |
241 | hir::ModuleDef::Trait(it) => it.to_nav(db), | 235 | hir::ModuleDef::Trait(it) => it.try_to_nav(db), |
242 | hir::ModuleDef::TypeAlias(it) => it.to_nav(db), | 236 | hir::ModuleDef::TypeAlias(it) => it.try_to_nav(db), |
243 | hir::ModuleDef::BuiltinType(_) => return None, | 237 | hir::ModuleDef::BuiltinType(_) => None, |
244 | }; | 238 | } |
245 | Some(res) | ||
246 | } | 239 | } |
247 | } | 240 | } |
248 | 241 | ||
@@ -277,13 +270,13 @@ impl ToNavFromAst for hir::Trait { | |||
277 | const KIND: SymbolKind = SymbolKind::Trait; | 270 | const KIND: SymbolKind = SymbolKind::Trait; |
278 | } | 271 | } |
279 | 272 | ||
280 | impl<D> ToNav for D | 273 | impl<D> TryToNav for D |
281 | where | 274 | where |
282 | D: HasSource + ToNavFromAst + Copy + HasAttrs, | 275 | D: HasSource + ToNavFromAst + Copy + HasAttrs, |
283 | D::Ast: ast::NameOwner + ShortLabel, | 276 | D::Ast: ast::NameOwner + ShortLabel, |
284 | { | 277 | { |
285 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 278 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
286 | let src = self.source(db); | 279 | let src = self.source(db)?; |
287 | let mut res = NavigationTarget::from_named( | 280 | let mut res = NavigationTarget::from_named( |
288 | db, | 281 | db, |
289 | src.as_ref().map(|it| it as &dyn ast::NameOwner), | 282 | src.as_ref().map(|it| it as &dyn ast::NameOwner), |
@@ -291,7 +284,7 @@ where | |||
291 | ); | 284 | ); |
292 | res.docs = self.docs(db); | 285 | res.docs = self.docs(db); |
293 | res.description = src.value.short_label(); | 286 | res.description = src.value.short_label(); |
294 | res | 287 | Some(res) |
295 | } | 288 | } |
296 | } | 289 | } |
297 | 290 | ||
@@ -310,9 +303,9 @@ impl ToNav for hir::Module { | |||
310 | } | 303 | } |
311 | } | 304 | } |
312 | 305 | ||
313 | impl ToNav for hir::Impl { | 306 | impl TryToNav for hir::Impl { |
314 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 307 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
315 | let src = self.source(db); | 308 | let src = self.source(db)?; |
316 | let derive_attr = self.is_builtin_derive(db); | 309 | let derive_attr = self.is_builtin_derive(db); |
317 | let frange = if let Some(item) = &derive_attr { | 310 | let frange = if let Some(item) = &derive_attr { |
318 | item.syntax().original_file_range(db) | 311 | item.syntax().original_file_range(db) |
@@ -325,21 +318,21 @@ impl ToNav for hir::Impl { | |||
325 | src.value.self_ty().map(|ty| src.with_value(ty.syntax()).original_file_range(db).range) | 318 | src.value.self_ty().map(|ty| src.with_value(ty.syntax()).original_file_range(db).range) |
326 | }; | 319 | }; |
327 | 320 | ||
328 | NavigationTarget::from_syntax( | 321 | Some(NavigationTarget::from_syntax( |
329 | frange.file_id, | 322 | frange.file_id, |
330 | "impl".into(), | 323 | "impl".into(), |
331 | focus_range, | 324 | focus_range, |
332 | frange.range, | 325 | frange.range, |
333 | SymbolKind::Impl, | 326 | SymbolKind::Impl, |
334 | ) | 327 | )) |
335 | } | 328 | } |
336 | } | 329 | } |
337 | 330 | ||
338 | impl ToNav for hir::Field { | 331 | impl TryToNav for hir::Field { |
339 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 332 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
340 | let src = self.source(db); | 333 | let src = self.source(db)?; |
341 | 334 | ||
342 | match &src.value { | 335 | let field_source = match &src.value { |
343 | FieldSource::Named(it) => { | 336 | FieldSource::Named(it) => { |
344 | let mut res = | 337 | let mut res = |
345 | NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field); | 338 | NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field); |
@@ -357,13 +350,14 @@ impl ToNav for hir::Field { | |||
357 | SymbolKind::Field, | 350 | SymbolKind::Field, |
358 | ) | 351 | ) |
359 | } | 352 | } |
360 | } | 353 | }; |
354 | Some(field_source) | ||
361 | } | 355 | } |
362 | } | 356 | } |
363 | 357 | ||
364 | impl ToNav for hir::MacroDef { | 358 | impl TryToNav for hir::MacroDef { |
365 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 359 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
366 | let src = self.source(db); | 360 | let src = self.source(db)?; |
367 | log::debug!("nav target {:#?}", src.value.syntax()); | 361 | log::debug!("nav target {:#?}", src.value.syntax()); |
368 | let mut res = NavigationTarget::from_named( | 362 | let mut res = NavigationTarget::from_named( |
369 | db, | 363 | db, |
@@ -371,26 +365,26 @@ impl ToNav for hir::MacroDef { | |||
371 | SymbolKind::Macro, | 365 | SymbolKind::Macro, |
372 | ); | 366 | ); |
373 | res.docs = self.docs(db); | 367 | res.docs = self.docs(db); |
374 | res | 368 | Some(res) |
375 | } | 369 | } |
376 | } | 370 | } |
377 | 371 | ||
378 | impl ToNav for hir::Adt { | 372 | impl TryToNav for hir::Adt { |
379 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 373 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
380 | match self { | 374 | match self { |
381 | hir::Adt::Struct(it) => it.to_nav(db), | 375 | hir::Adt::Struct(it) => it.try_to_nav(db), |
382 | hir::Adt::Union(it) => it.to_nav(db), | 376 | hir::Adt::Union(it) => it.try_to_nav(db), |
383 | hir::Adt::Enum(it) => it.to_nav(db), | 377 | hir::Adt::Enum(it) => it.try_to_nav(db), |
384 | } | 378 | } |
385 | } | 379 | } |
386 | } | 380 | } |
387 | 381 | ||
388 | impl ToNav for hir::AssocItem { | 382 | impl TryToNav for hir::AssocItem { |
389 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 383 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
390 | match self { | 384 | match self { |
391 | AssocItem::Function(it) => it.to_nav(db), | 385 | AssocItem::Function(it) => it.try_to_nav(db), |
392 | AssocItem::Const(it) => it.to_nav(db), | 386 | AssocItem::Const(it) => it.try_to_nav(db), |
393 | AssocItem::TypeAlias(it) => it.to_nav(db), | 387 | AssocItem::TypeAlias(it) => it.try_to_nav(db), |
394 | } | 388 | } |
395 | } | 389 | } |
396 | } | 390 | } |
@@ -444,9 +438,9 @@ impl ToNav for hir::Label { | |||
444 | } | 438 | } |
445 | } | 439 | } |
446 | 440 | ||
447 | impl ToNav for hir::TypeParam { | 441 | impl TryToNav for hir::TypeParam { |
448 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 442 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
449 | let src = self.source(db); | 443 | let src = self.source(db)?; |
450 | let full_range = match &src.value { | 444 | let full_range = match &src.value { |
451 | Either::Left(it) => it.syntax().text_range(), | 445 | Either::Left(it) => it.syntax().text_range(), |
452 | Either::Right(it) => it.syntax().text_range(), | 446 | Either::Right(it) => it.syntax().text_range(), |
@@ -455,7 +449,7 @@ impl ToNav for hir::TypeParam { | |||
455 | Either::Left(_) => None, | 449 | Either::Left(_) => None, |
456 | Either::Right(it) => it.name().map(|it| it.syntax().text_range()), | 450 | Either::Right(it) => it.name().map(|it| it.syntax().text_range()), |
457 | }; | 451 | }; |
458 | NavigationTarget { | 452 | Some(NavigationTarget { |
459 | file_id: src.file_id.original_file(db), | 453 | file_id: src.file_id.original_file(db), |
460 | name: self.name(db).to_string().into(), | 454 | name: self.name(db).to_string().into(), |
461 | kind: Some(SymbolKind::TypeParam), | 455 | kind: Some(SymbolKind::TypeParam), |
@@ -464,15 +458,15 @@ impl ToNav for hir::TypeParam { | |||
464 | container_name: None, | 458 | container_name: None, |
465 | description: None, | 459 | description: None, |
466 | docs: None, | 460 | docs: None, |
467 | } | 461 | }) |
468 | } | 462 | } |
469 | } | 463 | } |
470 | 464 | ||
471 | impl ToNav for hir::LifetimeParam { | 465 | impl TryToNav for hir::LifetimeParam { |
472 | fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { | 466 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { |
473 | let src = self.source(db); | 467 | let src = self.source(db)?; |
474 | let full_range = src.value.syntax().text_range(); | 468 | let full_range = src.value.syntax().text_range(); |
475 | NavigationTarget { | 469 | Some(NavigationTarget { |
476 | file_id: src.file_id.original_file(db), | 470 | file_id: src.file_id.original_file(db), |
477 | name: self.name(db).to_string().into(), | 471 | name: self.name(db).to_string().into(), |
478 | kind: Some(SymbolKind::LifetimeParam), | 472 | kind: Some(SymbolKind::LifetimeParam), |
@@ -481,7 +475,24 @@ impl ToNav for hir::LifetimeParam { | |||
481 | container_name: None, | 475 | container_name: None, |
482 | description: None, | 476 | description: None, |
483 | docs: None, | 477 | docs: None, |
484 | } | 478 | }) |
479 | } | ||
480 | } | ||
481 | |||
482 | impl TryToNav for hir::ConstParam { | ||
483 | fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> { | ||
484 | let src = self.source(db)?; | ||
485 | let full_range = src.value.syntax().text_range(); | ||
486 | Some(NavigationTarget { | ||
487 | file_id: src.file_id.original_file(db), | ||
488 | name: self.name(db).to_string().into(), | ||
489 | kind: Some(SymbolKind::ConstParam), | ||
490 | full_range, | ||
491 | focus_range: src.value.name().map(|n| n.syntax().text_range()), | ||
492 | container_name: None, | ||
493 | description: None, | ||
494 | docs: None, | ||
495 | }) | ||
485 | } | 496 | } |
486 | } | 497 | } |
487 | 498 | ||
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index e10516f43..367fac05e 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs | |||
@@ -193,6 +193,7 @@ fn rewrite_intra_doc_link( | |||
193 | Definition::SelfType(_) | 193 | Definition::SelfType(_) |
194 | | Definition::Local(_) | 194 | | Definition::Local(_) |
195 | | Definition::TypeParam(_) | 195 | | Definition::TypeParam(_) |
196 | | Definition::ConstParam(_) | ||
196 | | Definition::LifetimeParam(_) | 197 | | Definition::LifetimeParam(_) |
197 | | Definition::Label(_) => return None, | 198 | | Definition::Label(_) => return None, |
198 | }?; | 199 | }?; |
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs index 6eac39639..da9378a97 100644 --- a/crates/ide/src/goto_implementation.rs +++ b/crates/ide/src/goto_implementation.rs | |||
@@ -2,7 +2,7 @@ use hir::{Crate, Impl, Semantics}; | |||
2 | use ide_db::RootDatabase; | 2 | use ide_db::RootDatabase; |
3 | use syntax::{algo::find_node_at_offset, ast, AstNode}; | 3 | use syntax::{algo::find_node_at_offset, ast, AstNode}; |
4 | 4 | ||
5 | use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; | 5 | use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo}; |
6 | 6 | ||
7 | // Feature: Go to Implementation | 7 | // Feature: Go to Implementation |
8 | // | 8 | // |
@@ -55,7 +55,7 @@ fn impls_for_def( | |||
55 | impls | 55 | impls |
56 | .into_iter() | 56 | .into_iter() |
57 | .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db))) | 57 | .filter(|impl_def| ty.is_equal_for_find_impls(&impl_def.target_ty(sema.db))) |
58 | .map(|imp| imp.to_nav(sema.db)) | 58 | .filter_map(|imp| imp.try_to_nav(sema.db)) |
59 | .collect(), | 59 | .collect(), |
60 | ) | 60 | ) |
61 | } | 61 | } |
@@ -69,7 +69,7 @@ fn impls_for_trait( | |||
69 | 69 | ||
70 | let impls = Impl::for_trait(sema.db, krate, tr); | 70 | let impls = Impl::for_trait(sema.db, krate, tr); |
71 | 71 | ||
72 | Some(impls.into_iter().map(|imp| imp.to_nav(sema.db)).collect()) | 72 | Some(impls.into_iter().filter_map(|imp| imp.try_to_nav(sema.db)).collect()) |
73 | } | 73 | } |
74 | 74 | ||
75 | #[cfg(test)] | 75 | #[cfg(test)] |
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs index aba6bf5dc..7e84e06be 100644 --- a/crates/ide/src/goto_type_definition.rs +++ b/crates/ide/src/goto_type_definition.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use ide_db::RootDatabase; | 1 | use ide_db::RootDatabase; |
2 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; | 2 | use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; |
3 | 3 | ||
4 | use crate::{display::ToNav, FilePosition, NavigationTarget, RangeInfo}; | 4 | use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo}; |
5 | 5 | ||
6 | // Feature: Go to Type Definition | 6 | // Feature: Go to Type Definition |
7 | // | 7 | // |
@@ -37,7 +37,7 @@ pub(crate) fn goto_type_definition( | |||
37 | 37 | ||
38 | let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?; | 38 | let adt_def = ty.autoderef(db).filter_map(|ty| ty.as_adt()).last()?; |
39 | 39 | ||
40 | let nav = adt_def.to_nav(db); | 40 | let nav = adt_def.try_to_nav(db)?; |
41 | Some(RangeInfo::new(node.text_range(), vec![nav])) | 41 | Some(RangeInfo::new(node.text_range(), vec![nav])) |
42 | } | 42 | } |
43 | 43 | ||
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 73245fbe7..2737c900f 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -13,7 +13,7 @@ use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, | |||
13 | use test_utils::mark; | 13 | use test_utils::mark; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | display::{macro_label, ShortLabel, ToNav, TryToNav}, | 16 | display::{macro_label, ShortLabel, TryToNav}, |
17 | doc_links::{remove_links, rewrite_links}, | 17 | doc_links::{remove_links, rewrite_links}, |
18 | markdown_remove::remove_markdown, | 18 | markdown_remove::remove_markdown, |
19 | markup::Markup, | 19 | markup::Markup, |
@@ -109,6 +109,8 @@ pub(crate) fn hover( | |||
109 | match node { | 109 | match node { |
110 | ast::Name(name) => NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db)), | 110 | ast::Name(name) => NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db)), |
111 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), | 111 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), |
112 | ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime) | ||
113 | .map_or_else(|| NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(sema.db)), |d| d.defined(sema.db)), | ||
112 | _ => None, | 114 | _ => None, |
113 | } | 115 | } |
114 | }; | 116 | }; |
@@ -181,10 +183,10 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov | |||
181 | 183 | ||
182 | match def { | 184 | match def { |
183 | Definition::ModuleDef(it) => match it { | 185 | Definition::ModuleDef(it) => match it { |
184 | ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))), | 186 | ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.try_to_nav(db)?)), |
185 | ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))), | 187 | ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.try_to_nav(db)?)), |
186 | ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))), | 188 | ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.try_to_nav(db)?)), |
187 | ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))), | 189 | ModuleDef::Trait(it) => Some(to_action(it.try_to_nav(db)?)), |
188 | _ => None, | 190 | _ => None, |
189 | }, | 191 | }, |
190 | _ => None, | 192 | _ => None, |
@@ -204,7 +206,8 @@ fn runnable_action( | |||
204 | _ => None, | 206 | _ => None, |
205 | }, | 207 | }, |
206 | ModuleDef::Function(it) => { | 208 | ModuleDef::Function(it) => { |
207 | let src = it.source(sema.db); | 209 | #[allow(deprecated)] |
210 | let src = it.source(sema.db)?; | ||
208 | if src.file_id != file_id.into() { | 211 | if src.file_id != file_id.into() { |
209 | mark::hit!(hover_macro_generated_struct_fn_doc_comment); | 212 | mark::hit!(hover_macro_generated_struct_fn_doc_comment); |
210 | mark::hit!(hover_macro_generated_struct_fn_doc_attr); | 213 | mark::hit!(hover_macro_generated_struct_fn_doc_attr); |
@@ -324,17 +327,12 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
324 | let mod_path = definition_mod_path(db, &def); | 327 | let mod_path = definition_mod_path(db, &def); |
325 | return match def { | 328 | return match def { |
326 | Definition::Macro(it) => { | 329 | Definition::Macro(it) => { |
327 | // FIXME: Currently proc-macro do not have ast-node, | 330 | let label = macro_label(&it.source(db)?.value); |
328 | // such that it does not have source | ||
329 | // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913 | ||
330 | if it.is_proc_macro() { | ||
331 | return None; | ||
332 | } | ||
333 | let label = macro_label(&it.source(db).value); | ||
334 | from_def_source_labeled(db, it, Some(label), mod_path) | 331 | from_def_source_labeled(db, it, Some(label), mod_path) |
335 | } | 332 | } |
336 | Definition::Field(def) => { | 333 | Definition::Field(def) => { |
337 | let src = def.source(db).value; | 334 | #[allow(deprecated)] |
335 | let src = def.source(db)?.value; | ||
338 | if let FieldSource::Named(it) = src { | 336 | if let FieldSource::Named(it) = src { |
339 | from_def_source_labeled(db, def, it.short_label(), mod_path) | 337 | from_def_source_labeled(db, def, it.short_label(), mod_path) |
340 | } else { | 338 | } else { |
@@ -360,9 +358,9 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
360 | ModuleDef::Static(it) => from_def_source(db, it, mod_path), | 358 | ModuleDef::Static(it) => from_def_source(db, it, mod_path), |
361 | ModuleDef::Trait(it) => from_def_source(db, it, mod_path), | 359 | ModuleDef::Trait(it) => from_def_source(db, it, mod_path), |
362 | ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), | 360 | ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), |
363 | ModuleDef::BuiltinType(it) => return Some(it.to_string().into()), | 361 | ModuleDef::BuiltinType(it) => Some(Markup::fenced_block(&it)), |
364 | }, | 362 | }, |
365 | Definition::Local(it) => return Some(Markup::fenced_block(&it.ty(db).display(db))), | 363 | Definition::Local(it) => Some(Markup::fenced_block(&it.ty(db).display(db))), |
366 | Definition::SelfType(impl_def) => { | 364 | Definition::SelfType(impl_def) => { |
367 | impl_def.target_ty(db).as_adt().and_then(|adt| match adt { | 365 | impl_def.target_ty(db).as_adt().and_then(|adt| match adt { |
368 | Adt::Struct(it) => from_def_source(db, it, mod_path), | 366 | Adt::Struct(it) => from_def_source(db, it, mod_path), |
@@ -370,7 +368,9 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
370 | Adt::Enum(it) => from_def_source(db, it, mod_path), | 368 | Adt::Enum(it) => from_def_source(db, it, mod_path), |
371 | }) | 369 | }) |
372 | } | 370 | } |
373 | Definition::TypeParam(_) | Definition::LifetimeParam(_) | Definition::Label(_) => { | 371 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), |
372 | Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), | ||
373 | Definition::TypeParam(_) | Definition::ConstParam(_) => { | ||
374 | // FIXME: Hover for generic param | 374 | // FIXME: Hover for generic param |
375 | None | 375 | None |
376 | } | 376 | } |
@@ -381,7 +381,8 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
381 | D: HasSource<Ast = A> + HasAttrs + Copy, | 381 | D: HasSource<Ast = A> + HasAttrs + Copy, |
382 | A: ShortLabel, | 382 | A: ShortLabel, |
383 | { | 383 | { |
384 | let short_label = def.source(db).value.short_label(); | 384 | #[allow(deprecated)] |
385 | let short_label = def.source(db)?.value.short_label(); | ||
385 | from_def_source_labeled(db, def, short_label, mod_path) | 386 | from_def_source_labeled(db, def, short_label, mod_path) |
386 | } | 387 | } |
387 | 388 | ||
@@ -403,7 +404,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | |||
403 | return tokens.max_by_key(priority); | 404 | return tokens.max_by_key(priority); |
404 | fn priority(n: &SyntaxToken) -> usize { | 405 | fn priority(n: &SyntaxToken) -> usize { |
405 | match n.kind() { | 406 | match n.kind() { |
406 | IDENT | INT_NUMBER => 3, | 407 | IDENT | INT_NUMBER | LIFETIME_IDENT => 3, |
407 | T!['('] | T![')'] => 2, | 408 | T!['('] | T![')'] => 2, |
408 | kind if kind.is_trivia() => 0, | 409 | kind if kind.is_trivia() => 0, |
409 | _ => 1, | 410 | _ => 1, |
@@ -1169,7 +1170,10 @@ fn f() { fo<|>o!(); } | |||
1169 | r#"struct TS(String, i32<|>);"#, | 1170 | r#"struct TS(String, i32<|>);"#, |
1170 | expect![[r#" | 1171 | expect![[r#" |
1171 | *i32* | 1172 | *i32* |
1173 | |||
1174 | ```rust | ||
1172 | i32 | 1175 | i32 |
1176 | ``` | ||
1173 | "#]], | 1177 | "#]], |
1174 | ) | 1178 | ) |
1175 | } | 1179 | } |
@@ -3221,4 +3225,36 @@ fn no_hover() { | |||
3221 | "#, | 3225 | "#, |
3222 | ); | 3226 | ); |
3223 | } | 3227 | } |
3228 | |||
3229 | #[test] | ||
3230 | fn hover_label() { | ||
3231 | check( | ||
3232 | r#" | ||
3233 | fn foo() { | ||
3234 | 'label<|>: loop {} | ||
3235 | } | ||
3236 | "#, | ||
3237 | expect![[r#" | ||
3238 | *'label* | ||
3239 | |||
3240 | ```rust | ||
3241 | 'label | ||
3242 | ``` | ||
3243 | "#]], | ||
3244 | ); | ||
3245 | } | ||
3246 | |||
3247 | #[test] | ||
3248 | fn hover_lifetime() { | ||
3249 | check( | ||
3250 | r#"fn foo<'lifetime>(_: &'lifetime<|> ()) {}"#, | ||
3251 | expect![[r#" | ||
3252 | *'lifetime* | ||
3253 | |||
3254 | ```rust | ||
3255 | 'lifetime | ||
3256 | ``` | ||
3257 | "#]], | ||
3258 | ); | ||
3259 | } | ||
3224 | } | 3260 | } |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index b3331f03f..a450794f3 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -31,6 +31,7 @@ mod folding_ranges; | |||
31 | mod goto_definition; | 31 | mod goto_definition; |
32 | mod goto_implementation; | 32 | mod goto_implementation; |
33 | mod goto_type_definition; | 33 | mod goto_type_definition; |
34 | mod view_hir; | ||
34 | mod hover; | 35 | mod hover; |
35 | mod inlay_hints; | 36 | mod inlay_hints; |
36 | mod join_lines; | 37 | mod join_lines; |
@@ -271,6 +272,10 @@ impl Analysis { | |||
271 | self.with_db(|db| syntax_tree::syntax_tree(&db, file_id, text_range)) | 272 | self.with_db(|db| syntax_tree::syntax_tree(&db, file_id, text_range)) |
272 | } | 273 | } |
273 | 274 | ||
275 | pub fn view_hir(&self, position: FilePosition) -> Cancelable<String> { | ||
276 | self.with_db(|db| view_hir::view_hir(&db, position)) | ||
277 | } | ||
278 | |||
274 | pub fn expand_macro(&self, position: FilePosition) -> Cancelable<Option<ExpandedMacro>> { | 279 | pub fn expand_macro(&self, position: FilePosition) -> Cancelable<Option<ExpandedMacro>> { |
275 | self.with_db(|db| expand_macro::expand_macro(db, position)) | 280 | self.with_db(|db| expand_macro::expand_macro(db, position)) |
276 | } | 281 | } |
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs index 21b2d7ca1..fa58fc319 100644 --- a/crates/ide/src/references.rs +++ b/crates/ide/src/references.rs | |||
@@ -1144,4 +1144,20 @@ fn foo<'a>() -> &'a () { | |||
1144 | "#]], | 1144 | "#]], |
1145 | ); | 1145 | ); |
1146 | } | 1146 | } |
1147 | |||
1148 | #[test] | ||
1149 | fn test_find_const_param() { | ||
1150 | check( | ||
1151 | r#" | ||
1152 | fn foo<const FOO<|>: usize>() -> usize { | ||
1153 | FOO | ||
1154 | } | ||
1155 | "#, | ||
1156 | expect![[r#" | ||
1157 | FOO ConstParam FileId(0) 7..23 13..16 Other | ||
1158 | |||
1159 | FileId(0) 42..45 Other | ||
1160 | "#]], | ||
1161 | ); | ||
1162 | } | ||
1147 | } | 1163 | } |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index 891183266..c893afc7c 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -230,7 +230,7 @@ impl TestAttr { | |||
230 | 230 | ||
231 | const RUSTDOC_FENCE: &str = "```"; | 231 | const RUSTDOC_FENCE: &str = "```"; |
232 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = | 232 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] = |
233 | &["", "rust", "should_panic", "edition2015", "edition2018"]; | 233 | &["", "rust", "should_panic", "edition2015", "edition2018", "edition2021"]; |
234 | 234 | ||
235 | fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { | 235 | fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool { |
236 | attrs.docs().map_or(false, |doc| { | 236 | attrs.docs().map_or(false, |doc| { |
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs index 5ad96581b..ba0085244 100644 --- a/crates/ide/src/syntax_highlighting.rs +++ b/crates/ide/src/syntax_highlighting.rs | |||
@@ -819,6 +819,7 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { | |||
819 | }, | 819 | }, |
820 | Definition::SelfType(_) => HighlightTag::Symbol(SymbolKind::Impl), | 820 | Definition::SelfType(_) => HighlightTag::Symbol(SymbolKind::Impl), |
821 | Definition::TypeParam(_) => HighlightTag::Symbol(SymbolKind::TypeParam), | 821 | Definition::TypeParam(_) => HighlightTag::Symbol(SymbolKind::TypeParam), |
822 | Definition::ConstParam(_) => HighlightTag::Symbol(SymbolKind::ConstParam), | ||
822 | Definition::Local(local) => { | 823 | Definition::Local(local) => { |
823 | let tag = if local.is_param(db) { | 824 | let tag = if local.is_param(db) { |
824 | HighlightTag::Symbol(SymbolKind::ValueParam) | 825 | HighlightTag::Symbol(SymbolKind::ValueParam) |
diff --git a/crates/ide/src/syntax_highlighting/injection.rs b/crates/ide/src/syntax_highlighting/injection.rs index 9eb184c74..6cbd683c6 100644 --- a/crates/ide/src/syntax_highlighting/injection.rs +++ b/crates/ide/src/syntax_highlighting/injection.rs | |||
@@ -54,8 +54,17 @@ pub(super) fn highlight_injection( | |||
54 | type RangesMap = BTreeMap<TextSize, TextSize>; | 54 | type RangesMap = BTreeMap<TextSize, TextSize>; |
55 | 55 | ||
56 | const RUSTDOC_FENCE: &'static str = "```"; | 56 | const RUSTDOC_FENCE: &'static str = "```"; |
57 | const RUSTDOC_FENCE_TOKENS: &[&'static str] = | 57 | const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[ |
58 | &["", "rust", "should_panic", "ignore", "no_run", "compile_fail", "edition2015", "edition2018"]; | 58 | "", |
59 | "rust", | ||
60 | "should_panic", | ||
61 | "ignore", | ||
62 | "no_run", | ||
63 | "compile_fail", | ||
64 | "edition2015", | ||
65 | "edition2018", | ||
66 | "edition2021", | ||
67 | ]; | ||
59 | 68 | ||
60 | /// Extracts Rust code from documentation comments as well as a mapping from | 69 | /// Extracts Rust code from documentation comments as well as a mapping from |
61 | /// the extracted source code back to the original source ranges. | 70 | /// the extracted source code back to the original source ranges. |
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs index 2a6cc0cab..8b8867079 100644 --- a/crates/ide/src/syntax_highlighting/tags.rs +++ b/crates/ide/src/syntax_highlighting/tags.rs | |||
@@ -77,6 +77,7 @@ impl HighlightTag { | |||
77 | SymbolKind::Function => "function", | 77 | SymbolKind::Function => "function", |
78 | SymbolKind::TypeAlias => "type_alias", | 78 | SymbolKind::TypeAlias => "type_alias", |
79 | SymbolKind::TypeParam => "type_param", | 79 | SymbolKind::TypeParam => "type_param", |
80 | SymbolKind::ConstParam => "const_param", | ||
80 | SymbolKind::LifetimeParam => "lifetime", | 81 | SymbolKind::LifetimeParam => "lifetime", |
81 | SymbolKind::Macro => "macro", | 82 | SymbolKind::Macro => "macro", |
82 | SymbolKind::Local => "variable", | 83 | SymbolKind::Local => "variable", |
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html index 72ff9dd40..02270b077 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html | |||
@@ -118,6 +118,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd | |||
118 | <span class="keyword control">loop</span> <span class="punctuation">{</span><span class="punctuation">}</span> | 118 | <span class="keyword control">loop</span> <span class="punctuation">{</span><span class="punctuation">}</span> |
119 | <span class="punctuation">}</span> | 119 | <span class="punctuation">}</span> |
120 | 120 | ||
121 | <span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="punctuation"><</span><span class="keyword">const</span> <span class="const_param declaration">FOO</span><span class="punctuation">:</span> <span class="builtin_type">usize</span><span class="punctuation">></span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="builtin_type">usize</span> <span class="punctuation">{</span> | ||
122 | <span class="const_param">FOO</span> | ||
123 | <span class="punctuation">}</span> | ||
124 | |||
121 | <span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="punctuation">;</span> | 125 | <span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="punctuation">;</span> |
122 | <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation"><</span><span class="type_param declaration">F</span><span class="punctuation">:</span> <span class="trait">Fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">></span><span class="punctuation">(</span><span class="value_param declaration callable">f</span><span class="punctuation">:</span> <span class="type_param">F</span><span class="punctuation">)</span> <span class="punctuation">{</span> | 126 | <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation"><</span><span class="type_param declaration">F</span><span class="punctuation">:</span> <span class="trait">Fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-></span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">></span><span class="punctuation">(</span><span class="value_param declaration callable">f</span><span class="punctuation">:</span> <span class="type_param">F</span><span class="punctuation">)</span> <span class="punctuation">{</span> |
123 | <span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span> | 127 | <span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span> |
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs index e0df0d2b5..30b5b648e 100644 --- a/crates/ide/src/syntax_highlighting/tests.rs +++ b/crates/ide/src/syntax_highlighting/tests.rs | |||
@@ -91,6 +91,10 @@ fn never() -> ! { | |||
91 | loop {} | 91 | loop {} |
92 | } | 92 | } |
93 | 93 | ||
94 | fn const_param<const FOO: usize>() -> usize { | ||
95 | FOO | ||
96 | } | ||
97 | |||
94 | use ops::Fn; | 98 | use ops::Fn; |
95 | fn baz<F: Fn() -> ()>(f: F) { | 99 | fn baz<F: Fn() -> ()>(f: F) { |
96 | f() | 100 | f() |
diff --git a/crates/ide/src/view_hir.rs b/crates/ide/src/view_hir.rs new file mode 100644 index 000000000..cfcfb7cfb --- /dev/null +++ b/crates/ide/src/view_hir.rs | |||
@@ -0,0 +1,25 @@ | |||
1 | use hir::{Function, Semantics}; | ||
2 | use ide_db::base_db::FilePosition; | ||
3 | use ide_db::RootDatabase; | ||
4 | use syntax::{algo::find_node_at_offset, ast, AstNode}; | ||
5 | |||
6 | // Feature: View Hir | ||
7 | // | ||
8 | // |=== | ||
9 | // | Editor | Action Name | ||
10 | // | ||
11 | // | VS Code | **Rust Analyzer: View Hir** | ||
12 | // |=== | ||
13 | pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String { | ||
14 | body_hir(db, position).unwrap_or("Not inside a function body".to_string()) | ||
15 | } | ||
16 | |||
17 | fn body_hir(db: &RootDatabase, position: FilePosition) -> Option<String> { | ||
18 | let sema = Semantics::new(db); | ||
19 | let source_file = sema.parse(position.file_id); | ||
20 | |||
21 | let function = find_node_at_offset::<ast::Fn>(source_file.syntax(), position.offset)?; | ||
22 | |||
23 | let function: Function = sema.to_def(&function)?; | ||
24 | Some(function.debug_hir(db)) | ||
25 | } | ||
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml index ebe53c8ee..d3d3dc688 100644 --- a/crates/ide_db/Cargo.toml +++ b/crates/ide_db/Cargo.toml | |||
@@ -32,4 +32,4 @@ test_utils = { path = "../test_utils", version = "0.0.0" } | |||
32 | hir = { path = "../hir", version = "0.0.0" } | 32 | hir = { path = "../hir", version = "0.0.0" } |
33 | 33 | ||
34 | [dev-dependencies] | 34 | [dev-dependencies] |
35 | expect-test = "1.0" | 35 | expect-test = "1.1" |
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs index d33a6cb86..cc5078bf0 100644 --- a/crates/ide_db/src/defs.rs +++ b/crates/ide_db/src/defs.rs | |||
@@ -6,8 +6,8 @@ | |||
6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). | 6 | // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06). |
7 | 7 | ||
8 | use hir::{ | 8 | use hir::{ |
9 | db::HirDatabase, Crate, Field, HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, | 9 | db::HirDatabase, ConstParam, Crate, Field, HasVisibility, Impl, Label, LifetimeParam, Local, |
10 | Module, ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility, | 10 | MacroDef, Module, ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility, |
11 | }; | 11 | }; |
12 | use syntax::{ | 12 | use syntax::{ |
13 | ast::{self, AstNode}, | 13 | ast::{self, AstNode}, |
@@ -26,6 +26,7 @@ pub enum Definition { | |||
26 | Local(Local), | 26 | Local(Local), |
27 | TypeParam(TypeParam), | 27 | TypeParam(TypeParam), |
28 | LifetimeParam(LifetimeParam), | 28 | LifetimeParam(LifetimeParam), |
29 | ConstParam(ConstParam), | ||
29 | Label(Label), | 30 | Label(Label), |
30 | } | 31 | } |
31 | 32 | ||
@@ -39,6 +40,7 @@ impl Definition { | |||
39 | Definition::Local(it) => Some(it.module(db)), | 40 | Definition::Local(it) => Some(it.module(db)), |
40 | Definition::TypeParam(it) => Some(it.module(db)), | 41 | Definition::TypeParam(it) => Some(it.module(db)), |
41 | Definition::LifetimeParam(it) => Some(it.module(db)), | 42 | Definition::LifetimeParam(it) => Some(it.module(db)), |
43 | Definition::ConstParam(it) => Some(it.module(db)), | ||
42 | Definition::Label(it) => Some(it.module(db)), | 44 | Definition::Label(it) => Some(it.module(db)), |
43 | } | 45 | } |
44 | } | 46 | } |
@@ -52,6 +54,7 @@ impl Definition { | |||
52 | Definition::Local(_) => None, | 54 | Definition::Local(_) => None, |
53 | Definition::TypeParam(_) => None, | 55 | Definition::TypeParam(_) => None, |
54 | Definition::LifetimeParam(_) => None, | 56 | Definition::LifetimeParam(_) => None, |
57 | Definition::ConstParam(_) => None, | ||
55 | Definition::Label(_) => None, | 58 | Definition::Label(_) => None, |
56 | } | 59 | } |
57 | } | 60 | } |
@@ -79,6 +82,7 @@ impl Definition { | |||
79 | Definition::Local(it) => it.name(db)?, | 82 | Definition::Local(it) => it.name(db)?, |
80 | Definition::TypeParam(it) => it.name(db), | 83 | Definition::TypeParam(it) => it.name(db), |
81 | Definition::LifetimeParam(it) => it.name(db), | 84 | Definition::LifetimeParam(it) => it.name(db), |
85 | Definition::ConstParam(it) => it.name(db), | ||
82 | Definition::Label(it) => it.name(db), | 86 | Definition::Label(it) => it.name(db), |
83 | }; | 87 | }; |
84 | Some(name) | 88 | Some(name) |
@@ -233,6 +237,10 @@ impl NameClass { | |||
233 | let def = sema.to_def(&it)?; | 237 | let def = sema.to_def(&it)?; |
234 | Some(NameClass::Definition(Definition::TypeParam(def))) | 238 | Some(NameClass::Definition(Definition::TypeParam(def))) |
235 | }, | 239 | }, |
240 | ast::ConstParam(it) => { | ||
241 | let def = sema.to_def(&it)?; | ||
242 | Some(NameClass::Definition(Definition::ConstParam(def))) | ||
243 | }, | ||
236 | _ => None, | 244 | _ => None, |
237 | } | 245 | } |
238 | } | 246 | } |
@@ -417,6 +425,7 @@ impl From<PathResolution> for Definition { | |||
417 | PathResolution::TypeParam(par) => Definition::TypeParam(par), | 425 | PathResolution::TypeParam(par) => Definition::TypeParam(par), |
418 | PathResolution::Macro(def) => Definition::Macro(def), | 426 | PathResolution::Macro(def) => Definition::Macro(def), |
419 | PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def), | 427 | PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def), |
428 | PathResolution::ConstParam(par) => Definition::ConstParam(par), | ||
420 | } | 429 | } |
421 | } | 430 | } |
422 | } | 431 | } |
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs index ff10f71c3..436c59d2c 100644 --- a/crates/ide_db/src/search.rs +++ b/crates/ide_db/src/search.rs | |||
@@ -121,31 +121,56 @@ impl Definition { | |||
121 | 121 | ||
122 | if let Definition::Local(var) = self { | 122 | if let Definition::Local(var) = self { |
123 | let range = match var.parent(db) { | 123 | let range = match var.parent(db) { |
124 | DefWithBody::Function(f) => f.source(db).value.syntax().text_range(), | 124 | DefWithBody::Function(f) => { |
125 | DefWithBody::Const(c) => c.source(db).value.syntax().text_range(), | 125 | f.source(db).and_then(|src| Some(src.value.syntax().text_range())) |
126 | DefWithBody::Static(s) => s.source(db).value.syntax().text_range(), | 126 | } |
127 | DefWithBody::Const(c) => { | ||
128 | c.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
129 | } | ||
130 | DefWithBody::Static(s) => { | ||
131 | s.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
132 | } | ||
127 | }; | 133 | }; |
128 | let mut res = FxHashMap::default(); | 134 | let mut res = FxHashMap::default(); |
129 | res.insert(file_id, Some(range)); | 135 | res.insert(file_id, range); |
130 | return SearchScope::new(res); | 136 | return SearchScope::new(res); |
131 | } | 137 | } |
132 | 138 | ||
133 | if let Definition::LifetimeParam(param) = self { | 139 | if let Definition::LifetimeParam(param) = self { |
140 | #[allow(deprecated)] | ||
134 | let range = match param.parent(db) { | 141 | let range = match param.parent(db) { |
135 | hir::GenericDef::Function(it) => it.source(db).value.syntax().text_range(), | 142 | hir::GenericDef::Function(it) => { |
143 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
144 | } | ||
136 | hir::GenericDef::Adt(it) => match it { | 145 | hir::GenericDef::Adt(it) => match it { |
137 | hir::Adt::Struct(it) => it.source(db).value.syntax().text_range(), | 146 | hir::Adt::Struct(it) => { |
138 | hir::Adt::Union(it) => it.source(db).value.syntax().text_range(), | 147 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) |
139 | hir::Adt::Enum(it) => it.source(db).value.syntax().text_range(), | 148 | } |
149 | hir::Adt::Union(it) => { | ||
150 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
151 | } | ||
152 | hir::Adt::Enum(it) => { | ||
153 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
154 | } | ||
140 | }, | 155 | }, |
141 | hir::GenericDef::Trait(it) => it.source(db).value.syntax().text_range(), | 156 | hir::GenericDef::Trait(it) => { |
142 | hir::GenericDef::TypeAlias(it) => it.source(db).value.syntax().text_range(), | 157 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) |
143 | hir::GenericDef::Impl(it) => it.source(db).value.syntax().text_range(), | 158 | } |
144 | hir::GenericDef::Variant(it) => it.source(db).value.syntax().text_range(), | 159 | hir::GenericDef::TypeAlias(it) => { |
145 | hir::GenericDef::Const(it) => it.source(db).value.syntax().text_range(), | 160 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) |
161 | } | ||
162 | hir::GenericDef::Impl(it) => { | ||
163 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
164 | } | ||
165 | hir::GenericDef::Variant(it) => { | ||
166 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
167 | } | ||
168 | hir::GenericDef::Const(it) => { | ||
169 | it.source(db).and_then(|src| Some(src.value.syntax().text_range())) | ||
170 | } | ||
146 | }; | 171 | }; |
147 | let mut res = FxHashMap::default(); | 172 | let mut res = FxHashMap::default(); |
148 | res.insert(file_id, Some(range)); | 173 | res.insert(file_id, range); |
149 | return SearchScope::new(res); | 174 | return SearchScope::new(res); |
150 | } | 175 | } |
151 | 176 | ||
diff --git a/crates/proc_macro_api/src/msg.rs b/crates/proc_macro_api/src/msg.rs index f84ebdbc5..4cd572101 100644 --- a/crates/proc_macro_api/src/msg.rs +++ b/crates/proc_macro_api/src/msg.rs | |||
@@ -58,7 +58,13 @@ pub trait Message: Serialize + DeserializeOwned { | |||
58 | fn read(inp: &mut impl BufRead) -> io::Result<Option<Self>> { | 58 | fn read(inp: &mut impl BufRead) -> io::Result<Option<Self>> { |
59 | Ok(match read_json(inp)? { | 59 | Ok(match read_json(inp)? { |
60 | None => None, | 60 | None => None, |
61 | Some(text) => Some(serde_json::from_str(&text)?), | 61 | Some(text) => { |
62 | let mut deserializer = serde_json::Deserializer::from_str(&text); | ||
63 | // Note that some proc-macro generate very deep syntax tree | ||
64 | // We have to disable the current limit of serde here | ||
65 | deserializer.disable_recursion_limit(); | ||
66 | Some(Self::deserialize(&mut deserializer)?) | ||
67 | } | ||
62 | }) | 68 | }) |
63 | } | 69 | } |
64 | fn write(self, out: &mut impl Write) -> io::Result<()> { | 70 | fn write(self, out: &mut impl Write) -> io::Result<()> { |
diff --git a/crates/proc_macro_api/src/process.rs b/crates/proc_macro_api/src/process.rs index d68723ada..6d6ab8888 100644 --- a/crates/proc_macro_api/src/process.rs +++ b/crates/proc_macro_api/src/process.rs | |||
@@ -92,10 +92,11 @@ fn client_loop(task_rx: Receiver<Task>, mut process: Process) { | |||
92 | for Task { req, result_tx } in task_rx { | 92 | for Task { req, result_tx } in task_rx { |
93 | match send_request(&mut stdin, &mut stdout, req) { | 93 | match send_request(&mut stdin, &mut stdout, req) { |
94 | Ok(res) => result_tx.send(res).unwrap(), | 94 | Ok(res) => result_tx.send(res).unwrap(), |
95 | Err(_err) => { | 95 | Err(err) => { |
96 | log::error!( | 96 | log::error!( |
97 | "proc macro server crashed, server process state: {:?}", | 97 | "proc macro server crashed, server process state: {:?}, server request error: {:?}", |
98 | process.child.try_wait() | 98 | process.child.try_wait(), |
99 | err | ||
99 | ); | 100 | ); |
100 | let res = Response::Error(ResponseError { | 101 | let res = Response::Error(ResponseError { |
101 | code: ErrorCode::ServerErrorEnd, | 102 | code: ErrorCode::ServerErrorEnd, |
diff --git a/crates/project_model/src/project_json.rs b/crates/project_model/src/project_json.rs index aab279223..af884eb84 100644 --- a/crates/project_model/src/project_json.rs +++ b/crates/project_model/src/project_json.rs | |||
@@ -139,6 +139,8 @@ enum EditionData { | |||
139 | Edition2015, | 139 | Edition2015, |
140 | #[serde(rename = "2018")] | 140 | #[serde(rename = "2018")] |
141 | Edition2018, | 141 | Edition2018, |
142 | #[serde(rename = "2021")] | ||
143 | Edition2021, | ||
142 | } | 144 | } |
143 | 145 | ||
144 | impl From<EditionData> for Edition { | 146 | impl From<EditionData> for Edition { |
@@ -146,6 +148,7 @@ impl From<EditionData> for Edition { | |||
146 | match data { | 148 | match data { |
147 | EditionData::Edition2015 => Edition::Edition2015, | 149 | EditionData::Edition2015 => Edition::Edition2015, |
148 | EditionData::Edition2018 => Edition::Edition2018, | 150 | EditionData::Edition2018 => Edition::Edition2018, |
151 | EditionData::Edition2021 => Edition::Edition2021, | ||
149 | } | 152 | } |
150 | } | 153 | } |
151 | } | 154 | } |
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 0a63593fb..af7b86ead 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml | |||
@@ -62,7 +62,7 @@ proc_macro_srv = { path = "../proc_macro_srv", version = "0.0.0" } | |||
62 | winapi = "0.3.8" | 62 | winapi = "0.3.8" |
63 | 63 | ||
64 | [dev-dependencies] | 64 | [dev-dependencies] |
65 | expect-test = "1.0" | 65 | expect-test = "1.1" |
66 | test_utils = { path = "../test_utils" } | 66 | test_utils = { path = "../test_utils" } |
67 | mbe = { path = "../mbe" } | 67 | mbe = { path = "../mbe" } |
68 | tt = { path = "../tt" } | 68 | tt = { path = "../tt" } |
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index a23fb7a33..9445aec07 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs | |||
@@ -161,11 +161,12 @@ impl AnalysisStatsCmd { | |||
161 | } | 161 | } |
162 | let mut msg = format!("processing: {}", full_name); | 162 | let mut msg = format!("processing: {}", full_name); |
163 | if verbosity.is_verbose() { | 163 | if verbosity.is_verbose() { |
164 | let src = f.source(db); | 164 | if let Some(src) = f.source(db) { |
165 | let original_file = src.file_id.original_file(db); | 165 | let original_file = src.file_id.original_file(db); |
166 | let path = vfs.file_path(original_file); | 166 | let path = vfs.file_path(original_file); |
167 | let syntax_range = src.value.syntax().text_range(); | 167 | let syntax_range = src.value.syntax().text_range(); |
168 | format_to!(msg, " ({} {:?})", path, syntax_range); | 168 | format_to!(msg, " ({} {:?})", path, syntax_range); |
169 | } | ||
169 | } | 170 | } |
170 | if verbosity.is_spammy() { | 171 | if verbosity.is_spammy() { |
171 | bar.println(msg.to_string()); | 172 | bar.println(msg.to_string()); |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 1db5b4e7d..685a9fdf0 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -679,7 +679,7 @@ fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json: | |||
679 | for ((f1, ..), (f2, ..)) in fields.iter().zip(&fields[1..]) { | 679 | for ((f1, ..), (f2, ..)) in fields.iter().zip(&fields[1..]) { |
680 | fn key(f: &str) -> &str { | 680 | fn key(f: &str) -> &str { |
681 | f.splitn(2, "_").next().unwrap() | 681 | f.splitn(2, "_").next().unwrap() |
682 | }; | 682 | } |
683 | assert!(key(f1) <= key(f2), "wrong field order: {:?} {:?}", f1, f2); | 683 | assert!(key(f1) <= key(f2), "wrong field order: {:?} {:?}", f1, f2); |
684 | } | 684 | } |
685 | 685 | ||
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 948cfc17c..dd486070b 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -105,6 +105,16 @@ pub(crate) fn handle_syntax_tree( | |||
105 | Ok(res) | 105 | Ok(res) |
106 | } | 106 | } |
107 | 107 | ||
108 | pub(crate) fn handle_view_hir( | ||
109 | snap: GlobalStateSnapshot, | ||
110 | params: lsp_types::TextDocumentPositionParams, | ||
111 | ) -> Result<String> { | ||
112 | let _p = profile::span("handle_view_hir"); | ||
113 | let position = from_proto::file_position(&snap, params)?; | ||
114 | let res = snap.analysis.view_hir(position)?; | ||
115 | Ok(res) | ||
116 | } | ||
117 | |||
108 | pub(crate) fn handle_expand_macro( | 118 | pub(crate) fn handle_expand_macro( |
109 | snap: GlobalStateSnapshot, | 119 | snap: GlobalStateSnapshot, |
110 | params: lsp_ext::ExpandMacroParams, | 120 | params: lsp_ext::ExpandMacroParams, |
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs index 93ac45415..a85978737 100644 --- a/crates/rust-analyzer/src/lsp_ext.rs +++ b/crates/rust-analyzer/src/lsp_ext.rs | |||
@@ -53,6 +53,14 @@ pub struct SyntaxTreeParams { | |||
53 | pub range: Option<Range>, | 53 | pub range: Option<Range>, |
54 | } | 54 | } |
55 | 55 | ||
56 | pub enum ViewHir {} | ||
57 | |||
58 | impl Request for ViewHir { | ||
59 | type Params = lsp_types::TextDocumentPositionParams; | ||
60 | type Result = String; | ||
61 | const METHOD: &'static str = "rust-analyzer/viewHir"; | ||
62 | } | ||
63 | |||
56 | pub enum ExpandMacro {} | 64 | pub enum ExpandMacro {} |
57 | 65 | ||
58 | impl Request for ExpandMacro { | 66 | impl Request for ExpandMacro { |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 5d55dc96e..8eca79f7e 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -443,6 +443,7 @@ impl GlobalState { | |||
443 | .on_sync::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))? | 443 | .on_sync::<lsp_ext::MemoryUsage>(|s, p| handlers::handle_memory_usage(s, p))? |
444 | .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status) | 444 | .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status) |
445 | .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree) | 445 | .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree) |
446 | .on::<lsp_ext::ViewHir>(handlers::handle_view_hir) | ||
446 | .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro) | 447 | .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro) |
447 | .on::<lsp_ext::ParentModule>(handlers::handle_parent_module) | 448 | .on::<lsp_ext::ParentModule>(handlers::handle_parent_module) |
448 | .on::<lsp_ext::Runnables>(handlers::handle_runnables) | 449 | .on::<lsp_ext::Runnables>(handlers::handle_runnables) |
diff --git a/crates/rust-analyzer/src/markdown.rs b/crates/rust-analyzer/src/markdown.rs index 968ea55f0..a49a58c00 100644 --- a/crates/rust-analyzer/src/markdown.rs +++ b/crates/rust-analyzer/src/markdown.rs | |||
@@ -1,8 +1,17 @@ | |||
1 | //! Transforms markdown | 1 | //! Transforms markdown |
2 | 2 | ||
3 | const RUSTDOC_FENCE: &str = "```"; | 3 | const RUSTDOC_FENCE: &str = "```"; |
4 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUST_SPECIFIC: &[&str] = | 4 | const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUST_SPECIFIC: &[&str] = &[ |
5 | &["", "rust", "should_panic", "ignore", "no_run", "compile_fail", "edition2015", "edition2018"]; | 5 | "", |
6 | "rust", | ||
7 | "should_panic", | ||
8 | "ignore", | ||
9 | "no_run", | ||
10 | "compile_fail", | ||
11 | "edition2015", | ||
12 | "edition2018", | ||
13 | "edition2021", | ||
14 | ]; | ||
6 | 15 | ||
7 | pub(crate) fn format_docs(src: &str) -> String { | 16 | pub(crate) fn format_docs(src: &str) -> String { |
8 | let mut processed_lines = Vec::new(); | 17 | let mut processed_lines = Vec::new(); |
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs index c2f6a655d..5c4366f16 100644 --- a/crates/rust-analyzer/src/semantic_tokens.rs +++ b/crates/rust-analyzer/src/semantic_tokens.rs | |||
@@ -44,6 +44,7 @@ define_semantic_token_types![ | |||
44 | (ESCAPE_SEQUENCE, "escapeSequence"), | 44 | (ESCAPE_SEQUENCE, "escapeSequence"), |
45 | (FORMAT_SPECIFIER, "formatSpecifier"), | 45 | (FORMAT_SPECIFIER, "formatSpecifier"), |
46 | (GENERIC, "generic"), | 46 | (GENERIC, "generic"), |
47 | (CONST_PARAMETER, "constParameter"), | ||
47 | (LIFETIME, "lifetime"), | 48 | (LIFETIME, "lifetime"), |
48 | (LABEL, "label"), | 49 | (LABEL, "label"), |
49 | (PUNCTUATION, "punctuation"), | 50 | (PUNCTUATION, "punctuation"), |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 1a38e79f0..999b18351 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -42,6 +42,7 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind { | |||
42 | SymbolKind::Field => lsp_types::SymbolKind::Field, | 42 | SymbolKind::Field => lsp_types::SymbolKind::Field, |
43 | SymbolKind::Static => lsp_types::SymbolKind::Constant, | 43 | SymbolKind::Static => lsp_types::SymbolKind::Constant, |
44 | SymbolKind::Const => lsp_types::SymbolKind::Constant, | 44 | SymbolKind::Const => lsp_types::SymbolKind::Constant, |
45 | SymbolKind::ConstParam => lsp_types::SymbolKind::Constant, | ||
45 | SymbolKind::Impl => lsp_types::SymbolKind::Object, | 46 | SymbolKind::Impl => lsp_types::SymbolKind::Object, |
46 | SymbolKind::Local | 47 | SymbolKind::Local |
47 | | SymbolKind::SelfParam | 48 | | SymbolKind::SelfParam |
@@ -378,6 +379,7 @@ fn semantic_token_type_and_modifiers( | |||
378 | SymbolKind::Impl => lsp_types::SemanticTokenType::TYPE, | 379 | SymbolKind::Impl => lsp_types::SemanticTokenType::TYPE, |
379 | SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY, | 380 | SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY, |
380 | SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER, | 381 | SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER, |
382 | SymbolKind::ConstParam => semantic_tokens::CONST_PARAMETER, | ||
381 | SymbolKind::LifetimeParam => semantic_tokens::LIFETIME, | 383 | SymbolKind::LifetimeParam => semantic_tokens::LIFETIME, |
382 | SymbolKind::Label => semantic_tokens::LABEL, | 384 | SymbolKind::Label => semantic_tokens::LABEL, |
383 | SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER, | 385 | SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER, |
diff --git a/crates/ssr/Cargo.toml b/crates/ssr/Cargo.toml index 339eda86a..cc8136d22 100644 --- a/crates/ssr/Cargo.toml +++ b/crates/ssr/Cargo.toml | |||
@@ -21,4 +21,4 @@ hir = { path = "../hir", version = "0.0.0" } | |||
21 | test_utils = { path = "../test_utils", version = "0.0.0" } | 21 | test_utils = { path = "../test_utils", version = "0.0.0" } |
22 | 22 | ||
23 | [dev-dependencies] | 23 | [dev-dependencies] |
24 | expect-test = "1.0" | 24 | expect-test = "1.1" |
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml index 5d8389ade..181077944 100644 --- a/crates/syntax/Cargo.toml +++ b/crates/syntax/Cargo.toml | |||
@@ -33,4 +33,4 @@ profile = { path = "../profile", version = "0.0.0" } | |||
33 | [dev-dependencies] | 33 | [dev-dependencies] |
34 | walkdir = "2.3.1" | 34 | walkdir = "2.3.1" |
35 | rayon = "1" | 35 | rayon = "1" |
36 | expect-test = "1.0" | 36 | expect-test = "1.1" |
diff --git a/crates/syntax/src/ast/edit.rs b/crates/syntax/src/ast/edit.rs index 77233ab31..824ebf41c 100644 --- a/crates/syntax/src/ast/edit.rs +++ b/crates/syntax/src/ast/edit.rs | |||
@@ -220,7 +220,7 @@ impl ast::RecordExprFieldList { | |||
220 | InsertPosition::After($anchor.syntax().clone().into()) | 220 | InsertPosition::After($anchor.syntax().clone().into()) |
221 | } | 221 | } |
222 | }; | 222 | }; |
223 | }; | 223 | } |
224 | 224 | ||
225 | let position = match position { | 225 | let position = match position { |
226 | InsertPosition::First => after_l_curly!(), | 226 | InsertPosition::First => after_l_curly!(), |
@@ -533,7 +533,7 @@ impl ast::GenericParamList { | |||
533 | InsertPosition::After($anchor.syntax().clone().into()) | 533 | InsertPosition::After($anchor.syntax().clone().into()) |
534 | } | 534 | } |
535 | }; | 535 | }; |
536 | }; | 536 | } |
537 | 537 | ||
538 | let position = match self.generic_params().last() { | 538 | let position = match self.generic_params().last() { |
539 | Some(it) => after_field!(it), | 539 | Some(it) => after_field!(it), |
diff --git a/docs/dev/README.md b/docs/dev/README.md index 4a2f9feb3..55527bab0 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md | |||
@@ -227,6 +227,8 @@ There are also two VS Code commands which might be of interest: | |||
227 | 227 | ||
228 | * `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection. | 228 | * `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection. |
229 | 229 | ||
230 | * `Rust Analyzer: View Hir` shows the HIR expressions within the function containing the cursor. | ||
231 | |||
230 | You can hover over syntax nodes in the opened text file to see the appropriate | 232 | You can hover over syntax nodes in the opened text file to see the appropriate |
231 | rust code that it refers to and the rust editor will also highlight the proper | 233 | rust code that it refers to and the rust editor will also highlight the proper |
232 | text range. | 234 | text range. |
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 8c01db07c..78d86f060 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md | |||
@@ -1,5 +1,5 @@ | |||
1 | <!--- | 1 | <!--- |
2 | lsp_ext.rs hash: 203fdf79b21b5987 | 2 | lsp_ext.rs hash: 91f2c62457e0a20f |
3 | 3 | ||
4 | If you need to change the above hash to make the test pass, please check if you | 4 | If you need to change the above hash to make the test pass, please check if you |
5 | need to adjust this doc as well and ping this issue: | 5 | need to adjust this doc as well and ping this issue: |
@@ -449,6 +449,17 @@ interface SyntaxTeeParams { | |||
449 | Returns textual representation of a parse tree for the file/selected region. | 449 | Returns textual representation of a parse tree for the file/selected region. |
450 | Primarily for debugging, but very useful for all people working on rust-analyzer itself. | 450 | Primarily for debugging, but very useful for all people working on rust-analyzer itself. |
451 | 451 | ||
452 | ## View Hir | ||
453 | |||
454 | **Method:** `rust-analyzer/viewHir` | ||
455 | |||
456 | **Request:** `TextDocumentPositionParams` | ||
457 | |||
458 | **Response:** `string` | ||
459 | |||
460 | Returns a textual representation of the HIR of the function containing the cursor. | ||
461 | For debugging or when working on rust-analyzer itself. | ||
462 | |||
452 | ## Expand Macro | 463 | ## Expand Macro |
453 | 464 | ||
454 | **Method:** `rust-analyzer/expandMacro` | 465 | **Method:** `rust-analyzer/expandMacro` |
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 8ed7b041f..266baffa1 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc | |||
@@ -342,7 +342,7 @@ interface Crate { | |||
342 | /// Path to the root module of the crate. | 342 | /// Path to the root module of the crate. |
343 | root_module: string; | 343 | root_module: string; |
344 | /// Edition of the crate. | 344 | /// Edition of the crate. |
345 | edition: "2015" | "2018"; | 345 | edition: "2015" | "2018" | "2021"; |
346 | /// Dependencies | 346 | /// Dependencies |
347 | deps: Dep[]; | 347 | deps: Dep[]; |
348 | /// Should this crate be treated as a member of current "workspace". | 348 | /// Should this crate be treated as a member of current "workspace". |
diff --git a/editors/code/package.json b/editors/code/package.json index 587f11b90..3e55a3523 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -104,6 +104,11 @@ | |||
104 | "category": "Rust Analyzer" | 104 | "category": "Rust Analyzer" |
105 | }, | 105 | }, |
106 | { | 106 | { |
107 | "command": "rust-analyzer.viewHir", | ||
108 | "title": "View Hir", | ||
109 | "category": "Rust Analyzer" | ||
110 | }, | ||
111 | { | ||
107 | "command": "rust-analyzer.expandMacro", | 112 | "command": "rust-analyzer.expandMacro", |
108 | "title": "Expand macro recursively", | 113 | "title": "Expand macro recursively", |
109 | "category": "Rust Analyzer" | 114 | "category": "Rust Analyzer" |
@@ -1007,6 +1012,10 @@ | |||
1007 | "when": "inRustProject" | 1012 | "when": "inRustProject" |
1008 | }, | 1013 | }, |
1009 | { | 1014 | { |
1015 | "command": "rust-analyzer.viewHir", | ||
1016 | "when": "inRustProject" | ||
1017 | }, | ||
1018 | { | ||
1010 | "command": "rust-analyzer.expandMacro", | 1019 | "command": "rust-analyzer.expandMacro", |
1011 | "when": "inRustProject" | 1020 | "when": "inRustProject" |
1012 | }, | 1021 | }, |
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts index b12e134ca..c1c9f9754 100644 --- a/editors/code/src/commands.ts +++ b/editors/code/src/commands.ts | |||
@@ -340,6 +340,61 @@ export function syntaxTree(ctx: Ctx): Cmd { | |||
340 | }; | 340 | }; |
341 | } | 341 | } |
342 | 342 | ||
343 | // Opens the virtual file that will show the HIR of the function containing the cursor position | ||
344 | // | ||
345 | // The contents of the file come from the `TextDocumentContentProvider` | ||
346 | export function viewHir(ctx: Ctx): Cmd { | ||
347 | const tdcp = new class implements vscode.TextDocumentContentProvider { | ||
348 | readonly uri = vscode.Uri.parse('rust-analyzer://viewHir/hir.txt'); | ||
349 | readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>(); | ||
350 | constructor() { | ||
351 | vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions); | ||
352 | vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions); | ||
353 | } | ||
354 | |||
355 | private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { | ||
356 | if (isRustDocument(event.document)) { | ||
357 | // We need to order this after language server updates, but there's no API for that. | ||
358 | // Hence, good old sleep(). | ||
359 | void sleep(10).then(() => this.eventEmitter.fire(this.uri)); | ||
360 | } | ||
361 | } | ||
362 | private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { | ||
363 | if (editor && isRustEditor(editor)) { | ||
364 | this.eventEmitter.fire(this.uri); | ||
365 | } | ||
366 | } | ||
367 | |||
368 | provideTextDocumentContent(_uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult<string> { | ||
369 | const rustEditor = ctx.activeRustEditor; | ||
370 | const client = ctx.client; | ||
371 | if (!rustEditor || !client) return ''; | ||
372 | |||
373 | const params = { | ||
374 | textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(rustEditor.document), | ||
375 | position: client.code2ProtocolConverter.asPosition( | ||
376 | rustEditor.selection.active, | ||
377 | ), | ||
378 | }; | ||
379 | return client.sendRequest(ra.viewHir, params, ct); | ||
380 | } | ||
381 | |||
382 | get onDidChange(): vscode.Event<vscode.Uri> { | ||
383 | return this.eventEmitter.event; | ||
384 | } | ||
385 | }; | ||
386 | |||
387 | ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp)); | ||
388 | |||
389 | return async () => { | ||
390 | const document = await vscode.workspace.openTextDocument(tdcp.uri); | ||
391 | tdcp.eventEmitter.fire(tdcp.uri); | ||
392 | void await vscode.window.showTextDocument(document, { | ||
393 | viewColumn: vscode.ViewColumn.Two, | ||
394 | preserveFocus: true | ||
395 | }); | ||
396 | }; | ||
397 | } | ||
343 | 398 | ||
344 | // Opens the virtual file that will show the syntax tree | 399 | // Opens the virtual file that will show the syntax tree |
345 | // | 400 | // |
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts index 5e877ce65..d21a3db86 100644 --- a/editors/code/src/lsp_ext.ts +++ b/editors/code/src/lsp_ext.ts | |||
@@ -24,6 +24,7 @@ export interface SyntaxTreeParams { | |||
24 | } | 24 | } |
25 | export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>("rust-analyzer/syntaxTree"); | 25 | export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>("rust-analyzer/syntaxTree"); |
26 | 26 | ||
27 | export const viewHir = new lc.RequestType<lc.TextDocumentPositionParams, string, void>("rust-analyzer/viewHir"); | ||
27 | 28 | ||
28 | export interface ExpandMacroParams { | 29 | export interface ExpandMacroParams { |
29 | textDocument: lc.TextDocumentIdentifier; | 30 | textDocument: lc.TextDocumentIdentifier; |
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 282240d84..60907dfd4 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts | |||
@@ -105,6 +105,7 @@ async function tryActivate(context: vscode.ExtensionContext) { | |||
105 | ctx.registerCommand('joinLines', commands.joinLines); | 105 | ctx.registerCommand('joinLines', commands.joinLines); |
106 | ctx.registerCommand('parentModule', commands.parentModule); | 106 | ctx.registerCommand('parentModule', commands.parentModule); |
107 | ctx.registerCommand('syntaxTree', commands.syntaxTree); | 107 | ctx.registerCommand('syntaxTree', commands.syntaxTree); |
108 | ctx.registerCommand('viewHir', commands.viewHir); | ||
108 | ctx.registerCommand('expandMacro', commands.expandMacro); | 109 | ctx.registerCommand('expandMacro', commands.expandMacro); |
109 | ctx.registerCommand('run', commands.run); | 110 | ctx.registerCommand('run', commands.run); |
110 | ctx.registerCommand('debug', commands.debug); | 111 | ctx.registerCommand('debug', commands.debug); |
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs index d59b88131..6bc34106b 100644 --- a/xtask/src/dist.rs +++ b/xtask/src/dist.rs | |||
@@ -63,8 +63,7 @@ fn dist_server() -> Result<()> { | |||
63 | env::set_var("CC", "clang"); | 63 | env::set_var("CC", "clang"); |
64 | } | 64 | } |
65 | 65 | ||
66 | let toolchain = toolchain(&target); | 66 | cmd!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --release").run()?; |
67 | cmd!("cargo +{toolchain} build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --release").run()?; | ||
68 | 67 | ||
69 | let suffix = exe_suffix(&target); | 68 | let suffix = exe_suffix(&target); |
70 | let src = | 69 | let src = |
@@ -118,13 +117,6 @@ fn exe_suffix(target: &str) -> String { | |||
118 | } | 117 | } |
119 | } | 118 | } |
120 | 119 | ||
121 | fn toolchain(target: &str) -> String { | ||
122 | match target { | ||
123 | "aarch64-apple-darwin" => "beta".to_string(), | ||
124 | _ => "stable".to_string(), | ||
125 | } | ||
126 | } | ||
127 | |||
128 | fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> { | 120 | fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> { |
129 | let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best()); | 121 | let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best()); |
130 | let mut input = io::BufReader::new(File::open(src_path)?); | 122 | let mut input = io::BufReader::new(File::open(src_path)?); |
diff --git a/xtask/tests/tidy.rs b/xtask/tests/tidy.rs index 6bfa922e6..d1ffb70ad 100644 --- a/xtask/tests/tidy.rs +++ b/xtask/tests/tidy.rs | |||
@@ -139,7 +139,7 @@ fn deny_clippy(path: &PathBuf, text: &String) { | |||
139 | return; | 139 | return; |
140 | } | 140 | } |
141 | 141 | ||
142 | if text.contains("[\u{61}llow(clippy") { | 142 | if text.contains("\u{61}llow(clippy") { |
143 | panic!( | 143 | panic!( |
144 | "\n\nallowing lints is forbidden: {}. | 144 | "\n\nallowing lints is forbidden: {}. |
145 | rust-analyzer intentionally doesn't check clippy on CI. | 145 | rust-analyzer intentionally doesn't check clippy on CI. |