diff options
author | Benjamin Coenen <[email protected]> | 2020-04-11 21:54:22 +0100 |
---|---|---|
committer | Benjamin Coenen <[email protected]> | 2020-04-11 22:45:09 +0100 |
commit | 93bfc2d05d36a47dc05a1799210327473d702dbc (patch) | |
tree | dee25e78b24b5d1b23d73ae1009bddbd060927cf /crates | |
parent | d42346fed61f706d68fe888631a41ea5f2752d7f (diff) | |
parent | fd06fe7b13045185ab4e630b0044aa9d8bbcdf8a (diff) |
Improve autocompletion by looking on the type and name
Signed-off-by: Benjamin Coenen <[email protected]>
Diffstat (limited to 'crates')
280 files changed, 3500 insertions, 4971 deletions
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index 64444ee3a..b63b4d81a 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs | |||
@@ -180,7 +180,7 @@ trait Trait<T> { | |||
180 | } | 180 | } |
181 | 181 | ||
182 | impl Trait<u32> for () { | 182 | impl Trait<u32> for () { |
183 | fn foo(&self) -> u32 { unimplemented!() } | 183 | fn foo(&self) -> u32 { todo!() } |
184 | 184 | ||
185 | } | 185 | } |
186 | "#####, | 186 | "#####, |
@@ -607,6 +607,21 @@ impl Walrus { | |||
607 | } | 607 | } |
608 | 608 | ||
609 | #[test] | 609 | #[test] |
610 | fn doctest_reorder_fields() { | ||
611 | check( | ||
612 | "reorder_fields", | ||
613 | r#####" | ||
614 | struct Foo {foo: i32, bar: i32}; | ||
615 | const test: Foo = <|>Foo {bar: 0, foo: 1} | ||
616 | "#####, | ||
617 | r#####" | ||
618 | struct Foo {foo: i32, bar: i32}; | ||
619 | const test: Foo = Foo {foo: 1, bar: 0} | ||
620 | "#####, | ||
621 | ) | ||
622 | } | ||
623 | |||
624 | #[test] | ||
610 | fn doctest_replace_if_let_with_match() { | 625 | fn doctest_replace_if_let_with_match() { |
611 | check( | 626 | check( |
612 | "replace_if_let_with_match", | 627 | "replace_if_let_with_match", |
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs index 72a201b6d..6622eadb2 100644 --- a/crates/ra_assists/src/handlers/add_impl.rs +++ b/crates/ra_assists/src/handlers/add_impl.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::{ |
2 | ast::{self, AstNode, AstToken, NameOwner, TypeParamsOwner}, | 2 | ast::{self, AstNode, NameOwner, TypeParamsOwner}, |
3 | TextUnit, | 3 | TextUnit, |
4 | }; | 4 | }; |
5 | use stdx::{format_to, SepBy}; | 5 | use stdx::{format_to, SepBy}; |
@@ -42,7 +42,7 @@ pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> { | |||
42 | if let Some(type_params) = type_params { | 42 | if let Some(type_params) = type_params { |
43 | let lifetime_params = type_params | 43 | let lifetime_params = type_params |
44 | .lifetime_params() | 44 | .lifetime_params() |
45 | .filter_map(|it| it.lifetime()) | 45 | .filter_map(|it| it.lifetime_token()) |
46 | .map(|it| it.text().clone()); | 46 | .map(|it| it.text().clone()); |
47 | let type_params = | 47 | let type_params = |
48 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); | 48 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); |
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs index 722f207e2..2d6d44980 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs | |||
@@ -40,7 +40,7 @@ enum AddMissingImplMembersMode { | |||
40 | // } | 40 | // } |
41 | // | 41 | // |
42 | // impl Trait<u32> for () { | 42 | // impl Trait<u32> for () { |
43 | // fn foo(&self) -> u32 { unimplemented!() } | 43 | // fn foo(&self) -> u32 { todo!() } |
44 | // | 44 | // |
45 | // } | 45 | // } |
46 | // ``` | 46 | // ``` |
@@ -165,7 +165,7 @@ fn add_missing_impl_members_inner( | |||
165 | 165 | ||
166 | fn add_body(fn_def: ast::FnDef) -> ast::FnDef { | 166 | fn add_body(fn_def: ast::FnDef) -> ast::FnDef { |
167 | if fn_def.body().is_none() { | 167 | if fn_def.body().is_none() { |
168 | fn_def.with_body(make::block_from_expr(make::expr_unimplemented())) | 168 | fn_def.with_body(make::block_from_expr(make::expr_todo())) |
169 | } else { | 169 | } else { |
170 | fn_def | 170 | fn_def |
171 | } | 171 | } |
@@ -215,8 +215,8 @@ impl Foo for S { | |||
215 | fn bar(&self) {} | 215 | fn bar(&self) {} |
216 | <|>type Output; | 216 | <|>type Output; |
217 | const CONST: usize = 42; | 217 | const CONST: usize = 42; |
218 | fn foo(&self) { unimplemented!() } | 218 | fn foo(&self) { todo!() } |
219 | fn baz(&self) { unimplemented!() } | 219 | fn baz(&self) { todo!() } |
220 | 220 | ||
221 | }", | 221 | }", |
222 | ); | 222 | ); |
@@ -250,7 +250,7 @@ struct S; | |||
250 | 250 | ||
251 | impl Foo for S { | 251 | impl Foo for S { |
252 | fn bar(&self) {} | 252 | fn bar(&self) {} |
253 | <|>fn foo(&self) { unimplemented!() } | 253 | <|>fn foo(&self) { todo!() } |
254 | 254 | ||
255 | }", | 255 | }", |
256 | ); | 256 | ); |
@@ -268,7 +268,7 @@ impl Foo for S { <|> }", | |||
268 | trait Foo { fn foo(&self); } | 268 | trait Foo { fn foo(&self); } |
269 | struct S; | 269 | struct S; |
270 | impl Foo for S { | 270 | impl Foo for S { |
271 | <|>fn foo(&self) { unimplemented!() } | 271 | <|>fn foo(&self) { todo!() } |
272 | }", | 272 | }", |
273 | ); | 273 | ); |
274 | } | 274 | } |
@@ -285,7 +285,7 @@ impl Foo<u32> for S { <|> }", | |||
285 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 285 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
286 | struct S; | 286 | struct S; |
287 | impl Foo<u32> for S { | 287 | impl Foo<u32> for S { |
288 | <|>fn foo(&self, t: u32) -> &u32 { unimplemented!() } | 288 | <|>fn foo(&self, t: u32) -> &u32 { todo!() } |
289 | }", | 289 | }", |
290 | ); | 290 | ); |
291 | } | 291 | } |
@@ -302,7 +302,7 @@ impl<U> Foo<U> for S { <|> }", | |||
302 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 302 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
303 | struct S; | 303 | struct S; |
304 | impl<U> Foo<U> for S { | 304 | impl<U> Foo<U> for S { |
305 | <|>fn foo(&self, t: U) -> &U { unimplemented!() } | 305 | <|>fn foo(&self, t: U) -> &U { todo!() } |
306 | }", | 306 | }", |
307 | ); | 307 | ); |
308 | } | 308 | } |
@@ -319,7 +319,7 @@ impl Foo for S {}<|>", | |||
319 | trait Foo { fn foo(&self); } | 319 | trait Foo { fn foo(&self); } |
320 | struct S; | 320 | struct S; |
321 | impl Foo for S { | 321 | impl Foo for S { |
322 | <|>fn foo(&self) { unimplemented!() } | 322 | <|>fn foo(&self) { todo!() } |
323 | }", | 323 | }", |
324 | ) | 324 | ) |
325 | } | 325 | } |
@@ -342,7 +342,7 @@ mod foo { | |||
342 | } | 342 | } |
343 | struct S; | 343 | struct S; |
344 | impl foo::Foo for S { | 344 | impl foo::Foo for S { |
345 | <|>fn foo(&self, bar: foo::Bar) { unimplemented!() } | 345 | <|>fn foo(&self, bar: foo::Bar) { todo!() } |
346 | }", | 346 | }", |
347 | ); | 347 | ); |
348 | } | 348 | } |
@@ -365,7 +365,7 @@ mod foo { | |||
365 | } | 365 | } |
366 | struct S; | 366 | struct S; |
367 | impl foo::Foo for S { | 367 | impl foo::Foo for S { |
368 | <|>fn foo(&self, bar: foo::Bar<u32>) { unimplemented!() } | 368 | <|>fn foo(&self, bar: foo::Bar<u32>) { todo!() } |
369 | }", | 369 | }", |
370 | ); | 370 | ); |
371 | } | 371 | } |
@@ -388,7 +388,7 @@ mod foo { | |||
388 | } | 388 | } |
389 | struct S; | 389 | struct S; |
390 | impl foo::Foo<u32> for S { | 390 | impl foo::Foo<u32> for S { |
391 | <|>fn foo(&self, bar: foo::Bar<u32>) { unimplemented!() } | 391 | <|>fn foo(&self, bar: foo::Bar<u32>) { todo!() } |
392 | }", | 392 | }", |
393 | ); | 393 | ); |
394 | } | 394 | } |
@@ -414,7 +414,7 @@ mod foo { | |||
414 | struct Param; | 414 | struct Param; |
415 | struct S; | 415 | struct S; |
416 | impl foo::Foo<Param> for S { | 416 | impl foo::Foo<Param> for S { |
417 | <|>fn foo(&self, bar: Param) { unimplemented!() } | 417 | <|>fn foo(&self, bar: Param) { todo!() } |
418 | }", | 418 | }", |
419 | ); | 419 | ); |
420 | } | 420 | } |
@@ -439,7 +439,7 @@ mod foo { | |||
439 | } | 439 | } |
440 | struct S; | 440 | struct S; |
441 | impl foo::Foo for S { | 441 | impl foo::Foo for S { |
442 | <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { unimplemented!() } | 442 | <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { todo!() } |
443 | }", | 443 | }", |
444 | ); | 444 | ); |
445 | } | 445 | } |
@@ -464,7 +464,7 @@ mod foo { | |||
464 | } | 464 | } |
465 | struct S; | 465 | struct S; |
466 | impl foo::Foo for S { | 466 | impl foo::Foo for S { |
467 | <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { unimplemented!() } | 467 | <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { todo!() } |
468 | }", | 468 | }", |
469 | ); | 469 | ); |
470 | } | 470 | } |
@@ -487,7 +487,7 @@ mod foo { | |||
487 | } | 487 | } |
488 | struct S; | 488 | struct S; |
489 | impl foo::Foo for S { | 489 | impl foo::Foo for S { |
490 | <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { unimplemented!() } | 490 | <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { todo!() } |
491 | }", | 491 | }", |
492 | ); | 492 | ); |
493 | } | 493 | } |
@@ -544,7 +544,7 @@ trait Foo { | |||
544 | struct S; | 544 | struct S; |
545 | impl Foo for S { | 545 | impl Foo for S { |
546 | <|>type Output; | 546 | <|>type Output; |
547 | fn foo(&self) { unimplemented!() } | 547 | fn foo(&self) { todo!() } |
548 | }"#, | 548 | }"#, |
549 | ) | 549 | ) |
550 | } | 550 | } |
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs index c10397249..240b19fa3 100644 --- a/crates/ra_assists/src/handlers/add_new.rs +++ b/crates/ra_assists/src/handlers/add_new.rs | |||
@@ -1,8 +1,7 @@ | |||
1 | use hir::Adt; | 1 | use hir::Adt; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | ast::{ | 3 | ast::{ |
4 | self, AstNode, AstToken, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, | 4 | self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner, |
5 | VisibilityOwner, | ||
6 | }, | 5 | }, |
7 | TextUnit, T, | 6 | TextUnit, T, |
8 | }; | 7 | }; |
@@ -106,7 +105,7 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String { | |||
106 | if let Some(type_params) = type_params { | 105 | if let Some(type_params) = type_params { |
107 | let lifetime_params = type_params | 106 | let lifetime_params = type_params |
108 | .lifetime_params() | 107 | .lifetime_params() |
109 | .filter_map(|it| it.lifetime()) | 108 | .filter_map(|it| it.lifetime_token()) |
110 | .map(|it| it.text().clone()); | 109 | .map(|it| it.text().clone()); |
111 | let type_params = | 110 | let type_params = |
112 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); | 111 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); |
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs index 3bfcba8ff..c4fb425b0 100644 --- a/crates/ra_assists/src/handlers/inline_local_variable.rs +++ b/crates/ra_assists/src/handlers/inline_local_variable.rs | |||
@@ -29,7 +29,7 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> { | |||
29 | ast::Pat::BindPat(pat) => pat, | 29 | ast::Pat::BindPat(pat) => pat, |
30 | _ => return None, | 30 | _ => return None, |
31 | }; | 31 | }; |
32 | if bind_pat.is_mutable() { | 32 | if bind_pat.mut_token().is_some() { |
33 | tested_by!(test_not_inline_mut_variable); | 33 | tested_by!(test_not_inline_mut_variable); |
34 | return None; | 34 | return None; |
35 | } | 35 | } |
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs index 8a02f1a32..8d0f7e922 100644 --- a/crates/ra_assists/src/handlers/introduce_variable.rs +++ b/crates/ra_assists/src/handlers/introduce_variable.rs | |||
@@ -61,7 +61,7 @@ pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> { | |||
61 | }; | 61 | }; |
62 | if is_full_stmt { | 62 | if is_full_stmt { |
63 | tested_by!(test_introduce_var_expr_stmt); | 63 | tested_by!(test_introduce_var_expr_stmt); |
64 | if !full_stmt.unwrap().has_semi() { | 64 | if full_stmt.unwrap().semicolon_token().is_none() { |
65 | buf.push_str(";"); | 65 | buf.push_str(";"); |
66 | } | 66 | } |
67 | edit.replace(expr.syntax().text_range(), buf); | 67 | edit.replace(expr.syntax().text_range(), buf); |
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs index f8b3ddb4e..0958f52f1 100644 --- a/crates/ra_assists/src/handlers/merge_imports.rs +++ b/crates/ra_assists/src/handlers/merge_imports.rs | |||
@@ -3,7 +3,7 @@ use std::iter::successors; | |||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | algo::{neighbor, SyntaxRewriter}, | 4 | algo::{neighbor, SyntaxRewriter}, |
5 | ast::{self, edit::AstNodeEdit, make}, | 5 | ast::{self, edit::AstNodeEdit, make}, |
6 | AstNode, AstToken, Direction, InsertPosition, SyntaxElement, T, | 6 | AstNode, Direction, InsertPosition, SyntaxElement, T, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | use crate::{Assist, AssistCtx, AssistId}; | 9 | use crate::{Assist, AssistCtx, AssistId}; |
@@ -82,7 +82,7 @@ fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option<ast::UseTre | |||
82 | .filter(|it| it.kind() != T!['{'] && it.kind() != T!['}']), | 82 | .filter(|it| it.kind() != T!['{'] && it.kind() != T!['}']), |
83 | ); | 83 | ); |
84 | let use_tree_list = lhs.use_tree_list()?; | 84 | let use_tree_list = lhs.use_tree_list()?; |
85 | let pos = InsertPosition::Before(use_tree_list.r_curly()?.syntax().clone().into()); | 85 | let pos = InsertPosition::Before(use_tree_list.r_curly_token()?.into()); |
86 | let use_tree_list = use_tree_list.insert_children(pos, to_insert); | 86 | let use_tree_list = use_tree_list.insert_children(pos, to_insert); |
87 | Some(lhs.with_use_tree_list(use_tree_list)) | 87 | Some(lhs.with_use_tree_list(use_tree_list)) |
88 | } | 88 | } |
diff --git a/crates/ra_assists/src/handlers/move_bounds.rs b/crates/ra_assists/src/handlers/move_bounds.rs index 93f26f51a..0f26884dc 100644 --- a/crates/ra_assists/src/handlers/move_bounds.rs +++ b/crates/ra_assists/src/handlers/move_bounds.rs | |||
@@ -2,6 +2,7 @@ use ra_syntax::{ | |||
2 | ast::{self, edit::AstNodeEdit, make, AstNode, NameOwner, TypeBoundsOwner}, | 2 | ast::{self, edit::AstNodeEdit, make, AstNode, NameOwner, TypeBoundsOwner}, |
3 | match_ast, | 3 | match_ast, |
4 | SyntaxKind::*, | 4 | SyntaxKind::*, |
5 | T, | ||
5 | }; | 6 | }; |
6 | 7 | ||
7 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{Assist, AssistCtx, AssistId}; |
@@ -42,7 +43,7 @@ pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx) -> Option<Assist> { | |||
42 | ast::EnumDef(it) => it.variant_list()?.syntax().clone().into(), | 43 | ast::EnumDef(it) => it.variant_list()?.syntax().clone().into(), |
43 | ast::StructDef(it) => { | 44 | ast::StructDef(it) => { |
44 | it.syntax().children_with_tokens() | 45 | it.syntax().children_with_tokens() |
45 | .find(|it| it.kind() == RECORD_FIELD_DEF_LIST || it.kind() == SEMI)? | 46 | .find(|it| it.kind() == RECORD_FIELD_DEF_LIST || it.kind() == T![;])? |
46 | }, | 47 | }, |
47 | _ => return None | 48 | _ => return None |
48 | } | 49 | } |
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs new file mode 100644 index 000000000..692dd1315 --- /dev/null +++ b/crates/ra_assists/src/handlers/reorder_fields.rs | |||
@@ -0,0 +1,230 @@ | |||
1 | use std::collections::HashMap; | ||
2 | |||
3 | use itertools::Itertools; | ||
4 | |||
5 | use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct}; | ||
6 | use ra_ide_db::RootDatabase; | ||
7 | use ra_syntax::{ | ||
8 | algo, ast, | ||
9 | ast::{Name, Path, RecordLit, RecordPat}, | ||
10 | AstNode, SyntaxKind, SyntaxNode, | ||
11 | }; | ||
12 | |||
13 | use crate::{ | ||
14 | assist_ctx::{Assist, AssistCtx}, | ||
15 | AssistId, | ||
16 | }; | ||
17 | use ra_syntax::ast::{Expr, NameRef}; | ||
18 | |||
19 | // Assist: reorder_fields | ||
20 | // | ||
21 | // Reorder the fields of record literals and record patterns in the same order as in | ||
22 | // the definition. | ||
23 | // | ||
24 | // ``` | ||
25 | // struct Foo {foo: i32, bar: i32}; | ||
26 | // const test: Foo = <|>Foo {bar: 0, foo: 1} | ||
27 | // ``` | ||
28 | // -> | ||
29 | // ``` | ||
30 | // struct Foo {foo: i32, bar: i32}; | ||
31 | // const test: Foo = Foo {foo: 1, bar: 0} | ||
32 | // ``` | ||
33 | // | ||
34 | pub(crate) fn reorder_fields(ctx: AssistCtx) -> Option<Assist> { | ||
35 | reorder::<RecordLit>(ctx.clone()).or_else(|| reorder::<RecordPat>(ctx)) | ||
36 | } | ||
37 | |||
38 | fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> { | ||
39 | let record = ctx.find_node_at_offset::<R>()?; | ||
40 | let path = record.syntax().children().find_map(Path::cast)?; | ||
41 | |||
42 | let ranks = compute_fields_ranks(&path, &ctx)?; | ||
43 | |||
44 | let fields = get_fields(&record.syntax()); | ||
45 | let sorted_fields = sorted_by_rank(&fields, |node| { | ||
46 | *ranks.get(&get_field_name(node)).unwrap_or(&usize::max_value()) | ||
47 | }); | ||
48 | |||
49 | if sorted_fields == fields { | ||
50 | return None; | ||
51 | } | ||
52 | |||
53 | ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", |edit| { | ||
54 | for (old, new) in fields.iter().zip(&sorted_fields) { | ||
55 | algo::diff(old, new).into_text_edit(edit.text_edit_builder()); | ||
56 | } | ||
57 | edit.target(record.syntax().text_range()) | ||
58 | }) | ||
59 | } | ||
60 | |||
61 | fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> { | ||
62 | use SyntaxKind::*; | ||
63 | match node.kind() { | ||
64 | RECORD_LIT => vec![RECORD_FIELD], | ||
65 | RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT], | ||
66 | _ => vec![], | ||
67 | } | ||
68 | } | ||
69 | |||
70 | fn get_field_name(node: &SyntaxNode) -> String { | ||
71 | use SyntaxKind::*; | ||
72 | match node.kind() { | ||
73 | RECORD_FIELD => { | ||
74 | if let Some(name) = node.children().find_map(NameRef::cast) { | ||
75 | return name.to_string(); | ||
76 | } | ||
77 | node.children().find_map(Expr::cast).map(|expr| expr.to_string()).unwrap_or_default() | ||
78 | } | ||
79 | BIND_PAT | RECORD_FIELD_PAT => { | ||
80 | node.children().find_map(Name::cast).map(|n| n.to_string()).unwrap_or_default() | ||
81 | } | ||
82 | _ => String::new(), | ||
83 | } | ||
84 | } | ||
85 | |||
86 | fn get_fields(record: &SyntaxNode) -> Vec<SyntaxNode> { | ||
87 | let kinds = get_fields_kind(record); | ||
88 | record.children().flat_map(|n| n.children()).filter(|n| kinds.contains(&n.kind())).collect() | ||
89 | } | ||
90 | |||
91 | fn sorted_by_rank( | ||
92 | fields: &[SyntaxNode], | ||
93 | get_rank: impl Fn(&SyntaxNode) -> usize, | ||
94 | ) -> Vec<SyntaxNode> { | ||
95 | fields.iter().cloned().sorted_by_key(get_rank).collect() | ||
96 | } | ||
97 | |||
98 | fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<Struct> { | ||
99 | match sema.resolve_path(path) { | ||
100 | Some(PathResolution::Def(ModuleDef::Adt(Adt::Struct(s)))) => Some(s), | ||
101 | _ => None, | ||
102 | } | ||
103 | } | ||
104 | |||
105 | fn compute_fields_ranks(path: &Path, ctx: &AssistCtx) -> Option<HashMap<String, usize>> { | ||
106 | Some( | ||
107 | struct_definition(path, ctx.sema)? | ||
108 | .fields(ctx.db) | ||
109 | .iter() | ||
110 | .enumerate() | ||
111 | .map(|(idx, field)| (field.name(ctx.db).to_string(), idx)) | ||
112 | .collect(), | ||
113 | ) | ||
114 | } | ||
115 | |||
116 | #[cfg(test)] | ||
117 | mod tests { | ||
118 | use crate::helpers::{check_assist, check_assist_not_applicable}; | ||
119 | |||
120 | use super::*; | ||
121 | |||
122 | #[test] | ||
123 | fn not_applicable_if_sorted() { | ||
124 | check_assist_not_applicable( | ||
125 | reorder_fields, | ||
126 | r#" | ||
127 | struct Foo { | ||
128 | foo: i32, | ||
129 | bar: i32, | ||
130 | } | ||
131 | |||
132 | const test: Foo = <|>Foo { foo: 0, bar: 0 }; | ||
133 | "#, | ||
134 | ) | ||
135 | } | ||
136 | |||
137 | #[test] | ||
138 | fn trivial_empty_fields() { | ||
139 | check_assist_not_applicable( | ||
140 | reorder_fields, | ||
141 | r#" | ||
142 | struct Foo {}; | ||
143 | const test: Foo = <|>Foo {} | ||
144 | "#, | ||
145 | ) | ||
146 | } | ||
147 | |||
148 | #[test] | ||
149 | fn reorder_struct_fields() { | ||
150 | check_assist( | ||
151 | reorder_fields, | ||
152 | r#" | ||
153 | struct Foo {foo: i32, bar: i32}; | ||
154 | const test: Foo = <|>Foo {bar: 0, foo: 1} | ||
155 | "#, | ||
156 | r#" | ||
157 | struct Foo {foo: i32, bar: i32}; | ||
158 | const test: Foo = <|>Foo {foo: 1, bar: 0} | ||
159 | "#, | ||
160 | ) | ||
161 | } | ||
162 | |||
163 | #[test] | ||
164 | fn reorder_struct_pattern() { | ||
165 | check_assist( | ||
166 | reorder_fields, | ||
167 | r#" | ||
168 | struct Foo { foo: i64, bar: i64, baz: i64 } | ||
169 | |||
170 | fn f(f: Foo) -> { | ||
171 | match f { | ||
172 | <|>Foo { baz: 0, ref mut bar, .. } => (), | ||
173 | _ => () | ||
174 | } | ||
175 | } | ||
176 | "#, | ||
177 | r#" | ||
178 | struct Foo { foo: i64, bar: i64, baz: i64 } | ||
179 | |||
180 | fn f(f: Foo) -> { | ||
181 | match f { | ||
182 | <|>Foo { ref mut bar, baz: 0, .. } => (), | ||
183 | _ => () | ||
184 | } | ||
185 | } | ||
186 | "#, | ||
187 | ) | ||
188 | } | ||
189 | |||
190 | #[test] | ||
191 | fn reorder_with_extra_field() { | ||
192 | check_assist( | ||
193 | reorder_fields, | ||
194 | r#" | ||
195 | struct Foo { | ||
196 | foo: String, | ||
197 | bar: String, | ||
198 | } | ||
199 | |||
200 | impl Foo { | ||
201 | fn new() -> Foo { | ||
202 | let foo = String::new(); | ||
203 | <|>Foo { | ||
204 | bar: foo.clone(), | ||
205 | extra: "Extra field", | ||
206 | foo, | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | "#, | ||
211 | r#" | ||
212 | struct Foo { | ||
213 | foo: String, | ||
214 | bar: String, | ||
215 | } | ||
216 | |||
217 | impl Foo { | ||
218 | fn new() -> Foo { | ||
219 | let foo = String::new(); | ||
220 | <|>Foo { | ||
221 | foo, | ||
222 | bar: foo.clone(), | ||
223 | extra: "Extra field", | ||
224 | } | ||
225 | } | ||
226 | } | ||
227 | "#, | ||
228 | ) | ||
229 | } | ||
230 | } | ||
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 5ba5254fd..a00136da1 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -129,6 +129,7 @@ mod handlers { | |||
129 | mod replace_unwrap_with_match; | 129 | mod replace_unwrap_with_match; |
130 | mod split_import; | 130 | mod split_import; |
131 | mod add_from_impl_for_enum; | 131 | mod add_from_impl_for_enum; |
132 | mod reorder_fields; | ||
132 | 133 | ||
133 | pub(crate) fn all() -> &'static [AssistHandler] { | 134 | pub(crate) fn all() -> &'static [AssistHandler] { |
134 | &[ | 135 | &[ |
@@ -170,6 +171,7 @@ mod handlers { | |||
170 | // These are manually sorted for better priorities | 171 | // These are manually sorted for better priorities |
171 | add_missing_impl_members::add_missing_impl_members, | 172 | add_missing_impl_members::add_missing_impl_members, |
172 | add_missing_impl_members::add_missing_default_members, | 173 | add_missing_impl_members::add_missing_default_members, |
174 | reorder_fields::reorder_fields, | ||
173 | ] | 175 | ] |
174 | } | 176 | } |
175 | } | 177 | } |
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 45631f8fd..58ae6ce41 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -139,7 +139,7 @@ impl SourceAnalyzer { | |||
139 | &self, | 139 | &self, |
140 | db: &dyn HirDatabase, | 140 | db: &dyn HirDatabase, |
141 | field: &ast::FieldExpr, | 141 | field: &ast::FieldExpr, |
142 | ) -> Option<crate::StructField> { | 142 | ) -> Option<StructField> { |
143 | let expr_id = self.expr_id(db, &field.clone().into())?; | 143 | let expr_id = self.expr_id(db, &field.clone().into())?; |
144 | self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into()) | 144 | self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into()) |
145 | } | 145 | } |
@@ -148,21 +148,19 @@ impl SourceAnalyzer { | |||
148 | &self, | 148 | &self, |
149 | db: &dyn HirDatabase, | 149 | db: &dyn HirDatabase, |
150 | field: &ast::RecordField, | 150 | field: &ast::RecordField, |
151 | ) -> Option<(crate::StructField, Option<Local>)> { | 151 | ) -> Option<(StructField, Option<Local>)> { |
152 | let (expr_id, local) = match field.expr() { | 152 | let expr = field.expr()?; |
153 | Some(it) => (self.expr_id(db, &it)?, None), | 153 | let expr_id = self.expr_id(db, &expr)?; |
154 | None => { | 154 | let local = if field.name_ref().is_some() { |
155 | let src = InFile { file_id: self.file_id, value: field }; | 155 | None |
156 | let expr_id = self.body_source_map.as_ref()?.field_init_shorthand_expr(src)?; | 156 | } else { |
157 | let local_name = field.name_ref()?.as_name(); | 157 | let local_name = field.field_name()?.as_name(); |
158 | let path = ModPath::from_segments(PathKind::Plain, once(local_name)); | 158 | let path = ModPath::from_segments(PathKind::Plain, once(local_name)); |
159 | let local = match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { | 159 | match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { |
160 | Some(ValueNs::LocalBinding(pat_id)) => { | 160 | Some(ValueNs::LocalBinding(pat_id)) => { |
161 | Some(Local { pat_id, parent: self.resolver.body_owner()? }) | 161 | Some(Local { pat_id, parent: self.resolver.body_owner()? }) |
162 | } | 162 | } |
163 | _ => None, | 163 | _ => None, |
164 | }; | ||
165 | (expr_id, local) | ||
166 | } | 164 | } |
167 | }; | 165 | }; |
168 | let struct_field = self.infer.as_ref()?.record_field_resolution(expr_id)?; | 166 | let struct_field = self.infer.as_ref()?.record_field_resolution(expr_id)?; |
@@ -255,7 +253,7 @@ impl SourceAnalyzer { | |||
255 | _ => return None, | 253 | _ => return None, |
256 | }; | 254 | }; |
257 | 255 | ||
258 | let (variant, missing_fields) = | 256 | let (variant, missing_fields, _exhaustive) = |
259 | record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?; | 257 | record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?; |
260 | let res = self.missing_fields(db, krate, substs, variant, missing_fields); | 258 | let res = self.missing_fields(db, krate, substs, variant, missing_fields); |
261 | Some(res) | 259 | Some(res) |
@@ -319,8 +317,7 @@ fn scope_for_offset( | |||
319 | if source.file_id != offset.file_id { | 317 | if source.file_id != offset.file_id { |
320 | return None; | 318 | return None; |
321 | } | 319 | } |
322 | let syntax_node_ptr = | 320 | let syntax_node_ptr = source.value.syntax_node_ptr(); |
323 | source.value.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); | ||
324 | Some((syntax_node_ptr, scope)) | 321 | Some((syntax_node_ptr, scope)) |
325 | }) | 322 | }) |
326 | // find containing scope | 323 | // find containing scope |
@@ -399,8 +396,7 @@ fn adjust( | |||
399 | if source.file_id != file_id { | 396 | if source.file_id != file_id { |
400 | return None; | 397 | return None; |
401 | } | 398 | } |
402 | let syntax_node_ptr = | 399 | let syntax_node_ptr = source.value.syntax_node_ptr(); |
403 | source.value.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); | ||
404 | Some((syntax_node_ptr, scope)) | 400 | Some((syntax_node_ptr, scope)) |
405 | }) | 401 | }) |
406 | .map(|(ptr, scope)| (ptr.range(), scope)) | 402 | .map(|(ptr, scope)| (ptr.range(), scope)) |
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs index be4b0accb..7c0d93691 100644 --- a/crates/ra_hir_def/src/adt.rs +++ b/crates/ra_hir_def/src/adt.rs | |||
@@ -4,7 +4,6 @@ use std::sync::Arc; | |||
4 | 4 | ||
5 | use either::Either; | 5 | use either::Either; |
6 | use hir_expand::{ | 6 | use hir_expand::{ |
7 | hygiene::Hygiene, | ||
8 | name::{AsName, Name}, | 7 | name::{AsName, Name}, |
9 | InFile, | 8 | InFile, |
10 | }; | 9 | }; |
@@ -13,7 +12,7 @@ use ra_prof::profile; | |||
13 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; | 12 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; |
14 | 13 | ||
15 | use crate::{ | 14 | use crate::{ |
16 | attr::Attrs, db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, | 15 | body::CfgExpander, db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, |
17 | type_ref::TypeRef, visibility::RawVisibility, EnumId, HasModule, LocalEnumVariantId, | 16 | type_ref::TypeRef, visibility::RawVisibility, EnumId, HasModule, LocalEnumVariantId, |
18 | LocalStructFieldId, Lookup, ModuleId, StructId, UnionId, VariantId, | 17 | LocalStructFieldId, Lookup, ModuleId, StructId, UnionId, VariantId, |
19 | }; | 18 | }; |
@@ -125,8 +124,9 @@ fn lower_enum( | |||
125 | 124 | ||
126 | impl VariantData { | 125 | impl VariantData { |
127 | fn new(db: &dyn DefDatabase, flavor: InFile<ast::StructKind>, module_id: ModuleId) -> Self { | 126 | fn new(db: &dyn DefDatabase, flavor: InFile<ast::StructKind>, module_id: ModuleId) -> Self { |
127 | let mut expander = CfgExpander::new(db, flavor.file_id, module_id.krate); | ||
128 | let mut trace = Trace::new_for_arena(); | 128 | let mut trace = Trace::new_for_arena(); |
129 | match lower_struct(db, &mut trace, &flavor, module_id) { | 129 | match lower_struct(db, &mut expander, &mut trace, &flavor) { |
130 | StructKind::Tuple => VariantData::Tuple(trace.into_arena()), | 130 | StructKind::Tuple => VariantData::Tuple(trace.into_arena()), |
131 | StructKind::Record => VariantData::Record(trace.into_arena()), | 131 | StructKind::Record => VariantData::Record(trace.into_arena()), |
132 | StructKind::Unit => VariantData::Unit, | 132 | StructKind::Unit => VariantData::Unit, |
@@ -178,8 +178,9 @@ impl HasChildSource for VariantId { | |||
178 | it.lookup(db).container.module(db), | 178 | it.lookup(db).container.module(db), |
179 | ), | 179 | ), |
180 | }; | 180 | }; |
181 | let mut expander = CfgExpander::new(db, src.file_id, module_id.krate); | ||
181 | let mut trace = Trace::new_for_map(); | 182 | let mut trace = Trace::new_for_map(); |
182 | lower_struct(db, &mut trace, &src, module_id); | 183 | lower_struct(db, &mut expander, &mut trace, &src); |
183 | src.with_value(trace.into_map()) | 184 | src.with_value(trace.into_map()) |
184 | } | 185 | } |
185 | } | 186 | } |
@@ -193,16 +194,15 @@ pub enum StructKind { | |||
193 | 194 | ||
194 | fn lower_struct( | 195 | fn lower_struct( |
195 | db: &dyn DefDatabase, | 196 | db: &dyn DefDatabase, |
197 | expander: &mut CfgExpander, | ||
196 | trace: &mut Trace<StructFieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>, | 198 | trace: &mut Trace<StructFieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>, |
197 | ast: &InFile<ast::StructKind>, | 199 | ast: &InFile<ast::StructKind>, |
198 | module_id: ModuleId, | ||
199 | ) -> StructKind { | 200 | ) -> StructKind { |
200 | let crate_graph = db.crate_graph(); | ||
201 | match &ast.value { | 201 | match &ast.value { |
202 | ast::StructKind::Tuple(fl) => { | 202 | ast::StructKind::Tuple(fl) => { |
203 | for (i, fd) in fl.fields().enumerate() { | 203 | for (i, fd) in fl.fields().enumerate() { |
204 | let attrs = Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id)); | 204 | let attrs = expander.parse_attrs(&fd); |
205 | if !attrs.is_cfg_enabled(&crate_graph[module_id.krate].cfg_options) { | 205 | if !expander.is_cfg_enabled(&attrs) { |
206 | continue; | 206 | continue; |
207 | } | 207 | } |
208 | 208 | ||
@@ -219,8 +219,8 @@ fn lower_struct( | |||
219 | } | 219 | } |
220 | ast::StructKind::Record(fl) => { | 220 | ast::StructKind::Record(fl) => { |
221 | for fd in fl.fields() { | 221 | for fd in fl.fields() { |
222 | let attrs = Attrs::new(&fd, &Hygiene::new(db.upcast(), ast.file_id)); | 222 | let attrs = expander.parse_attrs(&fd); |
223 | if !attrs.is_cfg_enabled(&crate_graph[module_id.krate].cfg_options) { | 223 | if !expander.is_cfg_enabled(&attrs) { |
224 | continue; | 224 | continue; |
225 | } | 225 | } |
226 | 226 | ||
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 7b0c506b1..2f2e3e5ba 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs | |||
@@ -93,6 +93,7 @@ impl Attrs { | |||
93 | } | 93 | } |
94 | 94 | ||
95 | pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { | 95 | pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool { |
96 | // FIXME: handle cfg_attr :-) | ||
96 | self.by_key("cfg").tt_values().all(|tt| cfg_options.is_cfg_enabled(tt) != Some(false)) | 97 | self.by_key("cfg").tt_values().all(|tt| cfg_options.is_cfg_enabled(tt) != Some(false)) |
97 | } | 98 | } |
98 | } | 99 | } |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 5f9d53ecb..eafaf48c1 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -9,11 +9,14 @@ use drop_bomb::DropBomb; | |||
9 | use either::Either; | 9 | use either::Either; |
10 | use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId}; | 10 | use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId}; |
11 | use ra_arena::{map::ArenaMap, Arena}; | 11 | use ra_arena::{map::ArenaMap, Arena}; |
12 | use ra_cfg::CfgOptions; | ||
13 | use ra_db::CrateId; | ||
12 | use ra_prof::profile; | 14 | use ra_prof::profile; |
13 | use ra_syntax::{ast, AstNode, AstPtr}; | 15 | use ra_syntax::{ast, AstNode, AstPtr}; |
14 | use rustc_hash::FxHashMap; | 16 | use rustc_hash::FxHashMap; |
15 | 17 | ||
16 | use crate::{ | 18 | use crate::{ |
19 | attr::Attrs, | ||
17 | db::DefDatabase, | 20 | db::DefDatabase, |
18 | expr::{Expr, ExprId, Pat, PatId}, | 21 | expr::{Expr, ExprId, Pat, PatId}, |
19 | item_scope::BuiltinShadowMode, | 22 | item_scope::BuiltinShadowMode, |
@@ -24,25 +27,59 @@ use crate::{ | |||
24 | AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, | 27 | AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, |
25 | }; | 28 | }; |
26 | 29 | ||
30 | /// A subser of Exander that only deals with cfg attributes. We only need it to | ||
31 | /// avoid cyclic queries in crate def map during enum processing. | ||
32 | pub(crate) struct CfgExpander { | ||
33 | cfg_options: CfgOptions, | ||
34 | hygiene: Hygiene, | ||
35 | } | ||
36 | |||
27 | pub(crate) struct Expander { | 37 | pub(crate) struct Expander { |
38 | cfg_expander: CfgExpander, | ||
28 | crate_def_map: Arc<CrateDefMap>, | 39 | crate_def_map: Arc<CrateDefMap>, |
29 | current_file_id: HirFileId, | 40 | current_file_id: HirFileId, |
30 | hygiene: Hygiene, | ||
31 | ast_id_map: Arc<AstIdMap>, | 41 | ast_id_map: Arc<AstIdMap>, |
32 | module: ModuleId, | 42 | module: ModuleId, |
33 | recursive_limit: usize, | 43 | recursive_limit: usize, |
34 | } | 44 | } |
35 | 45 | ||
46 | impl CfgExpander { | ||
47 | pub(crate) fn new( | ||
48 | db: &dyn DefDatabase, | ||
49 | current_file_id: HirFileId, | ||
50 | krate: CrateId, | ||
51 | ) -> CfgExpander { | ||
52 | let hygiene = Hygiene::new(db.upcast(), current_file_id); | ||
53 | let cfg_options = db.crate_graph()[krate].cfg_options.clone(); | ||
54 | CfgExpander { cfg_options, hygiene } | ||
55 | } | ||
56 | |||
57 | pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs { | ||
58 | Attrs::new(owner, &self.hygiene) | ||
59 | } | ||
60 | |||
61 | pub(crate) fn is_cfg_enabled(&self, attrs: &Attrs) -> bool { | ||
62 | attrs.is_cfg_enabled(&self.cfg_options) | ||
63 | } | ||
64 | } | ||
65 | |||
36 | impl Expander { | 66 | impl Expander { |
37 | pub(crate) fn new( | 67 | pub(crate) fn new( |
38 | db: &dyn DefDatabase, | 68 | db: &dyn DefDatabase, |
39 | current_file_id: HirFileId, | 69 | current_file_id: HirFileId, |
40 | module: ModuleId, | 70 | module: ModuleId, |
41 | ) -> Expander { | 71 | ) -> Expander { |
72 | let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); | ||
42 | let crate_def_map = db.crate_def_map(module.krate); | 73 | let crate_def_map = db.crate_def_map(module.krate); |
43 | let hygiene = Hygiene::new(db.upcast(), current_file_id); | ||
44 | let ast_id_map = db.ast_id_map(current_file_id); | 74 | let ast_id_map = db.ast_id_map(current_file_id); |
45 | Expander { crate_def_map, current_file_id, hygiene, ast_id_map, module, recursive_limit: 0 } | 75 | Expander { |
76 | cfg_expander, | ||
77 | crate_def_map, | ||
78 | current_file_id, | ||
79 | ast_id_map, | ||
80 | module, | ||
81 | recursive_limit: 0, | ||
82 | } | ||
46 | } | 83 | } |
47 | 84 | ||
48 | pub(crate) fn enter_expand<T: ast::AstNode>( | 85 | pub(crate) fn enter_expand<T: ast::AstNode>( |
@@ -75,7 +112,7 @@ impl Expander { | |||
75 | ast_id_map: mem::take(&mut self.ast_id_map), | 112 | ast_id_map: mem::take(&mut self.ast_id_map), |
76 | bomb: DropBomb::new("expansion mark dropped"), | 113 | bomb: DropBomb::new("expansion mark dropped"), |
77 | }; | 114 | }; |
78 | self.hygiene = Hygiene::new(db.upcast(), file_id); | 115 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); |
79 | self.current_file_id = file_id; | 116 | self.current_file_id = file_id; |
80 | self.ast_id_map = db.ast_id_map(file_id); | 117 | self.ast_id_map = db.ast_id_map(file_id); |
81 | self.recursive_limit += 1; | 118 | self.recursive_limit += 1; |
@@ -91,7 +128,7 @@ impl Expander { | |||
91 | } | 128 | } |
92 | 129 | ||
93 | pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { | 130 | pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { |
94 | self.hygiene = Hygiene::new(db.upcast(), mark.file_id); | 131 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); |
95 | self.current_file_id = mark.file_id; | 132 | self.current_file_id = mark.file_id; |
96 | self.ast_id_map = mem::take(&mut mark.ast_id_map); | 133 | self.ast_id_map = mem::take(&mut mark.ast_id_map); |
97 | self.recursive_limit -= 1; | 134 | self.recursive_limit -= 1; |
@@ -102,8 +139,16 @@ impl Expander { | |||
102 | InFile { file_id: self.current_file_id, value } | 139 | InFile { file_id: self.current_file_id, value } |
103 | } | 140 | } |
104 | 141 | ||
142 | pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs { | ||
143 | self.cfg_expander.parse_attrs(owner) | ||
144 | } | ||
145 | |||
146 | pub(crate) fn is_cfg_enabled(&self, attrs: &Attrs) -> bool { | ||
147 | self.cfg_expander.is_cfg_enabled(attrs) | ||
148 | } | ||
149 | |||
105 | fn parse_path(&mut self, path: ast::Path) -> Option<Path> { | 150 | fn parse_path(&mut self, path: ast::Path) -> Option<Path> { |
106 | Path::from_src(path, &self.hygiene) | 151 | Path::from_src(path, &self.cfg_expander.hygiene) |
107 | } | 152 | } |
108 | 153 | ||
109 | fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> { | 154 | fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> { |
@@ -142,7 +187,7 @@ pub struct Body { | |||
142 | pub item_scope: ItemScope, | 187 | pub item_scope: ItemScope, |
143 | } | 188 | } |
144 | 189 | ||
145 | pub type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>; | 190 | pub type ExprPtr = AstPtr<ast::Expr>; |
146 | pub type ExprSource = InFile<ExprPtr>; | 191 | pub type ExprSource = InFile<ExprPtr>; |
147 | 192 | ||
148 | pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; | 193 | pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; |
@@ -236,11 +281,11 @@ impl Index<PatId> for Body { | |||
236 | 281 | ||
237 | impl BodySourceMap { | 282 | impl BodySourceMap { |
238 | pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> { | 283 | pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> { |
239 | self.expr_map_back[expr] | 284 | self.expr_map_back[expr].clone() |
240 | } | 285 | } |
241 | 286 | ||
242 | pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> { | 287 | pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> { |
243 | let src = node.map(|it| Either::Left(AstPtr::new(it))); | 288 | let src = node.map(|it| AstPtr::new(it)); |
244 | self.expr_map.get(&src).cloned() | 289 | self.expr_map.get(&src).cloned() |
245 | } | 290 | } |
246 | 291 | ||
@@ -249,13 +294,8 @@ impl BodySourceMap { | |||
249 | self.expansions.get(&src).cloned() | 294 | self.expansions.get(&src).cloned() |
250 | } | 295 | } |
251 | 296 | ||
252 | pub fn field_init_shorthand_expr(&self, node: InFile<&ast::RecordField>) -> Option<ExprId> { | ||
253 | let src = node.map(|it| Either::Right(AstPtr::new(it))); | ||
254 | self.expr_map.get(&src).cloned() | ||
255 | } | ||
256 | |||
257 | pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> { | 297 | pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> { |
258 | self.pat_map_back[pat] | 298 | self.pat_map_back[pat].clone() |
259 | } | 299 | } |
260 | 300 | ||
261 | pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> { | 301 | pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> { |
@@ -264,6 +304,6 @@ impl BodySourceMap { | |||
264 | } | 304 | } |
265 | 305 | ||
266 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { | 306 | pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr<ast::RecordField> { |
267 | self.field_map[&(expr, field)] | 307 | self.field_map[&(expr, field)].clone() |
268 | } | 308 | } |
269 | } | 309 | } |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 032037c8c..c057dc8f2 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -2,9 +2,7 @@ | |||
2 | //! representation. | 2 | //! representation. |
3 | 3 | ||
4 | use either::Either; | 4 | use either::Either; |
5 | |||
6 | use hir_expand::{ | 5 | use hir_expand::{ |
7 | hygiene::Hygiene, | ||
8 | name::{name, AsName, Name}, | 6 | name::{name, AsName, Name}, |
9 | MacroDefId, MacroDefKind, | 7 | MacroDefId, MacroDefKind, |
10 | }; | 8 | }; |
@@ -18,10 +16,8 @@ use ra_syntax::{ | |||
18 | }; | 16 | }; |
19 | use test_utils::tested_by; | 17 | use test_utils::tested_by; |
20 | 18 | ||
21 | use super::{ExprSource, PatSource}; | ||
22 | use crate::{ | 19 | use crate::{ |
23 | adt::StructKind, | 20 | adt::StructKind, |
24 | attr::Attrs, | ||
25 | body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax}, | 21 | body::{Body, BodySourceMap, Expander, PatPtr, SyntheticSyntax}, |
26 | builtin_type::{BuiltinFloat, BuiltinInt}, | 22 | builtin_type::{BuiltinFloat, BuiltinInt}, |
27 | db::DefDatabase, | 23 | db::DefDatabase, |
@@ -31,12 +27,13 @@ use crate::{ | |||
31 | }, | 27 | }, |
32 | item_scope::BuiltinShadowMode, | 28 | item_scope::BuiltinShadowMode, |
33 | path::GenericArgs, | 29 | path::GenericArgs, |
34 | path::Path, | ||
35 | type_ref::{Mutability, TypeRef}, | 30 | type_ref::{Mutability, TypeRef}, |
36 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, HasModule, Intern, | 31 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, |
37 | ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, | 32 | StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, |
38 | }; | 33 | }; |
39 | 34 | ||
35 | use super::{ExprSource, PatSource}; | ||
36 | |||
40 | pub(super) fn lower( | 37 | pub(super) fn lower( |
41 | db: &dyn DefDatabase, | 38 | db: &dyn DefDatabase, |
42 | def: DefWithBodyId, | 39 | def: DefWithBodyId, |
@@ -104,9 +101,8 @@ impl ExprCollector<'_> { | |||
104 | } | 101 | } |
105 | 102 | ||
106 | fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { | 103 | fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { |
107 | let ptr = Either::Left(ptr); | ||
108 | let src = self.expander.to_source(ptr); | 104 | let src = self.expander.to_source(ptr); |
109 | let id = self.make_expr(expr, Ok(src)); | 105 | let id = self.make_expr(expr, Ok(src.clone())); |
110 | self.source_map.expr_map.insert(src, id); | 106 | self.source_map.expr_map.insert(src, id); |
111 | id | 107 | id |
112 | } | 108 | } |
@@ -115,13 +111,6 @@ impl ExprCollector<'_> { | |||
115 | fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { | 111 | fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { |
116 | self.make_expr(expr, Err(SyntheticSyntax)) | 112 | self.make_expr(expr, Err(SyntheticSyntax)) |
117 | } | 113 | } |
118 | fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId { | ||
119 | let ptr = Either::Right(ptr); | ||
120 | let src = self.expander.to_source(ptr); | ||
121 | let id = self.make_expr(expr, Ok(src)); | ||
122 | self.source_map.expr_map.insert(src, id); | ||
123 | id | ||
124 | } | ||
125 | fn empty_block(&mut self) -> ExprId { | 114 | fn empty_block(&mut self) -> ExprId { |
126 | self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None }) | 115 | self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None }) |
127 | } | 116 | } |
@@ -136,7 +125,7 @@ impl ExprCollector<'_> { | |||
136 | 125 | ||
137 | fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { | 126 | fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { |
138 | let src = self.expander.to_source(ptr); | 127 | let src = self.expander.to_source(ptr); |
139 | let id = self.make_pat(pat, Ok(src)); | 128 | let id = self.make_pat(pat, Ok(src.clone())); |
140 | self.source_map.pat_map.insert(src, id); | 129 | self.source_map.pat_map.insert(src, id); |
141 | id | 130 | id |
142 | } | 131 | } |
@@ -291,7 +280,7 @@ impl ExprCollector<'_> { | |||
291 | ast::Expr::ParenExpr(e) => { | 280 | ast::Expr::ParenExpr(e) => { |
292 | let inner = self.collect_expr_opt(e.expr()); | 281 | let inner = self.collect_expr_opt(e.expr()); |
293 | // make the paren expr point to the inner expression as well | 282 | // make the paren expr point to the inner expression as well |
294 | let src = self.expander.to_source(Either::Left(syntax_ptr)); | 283 | let src = self.expander.to_source(syntax_ptr); |
295 | self.source_map.expr_map.insert(src, inner); | 284 | self.source_map.expr_map.insert(src, inner); |
296 | inner | 285 | inner |
297 | } | 286 | } |
@@ -300,7 +289,6 @@ impl ExprCollector<'_> { | |||
300 | self.alloc_expr(Expr::Return { expr }, syntax_ptr) | 289 | self.alloc_expr(Expr::Return { expr }, syntax_ptr) |
301 | } | 290 | } |
302 | ast::Expr::RecordLit(e) => { | 291 | ast::Expr::RecordLit(e) => { |
303 | let crate_graph = self.db.crate_graph(); | ||
304 | let path = e.path().and_then(|path| self.expander.parse_path(path)); | 292 | let path = e.path().and_then(|path| self.expander.parse_path(path)); |
305 | let mut field_ptrs = Vec::new(); | 293 | let mut field_ptrs = Vec::new(); |
306 | let record_lit = if let Some(nfl) = e.record_field_list() { | 294 | let record_lit = if let Some(nfl) = e.record_field_list() { |
@@ -308,31 +296,17 @@ impl ExprCollector<'_> { | |||
308 | .fields() | 296 | .fields() |
309 | .inspect(|field| field_ptrs.push(AstPtr::new(field))) | 297 | .inspect(|field| field_ptrs.push(AstPtr::new(field))) |
310 | .filter_map(|field| { | 298 | .filter_map(|field| { |
311 | let module_id = ContainerId::DefWithBodyId(self.def).module(self.db); | 299 | let attrs = self.expander.parse_attrs(&field); |
312 | let attrs = Attrs::new( | 300 | if !self.expander.is_cfg_enabled(&attrs) { |
313 | &field, | ||
314 | &Hygiene::new(self.db.upcast(), self.expander.current_file_id), | ||
315 | ); | ||
316 | |||
317 | if !attrs.is_cfg_enabled(&crate_graph[module_id.krate].cfg_options) { | ||
318 | return None; | 301 | return None; |
319 | } | 302 | } |
303 | let name = field.field_name()?.as_name(); | ||
320 | 304 | ||
321 | Some(RecordLitField { | 305 | Some(RecordLitField { |
322 | name: field | 306 | name, |
323 | .name_ref() | 307 | expr: match field.expr() { |
324 | .map(|nr| nr.as_name()) | 308 | Some(e) => self.collect_expr(e), |
325 | .unwrap_or_else(Name::missing), | 309 | None => self.missing_expr(), |
326 | expr: if let Some(e) = field.expr() { | ||
327 | self.collect_expr(e) | ||
328 | } else if let Some(nr) = field.name_ref() { | ||
329 | // field shorthand | ||
330 | self.alloc_expr_field_shorthand( | ||
331 | Expr::Path(Path::from_name_ref(&nr)), | ||
332 | AstPtr::new(&field), | ||
333 | ) | ||
334 | } else { | ||
335 | self.missing_expr() | ||
336 | }, | 310 | }, |
337 | }) | 311 | }) |
338 | }) | 312 | }) |
@@ -372,7 +346,7 @@ impl ExprCollector<'_> { | |||
372 | } | 346 | } |
373 | ast::Expr::RefExpr(e) => { | 347 | ast::Expr::RefExpr(e) => { |
374 | let expr = self.collect_expr_opt(e.expr()); | 348 | let expr = self.collect_expr_opt(e.expr()); |
375 | let mutability = Mutability::from_mutable(e.is_mut()); | 349 | let mutability = Mutability::from_mutable(e.mut_token().is_some()); |
376 | self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr) | 350 | self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr) |
377 | } | 351 | } |
378 | ast::Expr::PrefixExpr(e) => { | 352 | ast::Expr::PrefixExpr(e) => { |
@@ -587,7 +561,8 @@ impl ExprCollector<'_> { | |||
587 | let pattern = match &pat { | 561 | let pattern = match &pat { |
588 | ast::Pat::BindPat(bp) => { | 562 | ast::Pat::BindPat(bp) => { |
589 | let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); | 563 | let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); |
590 | let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref()); | 564 | let annotation = |
565 | BindingAnnotation::new(bp.mut_token().is_some(), bp.ref_token().is_some()); | ||
591 | let subpat = bp.pat().map(|subpat| self.collect_pat(subpat)); | 566 | let subpat = bp.pat().map(|subpat| self.collect_pat(subpat)); |
592 | if annotation == BindingAnnotation::Unannotated && subpat.is_none() { | 567 | if annotation == BindingAnnotation::Unannotated && subpat.is_none() { |
593 | // This could also be a single-segment path pattern. To | 568 | // This could also be a single-segment path pattern. To |
@@ -628,7 +603,7 @@ impl ExprCollector<'_> { | |||
628 | } | 603 | } |
629 | ast::Pat::RefPat(p) => { | 604 | ast::Pat::RefPat(p) => { |
630 | let pat = self.collect_pat_opt(p.pat()); | 605 | let pat = self.collect_pat_opt(p.pat()); |
631 | let mutability = Mutability::from_mutable(p.is_mut()); | 606 | let mutability = Mutability::from_mutable(p.mut_token().is_some()); |
632 | Pat::Ref { pat, mutability } | 607 | Pat::Ref { pat, mutability } |
633 | } | 608 | } |
634 | ast::Pat::PathPat(p) => { | 609 | ast::Pat::PathPat(p) => { |
@@ -667,7 +642,9 @@ impl ExprCollector<'_> { | |||
667 | }); | 642 | }); |
668 | fields.extend(iter); | 643 | fields.extend(iter); |
669 | 644 | ||
670 | Pat::Record { path, args: fields } | 645 | let ellipsis = record_field_pat_list.dotdot_token().is_some(); |
646 | |||
647 | Pat::Record { path, args: fields, ellipsis } | ||
671 | } | 648 | } |
672 | ast::Pat::SlicePat(p) => { | 649 | ast::Pat::SlicePat(p) => { |
673 | let SlicePatComponents { prefix, slice, suffix } = p.components(); | 650 | let SlicePatComponents { prefix, slice, suffix } = p.components(); |
@@ -688,7 +665,6 @@ impl ExprCollector<'_> { | |||
688 | Pat::Missing | 665 | Pat::Missing |
689 | } | 666 | } |
690 | } | 667 | } |
691 | |||
692 | // FIXME: implement | 668 | // FIXME: implement |
693 | ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, | 669 | ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, |
694 | }; | 670 | }; |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index e793ad874..56a20c5bd 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -20,7 +20,7 @@ use crate::{ | |||
20 | type_ref::{Mutability, TypeBound, TypeRef}, | 20 | type_ref::{Mutability, TypeBound, TypeRef}, |
21 | visibility::RawVisibility, | 21 | visibility::RawVisibility, |
22 | AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, | 22 | AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, |
23 | ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, | 23 | ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc, |
24 | }; | 24 | }; |
25 | 25 | ||
26 | #[derive(Debug, Clone, PartialEq, Eq)] | 26 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -74,7 +74,7 @@ impl FunctionData { | |||
74 | TypeRef::unit() | 74 | TypeRef::unit() |
75 | }; | 75 | }; |
76 | 76 | ||
77 | let ret_type = if src.value.is_async() { | 77 | let ret_type = if src.value.async_token().is_some() { |
78 | let future_impl = desugar_future_path(ret_type); | 78 | let future_impl = desugar_future_path(ret_type); |
79 | let ty_bound = TypeBound::Path(future_impl); | 79 | let ty_bound = TypeBound::Path(future_impl); |
80 | TypeRef::ImplTrait(vec![ty_bound]) | 80 | TypeRef::ImplTrait(vec![ty_bound]) |
@@ -135,7 +135,7 @@ impl TraitData { | |||
135 | pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { | 135 | pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { |
136 | let src = tr.lookup(db).source(db); | 136 | let src = tr.lookup(db).source(db); |
137 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); | 137 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); |
138 | let auto = src.value.is_auto(); | 138 | let auto = src.value.auto_token().is_some(); |
139 | let ast_id_map = db.ast_id_map(src.file_id); | 139 | let ast_id_map = db.ast_id_map(src.file_id); |
140 | 140 | ||
141 | let container = AssocContainerId::TraitId(tr); | 141 | let container = AssocContainerId::TraitId(tr); |
@@ -212,16 +212,23 @@ impl ImplData { | |||
212 | 212 | ||
213 | let target_trait = src.value.target_trait().map(TypeRef::from_ast); | 213 | let target_trait = src.value.target_trait().map(TypeRef::from_ast); |
214 | let target_type = TypeRef::from_ast_opt(src.value.target_type()); | 214 | let target_type = TypeRef::from_ast_opt(src.value.target_type()); |
215 | let is_negative = src.value.is_negative(); | 215 | let is_negative = src.value.excl_token().is_some(); |
216 | let module_id = impl_loc.container.module(db); | 216 | let module_id = impl_loc.container.module(db); |
217 | 217 | ||
218 | let mut items = Vec::new(); | 218 | let mut items = Vec::new(); |
219 | 219 | ||
220 | if let Some(item_list) = src.value.item_list() { | 220 | if let Some(item_list) = src.value.item_list() { |
221 | items.extend(collect_impl_items(db, item_list.impl_items(), src.file_id, id)); | 221 | let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id); |
222 | items.extend(collect_impl_items( | ||
223 | db, | ||
224 | &mut expander, | ||
225 | item_list.impl_items(), | ||
226 | src.file_id, | ||
227 | id, | ||
228 | )); | ||
222 | items.extend(collect_impl_items_in_macros( | 229 | items.extend(collect_impl_items_in_macros( |
223 | db, | 230 | db, |
224 | module_id, | 231 | &mut expander, |
225 | &src.with_value(item_list), | 232 | &src.with_value(item_list), |
226 | id, | 233 | id, |
227 | )); | 234 | )); |
@@ -268,18 +275,17 @@ impl ConstData { | |||
268 | 275 | ||
269 | fn collect_impl_items_in_macros( | 276 | fn collect_impl_items_in_macros( |
270 | db: &dyn DefDatabase, | 277 | db: &dyn DefDatabase, |
271 | module_id: ModuleId, | 278 | expander: &mut Expander, |
272 | impl_def: &InFile<ast::ItemList>, | 279 | impl_def: &InFile<ast::ItemList>, |
273 | id: ImplId, | 280 | id: ImplId, |
274 | ) -> Vec<AssocItemId> { | 281 | ) -> Vec<AssocItemId> { |
275 | let mut expander = Expander::new(db, impl_def.file_id, module_id); | ||
276 | let mut res = Vec::new(); | 282 | let mut res = Vec::new(); |
277 | 283 | ||
278 | // We set a limit to protect against infinite recursion | 284 | // We set a limit to protect against infinite recursion |
279 | let limit = 100; | 285 | let limit = 100; |
280 | 286 | ||
281 | for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) { | 287 | for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) { |
282 | res.extend(collect_impl_items_in_macro(db, &mut expander, m, id, limit)) | 288 | res.extend(collect_impl_items_in_macro(db, expander, m, id, limit)) |
283 | } | 289 | } |
284 | 290 | ||
285 | res | 291 | res |
@@ -300,6 +306,7 @@ fn collect_impl_items_in_macro( | |||
300 | let items: InFile<ast::MacroItems> = expander.to_source(items); | 306 | let items: InFile<ast::MacroItems> = expander.to_source(items); |
301 | let mut res = collect_impl_items( | 307 | let mut res = collect_impl_items( |
302 | db, | 308 | db, |
309 | expander, | ||
303 | items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())), | 310 | items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())), |
304 | items.file_id, | 311 | items.file_id, |
305 | id, | 312 | id, |
@@ -319,32 +326,26 @@ fn collect_impl_items_in_macro( | |||
319 | 326 | ||
320 | fn collect_impl_items( | 327 | fn collect_impl_items( |
321 | db: &dyn DefDatabase, | 328 | db: &dyn DefDatabase, |
329 | expander: &mut Expander, | ||
322 | impl_items: impl Iterator<Item = ImplItem>, | 330 | impl_items: impl Iterator<Item = ImplItem>, |
323 | file_id: crate::HirFileId, | 331 | file_id: crate::HirFileId, |
324 | id: ImplId, | 332 | id: ImplId, |
325 | ) -> Vec<AssocItemId> { | 333 | ) -> Vec<AssocItemId> { |
326 | let items = db.ast_id_map(file_id); | 334 | let items = db.ast_id_map(file_id); |
327 | let crate_graph = db.crate_graph(); | ||
328 | let module_id = id.lookup(db).container.module(db); | ||
329 | 335 | ||
330 | impl_items | 336 | impl_items |
331 | .filter_map(|item_node| match item_node { | 337 | .filter_map(|item_node| match item_node { |
332 | ast::ImplItem::FnDef(it) => { | 338 | ast::ImplItem::FnDef(it) => { |
339 | let attrs = expander.parse_attrs(&it); | ||
340 | if !expander.is_cfg_enabled(&attrs) { | ||
341 | return None; | ||
342 | } | ||
333 | let def = FunctionLoc { | 343 | let def = FunctionLoc { |
334 | container: AssocContainerId::ImplId(id), | 344 | container: AssocContainerId::ImplId(id), |
335 | ast_id: AstId::new(file_id, items.ast_id(&it)), | 345 | ast_id: AstId::new(file_id, items.ast_id(&it)), |
336 | } | 346 | } |
337 | .intern(db); | 347 | .intern(db); |
338 | 348 | Some(def.into()) | |
339 | if !db | ||
340 | .function_data(def) | ||
341 | .attrs | ||
342 | .is_cfg_enabled(&crate_graph[module_id.krate].cfg_options) | ||
343 | { | ||
344 | None | ||
345 | } else { | ||
346 | Some(def.into()) | ||
347 | } | ||
348 | } | 349 | } |
349 | ast::ImplItem::ConstDef(it) => { | 350 | ast::ImplItem::ConstDef(it) => { |
350 | let def = ConstLoc { | 351 | let def = ConstLoc { |
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs index 095498429..cfa0f2f76 100644 --- a/crates/ra_hir_def/src/diagnostics.rs +++ b/crates/ra_hir_def/src/diagnostics.rs | |||
@@ -20,7 +20,7 @@ impl Diagnostic for UnresolvedModule { | |||
20 | "unresolved module".to_string() | 20 | "unresolved module".to_string() |
21 | } | 21 | } |
22 | fn source(&self) -> InFile<SyntaxNodePtr> { | 22 | fn source(&self) -> InFile<SyntaxNodePtr> { |
23 | InFile { file_id: self.file, value: self.decl.into() } | 23 | InFile { file_id: self.file, value: self.decl.clone().into() } |
24 | } | 24 | } |
25 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 25 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
26 | self | 26 | self |
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs index 197bbe9bd..e11bdf3ec 100644 --- a/crates/ra_hir_def/src/expr.rs +++ b/crates/ra_hir_def/src/expr.rs | |||
@@ -376,35 +376,14 @@ pub enum Pat { | |||
376 | Wild, | 376 | Wild, |
377 | Tuple(Vec<PatId>), | 377 | Tuple(Vec<PatId>), |
378 | Or(Vec<PatId>), | 378 | Or(Vec<PatId>), |
379 | Record { | 379 | Record { path: Option<Path>, args: Vec<RecordFieldPat>, ellipsis: bool }, |
380 | path: Option<Path>, | 380 | Range { start: ExprId, end: ExprId }, |
381 | args: Vec<RecordFieldPat>, | 381 | Slice { prefix: Vec<PatId>, slice: Option<PatId>, suffix: Vec<PatId> }, |
382 | // FIXME: 'ellipsis' option | ||
383 | }, | ||
384 | Range { | ||
385 | start: ExprId, | ||
386 | end: ExprId, | ||
387 | }, | ||
388 | Slice { | ||
389 | prefix: Vec<PatId>, | ||
390 | slice: Option<PatId>, | ||
391 | suffix: Vec<PatId>, | ||
392 | }, | ||
393 | Path(Path), | 382 | Path(Path), |
394 | Lit(ExprId), | 383 | Lit(ExprId), |
395 | Bind { | 384 | Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> }, |
396 | mode: BindingAnnotation, | 385 | TupleStruct { path: Option<Path>, args: Vec<PatId> }, |
397 | name: Name, | 386 | Ref { pat: PatId, mutability: Mutability }, |
398 | subpat: Option<PatId>, | ||
399 | }, | ||
400 | TupleStruct { | ||
401 | path: Option<Path>, | ||
402 | args: Vec<PatId>, | ||
403 | }, | ||
404 | Ref { | ||
405 | pat: PatId, | ||
406 | mutability: Mutability, | ||
407 | }, | ||
408 | } | 387 | } |
409 | 388 | ||
410 | impl Pat { | 389 | impl Pat { |
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index b687ce2b2..d850244c4 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs | |||
@@ -194,7 +194,7 @@ impl GenericParams { | |||
194 | } | 194 | } |
195 | 195 | ||
196 | fn add_where_predicate_from_bound(&mut self, bound: ast::TypeBound, type_ref: TypeRef) { | 196 | fn add_where_predicate_from_bound(&mut self, bound: ast::TypeBound, type_ref: TypeRef) { |
197 | if bound.has_question_mark() { | 197 | if bound.question_token().is_some() { |
198 | // FIXME: remove this bound | 198 | // FIXME: remove this bound |
199 | return; | 199 | return; |
200 | } | 200 | } |
diff --git a/crates/ra_hir_def/src/lang_item.rs b/crates/ra_hir_def/src/lang_item.rs index 01b367278..d96ac8c0a 100644 --- a/crates/ra_hir_def/src/lang_item.rs +++ b/crates/ra_hir_def/src/lang_item.rs | |||
@@ -4,6 +4,7 @@ | |||
4 | //! features, such as Fn family of traits. | 4 | //! features, such as Fn family of traits. |
5 | use std::sync::Arc; | 5 | use std::sync::Arc; |
6 | 6 | ||
7 | use ra_prof::profile; | ||
7 | use ra_syntax::SmolStr; | 8 | use ra_syntax::SmolStr; |
8 | use rustc_hash::FxHashMap; | 9 | use rustc_hash::FxHashMap; |
9 | 10 | ||
@@ -78,6 +79,8 @@ impl LangItems { | |||
78 | 79 | ||
79 | /// Salsa query. This will look for lang items in a specific crate. | 80 | /// Salsa query. This will look for lang items in a specific crate. |
80 | pub(crate) fn crate_lang_items_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<LangItems> { | 81 | pub(crate) fn crate_lang_items_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<LangItems> { |
82 | let _p = profile("crate_lang_items_query"); | ||
83 | |||
81 | let mut lang_items = LangItems::default(); | 84 | let mut lang_items = LangItems::default(); |
82 | 85 | ||
83 | let crate_def_map = db.crate_def_map(krate); | 86 | let crate_def_map = db.crate_def_map(krate); |
@@ -95,6 +98,7 @@ impl LangItems { | |||
95 | db: &dyn DefDatabase, | 98 | db: &dyn DefDatabase, |
96 | module: ModuleId, | 99 | module: ModuleId, |
97 | ) -> Option<Arc<LangItems>> { | 100 | ) -> Option<Arc<LangItems>> { |
101 | let _p = profile("module_lang_items_query"); | ||
98 | let mut lang_items = LangItems::default(); | 102 | let mut lang_items = LangItems::default(); |
99 | lang_items.collect_lang_items(db, module); | 103 | lang_items.collect_lang_items(db, module); |
100 | if lang_items.items.is_empty() { | 104 | if lang_items.items.is_empty() { |
@@ -111,6 +115,7 @@ impl LangItems { | |||
111 | start_crate: CrateId, | 115 | start_crate: CrateId, |
112 | item: SmolStr, | 116 | item: SmolStr, |
113 | ) -> Option<LangItemTarget> { | 117 | ) -> Option<LangItemTarget> { |
118 | let _p = profile("lang_item_query"); | ||
114 | let lang_items = db.crate_lang_items(start_crate); | 119 | let lang_items = db.crate_lang_items(start_crate); |
115 | let start_crate_target = lang_items.items.get(&item); | 120 | let start_crate_target = lang_items.items.get(&item); |
116 | if let Some(target) = start_crate_target { | 121 | if let Some(target) = start_crate_target { |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 8fe3f8617..98c74fe25 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -462,6 +462,14 @@ impl DefCollector<'_> { | |||
462 | Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { | 462 | Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { |
463 | tested_by!(glob_enum); | 463 | tested_by!(glob_enum); |
464 | // glob import from enum => just import all the variants | 464 | // glob import from enum => just import all the variants |
465 | |||
466 | // XXX: urgh, so this works by accident! Here, we look at | ||
467 | // the enum data, and, in theory, this might require us to | ||
468 | // look back at the crate_def_map, creating a cycle. For | ||
469 | // example, `enum E { crate::some_macro!(); }`. Luckely, the | ||
470 | // only kind of macro that is allowed inside enum is a | ||
471 | // `cfg_macro`, and we don't need to run name resolution for | ||
472 | // it, but this is sheer luck! | ||
465 | let enum_data = self.db.enum_data(e); | 473 | let enum_data = self.db.enum_data(e); |
466 | let resolutions = enum_data | 474 | let resolutions = enum_data |
467 | .variants | 475 | .variants |
@@ -977,11 +985,7 @@ impl ModCollector<'_, '_> { | |||
977 | } | 985 | } |
978 | 986 | ||
979 | fn is_cfg_enabled(&self, attrs: &Attrs) -> bool { | 987 | fn is_cfg_enabled(&self, attrs: &Attrs) -> bool { |
980 | // FIXME: handle cfg_attr :-) | 988 | attrs.is_cfg_enabled(self.def_collector.cfg_options) |
981 | attrs | ||
982 | .by_key("cfg") | ||
983 | .tt_values() | ||
984 | .all(|tt| self.def_collector.cfg_options.is_cfg_enabled(tt) != Some(false)) | ||
985 | } | 989 | } |
986 | } | 990 | } |
987 | 991 | ||
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index a9dff3a5d..afd538e4a 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs | |||
@@ -287,7 +287,7 @@ impl RawItemsCollector { | |||
287 | let visibility = RawVisibility::from_ast_with_hygiene(module.visibility(), &self.hygiene); | 287 | let visibility = RawVisibility::from_ast_with_hygiene(module.visibility(), &self.hygiene); |
288 | 288 | ||
289 | let ast_id = self.source_ast_id_map.ast_id(&module); | 289 | let ast_id = self.source_ast_id_map.ast_id(&module); |
290 | if module.has_semi() { | 290 | if module.semicolon_token().is_some() { |
291 | let item = | 291 | let item = |
292 | self.raw_items.modules.alloc(ModuleData::Declaration { name, visibility, ast_id }); | 292 | self.raw_items.modules.alloc(ModuleData::Declaration { name, visibility, ast_id }); |
293 | self.push_item(current_module, attrs, RawItemKind::Module(item)); | 293 | self.push_item(current_module, attrs, RawItemKind::Module(item)); |
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs index 496fc6b08..87165ac33 100644 --- a/crates/ra_hir_def/src/nameres/tests/incremental.rs +++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs | |||
@@ -32,6 +32,9 @@ fn typing_inside_a_function_should_not_invalidate_def_map() { | |||
32 | 32 | ||
33 | use crate::foo::bar::Baz; | 33 | use crate::foo::bar::Baz; |
34 | 34 | ||
35 | enum E { A, B } | ||
36 | use E::*; | ||
37 | |||
35 | fn foo() -> i32 { | 38 | fn foo() -> i32 { |
36 | 1 + 1 | 39 | 1 + 1 |
37 | } | 40 | } |
@@ -46,6 +49,9 @@ fn typing_inside_a_function_should_not_invalidate_def_map() { | |||
46 | 49 | ||
47 | use crate::foo::bar::Baz; | 50 | use crate::foo::bar::Baz; |
48 | 51 | ||
52 | enum E { A, B } | ||
53 | use E::*; | ||
54 | |||
49 | fn foo() -> i32 { 92 } | 55 | fn foo() -> i32 { 92 } |
50 | ", | 56 | ", |
51 | ); | 57 | ); |
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 904080341..91c7b3e09 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -134,11 +134,6 @@ impl Path { | |||
134 | lower::lower_path(path, hygiene) | 134 | lower::lower_path(path, hygiene) |
135 | } | 135 | } |
136 | 136 | ||
137 | /// Converts an `ast::NameRef` into a single-identifier `Path`. | ||
138 | pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path { | ||
139 | Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] } | ||
140 | } | ||
141 | |||
142 | /// Converts a known mod path to `Path`. | 137 | /// Converts a known mod path to `Path`. |
143 | pub(crate) fn from_known_path( | 138 | pub(crate) fn from_known_path( |
144 | path: ModPath, | 139 | path: ModPath, |
diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs index 3c13cb2c7..0f806d6fb 100644 --- a/crates/ra_hir_def/src/path/lower.rs +++ b/crates/ra_hir_def/src/path/lower.rs | |||
@@ -28,7 +28,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
28 | loop { | 28 | loop { |
29 | let segment = path.segment()?; | 29 | let segment = path.segment()?; |
30 | 30 | ||
31 | if segment.coloncolon().is_some() { | 31 | if segment.coloncolon_token().is_some() { |
32 | kind = PathKind::Abs; | 32 | kind = PathKind::Abs; |
33 | } | 33 | } |
34 | 34 | ||
diff --git a/crates/ra_hir_def/src/path/lower/lower_use.rs b/crates/ra_hir_def/src/path/lower/lower_use.rs index 6ec944228..5b6854b0f 100644 --- a/crates/ra_hir_def/src/path/lower/lower_use.rs +++ b/crates/ra_hir_def/src/path/lower/lower_use.rs | |||
@@ -34,7 +34,7 @@ pub(crate) fn lower_use_tree( | |||
34 | let alias = tree.alias().map(|a| { | 34 | let alias = tree.alias().map(|a| { |
35 | a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) | 35 | a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) |
36 | }); | 36 | }); |
37 | let is_glob = tree.star().is_some(); | 37 | let is_glob = tree.star_token().is_some(); |
38 | if let Some(ast_path) = tree.path() { | 38 | if let Some(ast_path) = tree.path() { |
39 | // Handle self in a path. | 39 | // Handle self in a path. |
40 | // E.g. `use something::{self, <...>}` | 40 | // E.g. `use something::{self, <...>}` |
diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs index 01cc392db..ea29c4176 100644 --- a/crates/ra_hir_def/src/type_ref.rs +++ b/crates/ra_hir_def/src/type_ref.rs | |||
@@ -77,7 +77,7 @@ impl TypeRef { | |||
77 | } | 77 | } |
78 | ast::TypeRef::PointerType(inner) => { | 78 | ast::TypeRef::PointerType(inner) => { |
79 | let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); | 79 | let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); |
80 | let mutability = Mutability::from_mutable(inner.is_mut()); | 80 | let mutability = Mutability::from_mutable(inner.mut_token().is_some()); |
81 | TypeRef::RawPtr(Box::new(inner_ty), mutability) | 81 | TypeRef::RawPtr(Box::new(inner_ty), mutability) |
82 | } | 82 | } |
83 | ast::TypeRef::ArrayType(inner) => { | 83 | ast::TypeRef::ArrayType(inner) => { |
@@ -88,7 +88,7 @@ impl TypeRef { | |||
88 | } | 88 | } |
89 | ast::TypeRef::ReferenceType(inner) => { | 89 | ast::TypeRef::ReferenceType(inner) => { |
90 | let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); | 90 | let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); |
91 | let mutability = Mutability::from_mutable(inner.is_mut()); | 91 | let mutability = Mutability::from_mutable(inner.mut_token().is_some()); |
92 | TypeRef::Reference(Box::new(inner_ty), mutability) | 92 | TypeRef::Reference(Box::new(inner_ty), mutability) |
93 | } | 93 | } |
94 | ast::TypeRef::PlaceholderType(_inner) => TypeRef::Placeholder, | 94 | ast::TypeRef::PlaceholderType(_inner) => TypeRef::Placeholder, |
diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs index 5643ecdce..a3ca302c2 100644 --- a/crates/ra_hir_expand/src/ast_id_map.rs +++ b/crates/ra_hir_expand/src/ast_id_map.rs | |||
@@ -90,7 +90,7 @@ impl AstIdMap { | |||
90 | } | 90 | } |
91 | 91 | ||
92 | pub(crate) fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> { | 92 | pub(crate) fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> { |
93 | self.arena[id.raw].cast::<N>().unwrap() | 93 | self.arena[id.raw].clone().cast::<N>().unwrap() |
94 | } | 94 | } |
95 | 95 | ||
96 | fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId { | 96 | fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId { |
diff --git a/crates/ra_hir_expand/src/quote.rs b/crates/ra_hir_expand/src/quote.rs index 3fd4233da..219bc2097 100644 --- a/crates/ra_hir_expand/src/quote.rs +++ b/crates/ra_hir_expand/src/quote.rs | |||
@@ -232,7 +232,7 @@ mod tests { | |||
232 | let quoted = quote!(#a); | 232 | let quoted = quote!(#a); |
233 | assert_eq!(quoted.to_string(), "hello"); | 233 | assert_eq!(quoted.to_string(), "hello"); |
234 | let t = format!("{:?}", quoted); | 234 | let t = format!("{:?}", quoted); |
235 | assert_eq!(t, "Subtree { delimiter: None, token_trees: [Leaf(Ident(Ident { text: \"hello\", id: TokenId(4294967295) }))] }"); | 235 | assert_eq!(t, "SUBTREE $\n IDENT hello 4294967295"); |
236 | } | 236 | } |
237 | 237 | ||
238 | #[test] | 238 | #[test] |
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index 9a4a7aa6f..59efc1c31 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml | |||
@@ -24,6 +24,8 @@ ra_prof = { path = "../ra_prof" } | |||
24 | ra_syntax = { path = "../ra_syntax" } | 24 | ra_syntax = { path = "../ra_syntax" } |
25 | test_utils = { path = "../test_utils" } | 25 | test_utils = { path = "../test_utils" } |
26 | 26 | ||
27 | scoped-tls = "1" | ||
28 | |||
27 | chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" } | 29 | chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" } |
28 | chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" } | 30 | chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" } |
29 | chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" } | 31 | chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" } |
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index 1462b053f..33da16b48 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs | |||
@@ -11,7 +11,7 @@ use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; | |||
11 | use ra_prof::profile; | 11 | use ra_prof::profile; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | method_resolution::CrateImplDefs, | 14 | method_resolution::{CrateImplDefs, TyFingerprint}, |
15 | traits::{chalk, AssocTyValue, Impl}, | 15 | traits::{chalk, AssocTyValue, Impl}, |
16 | Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty, | 16 | Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty, |
17 | TyDefId, TypeCtor, ValueTyDefId, | 17 | TyDefId, TypeCtor, ValueTyDefId, |
@@ -65,7 +65,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
65 | fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; | 65 | fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; |
66 | 66 | ||
67 | #[salsa::invoke(crate::traits::impls_for_trait_query)] | 67 | #[salsa::invoke(crate::traits::impls_for_trait_query)] |
68 | fn impls_for_trait(&self, krate: CrateId, trait_: TraitId) -> Arc<[ImplId]>; | 68 | fn impls_for_trait( |
69 | &self, | ||
70 | krate: CrateId, | ||
71 | trait_: TraitId, | ||
72 | self_ty_fp: Option<TyFingerprint>, | ||
73 | ) -> Arc<[ImplId]>; | ||
69 | 74 | ||
70 | // Interned IDs for Chalk integration | 75 | // Interned IDs for Chalk integration |
71 | #[salsa::interned] | 76 | #[salsa::interned] |
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 8cbce1168..927896d6f 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs | |||
@@ -21,7 +21,7 @@ impl Diagnostic for NoSuchField { | |||
21 | } | 21 | } |
22 | 22 | ||
23 | fn source(&self) -> InFile<SyntaxNodePtr> { | 23 | fn source(&self) -> InFile<SyntaxNodePtr> { |
24 | InFile { file_id: self.file, value: self.field.into() } | 24 | InFile { file_id: self.file, value: self.field.clone().into() } |
25 | } | 25 | } |
26 | 26 | ||
27 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 27 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
@@ -45,7 +45,7 @@ impl Diagnostic for MissingFields { | |||
45 | buf | 45 | buf |
46 | } | 46 | } |
47 | fn source(&self) -> InFile<SyntaxNodePtr> { | 47 | fn source(&self) -> InFile<SyntaxNodePtr> { |
48 | InFile { file_id: self.file, value: self.field_list.into() } | 48 | InFile { file_id: self.file, value: self.field_list.clone().into() } |
49 | } | 49 | } |
50 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 50 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
51 | self | 51 | self |
@@ -63,6 +63,29 @@ impl AstDiagnostic for MissingFields { | |||
63 | } | 63 | } |
64 | 64 | ||
65 | #[derive(Debug)] | 65 | #[derive(Debug)] |
66 | pub struct MissingPatFields { | ||
67 | pub file: HirFileId, | ||
68 | pub field_list: AstPtr<ast::RecordFieldPatList>, | ||
69 | pub missed_fields: Vec<Name>, | ||
70 | } | ||
71 | |||
72 | impl Diagnostic for MissingPatFields { | ||
73 | fn message(&self) -> String { | ||
74 | let mut buf = String::from("Missing structure fields:\n"); | ||
75 | for field in &self.missed_fields { | ||
76 | format_to!(buf, "- {}", field); | ||
77 | } | ||
78 | buf | ||
79 | } | ||
80 | fn source(&self) -> InFile<SyntaxNodePtr> { | ||
81 | InFile { file_id: self.file, value: self.field_list.clone().into() } | ||
82 | } | ||
83 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
84 | self | ||
85 | } | ||
86 | } | ||
87 | |||
88 | #[derive(Debug)] | ||
66 | pub struct MissingMatchArms { | 89 | pub struct MissingMatchArms { |
67 | pub file: HirFileId, | 90 | pub file: HirFileId, |
68 | pub match_expr: AstPtr<ast::Expr>, | 91 | pub match_expr: AstPtr<ast::Expr>, |
@@ -74,7 +97,7 @@ impl Diagnostic for MissingMatchArms { | |||
74 | String::from("Missing match arm") | 97 | String::from("Missing match arm") |
75 | } | 98 | } |
76 | fn source(&self) -> InFile<SyntaxNodePtr> { | 99 | fn source(&self) -> InFile<SyntaxNodePtr> { |
77 | InFile { file_id: self.file, value: self.match_expr.into() } | 100 | InFile { file_id: self.file, value: self.match_expr.clone().into() } |
78 | } | 101 | } |
79 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 102 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
80 | self | 103 | self |
@@ -92,7 +115,7 @@ impl Diagnostic for MissingOkInTailExpr { | |||
92 | "wrap return expression in Ok".to_string() | 115 | "wrap return expression in Ok".to_string() |
93 | } | 116 | } |
94 | fn source(&self) -> InFile<SyntaxNodePtr> { | 117 | fn source(&self) -> InFile<SyntaxNodePtr> { |
95 | InFile { file_id: self.file, value: self.expr.into() } | 118 | InFile { file_id: self.file, value: self.expr.clone().into() } |
96 | } | 119 | } |
97 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 120 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
98 | self | 121 | self |
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs index 0e9313aa1..d03bbd5a7 100644 --- a/crates/ra_hir_ty/src/display.rs +++ b/crates/ra_hir_ty/src/display.rs | |||
@@ -247,19 +247,21 @@ impl HirDisplay for ApplicationTy { | |||
247 | } | 247 | } |
248 | } | 248 | } |
249 | TypeCtor::Closure { .. } => { | 249 | TypeCtor::Closure { .. } => { |
250 | let sig = self.parameters[0] | 250 | let sig = self.parameters[0].callable_sig(f.db); |
251 | .callable_sig(f.db) | 251 | if let Some(sig) = sig { |
252 | .expect("first closure parameter should contain signature"); | 252 | if sig.params().is_empty() { |
253 | if sig.params().is_empty() { | 253 | write!(f, "||")?; |
254 | write!(f, "||")?; | 254 | } else if f.omit_verbose_types() { |
255 | } else if f.omit_verbose_types() { | 255 | write!(f, "|{}|", TYPE_HINT_TRUNCATION)?; |
256 | write!(f, "|{}|", TYPE_HINT_TRUNCATION)?; | 256 | } else { |
257 | write!(f, "|")?; | ||
258 | f.write_joined(sig.params(), ", ")?; | ||
259 | write!(f, "|")?; | ||
260 | }; | ||
261 | write!(f, " -> {}", sig.ret().display(f.db))?; | ||
257 | } else { | 262 | } else { |
258 | write!(f, "|")?; | 263 | write!(f, "{{closure}}")?; |
259 | f.write_joined(sig.params(), ", ")?; | 264 | } |
260 | write!(f, "|")?; | ||
261 | }; | ||
262 | write!(f, " -> {}", sig.ret().display(f.db))?; | ||
263 | } | 265 | } |
264 | } | 266 | } |
265 | Ok(()) | 267 | Ok(()) |
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs index e45e9ea14..69b527f74 100644 --- a/crates/ra_hir_ty/src/expr.rs +++ b/crates/ra_hir_ty/src/expr.rs | |||
@@ -9,7 +9,7 @@ use rustc_hash::FxHashSet; | |||
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | db::HirDatabase, | 11 | db::HirDatabase, |
12 | diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr}, | 12 | diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields}, |
13 | utils::variant_data, | 13 | utils::variant_data, |
14 | ApplicationTy, InferenceResult, Ty, TypeCtor, | 14 | ApplicationTy, InferenceResult, Ty, TypeCtor, |
15 | _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, | 15 | _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, |
@@ -49,39 +49,95 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
49 | if let Some((variant_def, missed_fields, true)) = | 49 | if let Some((variant_def, missed_fields, true)) = |
50 | record_literal_missing_fields(db, &self.infer, id, expr) | 50 | record_literal_missing_fields(db, &self.infer, id, expr) |
51 | { | 51 | { |
52 | // XXX: only look at source_map if we do have missing fields | 52 | self.create_record_literal_missing_fields_diagnostic( |
53 | let (_, source_map) = db.body_with_source_map(self.func.into()); | 53 | id, |
54 | 54 | db, | |
55 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 55 | variant_def, |
56 | if let Some(expr) = source_ptr.value.left() { | 56 | missed_fields, |
57 | let root = source_ptr.file_syntax(db.upcast()); | 57 | ); |
58 | if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { | ||
59 | if let Some(field_list) = record_lit.record_field_list() { | ||
60 | let variant_data = variant_data(db.upcast(), variant_def); | ||
61 | let missed_fields = missed_fields | ||
62 | .into_iter() | ||
63 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
64 | .collect(); | ||
65 | self.sink.push(MissingFields { | ||
66 | file: source_ptr.file_id, | ||
67 | field_list: AstPtr::new(&field_list), | ||
68 | missed_fields, | ||
69 | }) | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | } | 58 | } |
75 | if let Expr::Match { expr, arms } = expr { | 59 | if let Expr::Match { expr, arms } = expr { |
76 | self.validate_match(id, *expr, arms, db, self.infer.clone()); | 60 | self.validate_match(id, *expr, arms, db, self.infer.clone()); |
77 | } | 61 | } |
78 | } | 62 | } |
63 | for (id, pat) in body.pats.iter() { | ||
64 | if let Some((variant_def, missed_fields, true)) = | ||
65 | record_pattern_missing_fields(db, &self.infer, id, pat) | ||
66 | { | ||
67 | self.create_record_pattern_missing_fields_diagnostic( | ||
68 | id, | ||
69 | db, | ||
70 | variant_def, | ||
71 | missed_fields, | ||
72 | ); | ||
73 | } | ||
74 | } | ||
79 | let body_expr = &body[body.body_expr]; | 75 | let body_expr = &body[body.body_expr]; |
80 | if let Expr::Block { tail: Some(t), .. } = body_expr { | 76 | if let Expr::Block { tail: Some(t), .. } = body_expr { |
81 | self.validate_results_in_tail_expr(body.body_expr, *t, db); | 77 | self.validate_results_in_tail_expr(body.body_expr, *t, db); |
82 | } | 78 | } |
83 | } | 79 | } |
84 | 80 | ||
81 | fn create_record_literal_missing_fields_diagnostic( | ||
82 | &mut self, | ||
83 | id: ExprId, | ||
84 | db: &dyn HirDatabase, | ||
85 | variant_def: VariantId, | ||
86 | missed_fields: Vec<LocalStructFieldId>, | ||
87 | ) { | ||
88 | // XXX: only look at source_map if we do have missing fields | ||
89 | let (_, source_map) = db.body_with_source_map(self.func.into()); | ||
90 | |||
91 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | ||
92 | let root = source_ptr.file_syntax(db.upcast()); | ||
93 | if let ast::Expr::RecordLit(record_lit) = &source_ptr.value.to_node(&root) { | ||
94 | if let Some(field_list) = record_lit.record_field_list() { | ||
95 | let variant_data = variant_data(db.upcast(), variant_def); | ||
96 | let missed_fields = missed_fields | ||
97 | .into_iter() | ||
98 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
99 | .collect(); | ||
100 | self.sink.push(MissingFields { | ||
101 | file: source_ptr.file_id, | ||
102 | field_list: AstPtr::new(&field_list), | ||
103 | missed_fields, | ||
104 | }) | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | } | ||
109 | |||
110 | fn create_record_pattern_missing_fields_diagnostic( | ||
111 | &mut self, | ||
112 | id: PatId, | ||
113 | db: &dyn HirDatabase, | ||
114 | variant_def: VariantId, | ||
115 | missed_fields: Vec<LocalStructFieldId>, | ||
116 | ) { | ||
117 | // XXX: only look at source_map if we do have missing fields | ||
118 | let (_, source_map) = db.body_with_source_map(self.func.into()); | ||
119 | |||
120 | if let Ok(source_ptr) = source_map.pat_syntax(id) { | ||
121 | if let Some(expr) = source_ptr.value.as_ref().left() { | ||
122 | let root = source_ptr.file_syntax(db.upcast()); | ||
123 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { | ||
124 | if let Some(field_list) = record_pat.record_field_pat_list() { | ||
125 | let variant_data = variant_data(db.upcast(), variant_def); | ||
126 | let missed_fields = missed_fields | ||
127 | .into_iter() | ||
128 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
129 | .collect(); | ||
130 | self.sink.push(MissingPatFields { | ||
131 | file: source_ptr.file_id, | ||
132 | field_list: AstPtr::new(&field_list), | ||
133 | missed_fields, | ||
134 | }) | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | |||
85 | fn validate_match( | 141 | fn validate_match( |
86 | &mut self, | 142 | &mut self, |
87 | id: ExprId, | 143 | id: ExprId, |
@@ -147,18 +203,16 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
147 | } | 203 | } |
148 | 204 | ||
149 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 205 | if let Ok(source_ptr) = source_map.expr_syntax(id) { |
150 | if let Some(expr) = source_ptr.value.left() { | 206 | let root = source_ptr.file_syntax(db.upcast()); |
151 | let root = source_ptr.file_syntax(db.upcast()); | 207 | if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) { |
152 | if let ast::Expr::MatchExpr(match_expr) = expr.to_node(&root) { | 208 | if let (Some(match_expr), Some(arms)) = |
153 | if let (Some(match_expr), Some(arms)) = | 209 | (match_expr.expr(), match_expr.match_arm_list()) |
154 | (match_expr.expr(), match_expr.match_arm_list()) | 210 | { |
155 | { | 211 | self.sink.push(MissingMatchArms { |
156 | self.sink.push(MissingMatchArms { | 212 | file: source_ptr.file_id, |
157 | file: source_ptr.file_id, | 213 | match_expr: AstPtr::new(&match_expr), |
158 | match_expr: AstPtr::new(&match_expr), | 214 | arms: AstPtr::new(&arms), |
159 | arms: AstPtr::new(&arms), | 215 | }) |
160 | }) | ||
161 | } | ||
162 | } | 216 | } |
163 | } | 217 | } |
164 | } | 218 | } |
@@ -189,9 +243,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
189 | let (_, source_map) = db.body_with_source_map(self.func.into()); | 243 | let (_, source_map) = db.body_with_source_map(self.func.into()); |
190 | 244 | ||
191 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 245 | if let Ok(source_ptr) = source_map.expr_syntax(id) { |
192 | if let Some(expr) = source_ptr.value.left() { | 246 | self.sink |
193 | self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); | 247 | .push(MissingOkInTailExpr { file: source_ptr.file_id, expr: source_ptr.value }); |
194 | } | ||
195 | } | 248 | } |
196 | } | 249 | } |
197 | } | 250 | } |
@@ -232,9 +285,9 @@ pub fn record_pattern_missing_fields( | |||
232 | infer: &InferenceResult, | 285 | infer: &InferenceResult, |
233 | id: PatId, | 286 | id: PatId, |
234 | pat: &Pat, | 287 | pat: &Pat, |
235 | ) -> Option<(VariantId, Vec<LocalStructFieldId>)> { | 288 | ) -> Option<(VariantId, Vec<LocalStructFieldId>, /*exhaustive*/ bool)> { |
236 | let fields = match pat { | 289 | let (fields, exhaustive) = match pat { |
237 | Pat::Record { path: _, args } => args, | 290 | Pat::Record { path: _, args, ellipsis } => (args, !ellipsis), |
238 | _ => return None, | 291 | _ => return None, |
239 | }; | 292 | }; |
240 | 293 | ||
@@ -254,5 +307,5 @@ pub fn record_pattern_missing_fields( | |||
254 | if missed_fields.is_empty() { | 307 | if missed_fields.is_empty() { |
255 | return None; | 308 | return None; |
256 | } | 309 | } |
257 | Some((variant_def, missed_fields)) | 310 | Some((variant_def, missed_fields, exhaustive)) |
258 | } | 311 | } |
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs index 69bbb4307..078476f76 100644 --- a/crates/ra_hir_ty/src/infer/pat.rs +++ b/crates/ra_hir_ty/src/infer/pat.rs | |||
@@ -158,7 +158,7 @@ impl<'a> InferenceContext<'a> { | |||
158 | Pat::TupleStruct { path: p, args: subpats } => { | 158 | Pat::TupleStruct { path: p, args: subpats } => { |
159 | self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm, pat) | 159 | self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm, pat) |
160 | } | 160 | } |
161 | Pat::Record { path: p, args: fields } => { | 161 | Pat::Record { path: p, args: fields, ellipsis: _ } => { |
162 | self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat) | 162 | self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat) |
163 | } | 163 | } |
164 | Pat::Path(path) => { | 164 | Pat::Path(path) => { |
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index 74a0bc7db..657284fd0 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs | |||
@@ -34,7 +34,7 @@ impl TyFingerprint { | |||
34 | /// Creates a TyFingerprint for looking up an impl. Only certain types can | 34 | /// Creates a TyFingerprint for looking up an impl. Only certain types can |
35 | /// have impls: if we have some `struct S`, we can have an `impl S`, but not | 35 | /// have impls: if we have some `struct S`, we can have an `impl S`, but not |
36 | /// `impl &S`. Hence, this will return `None` for reference types and such. | 36 | /// `impl &S`. Hence, this will return `None` for reference types and such. |
37 | fn for_impl(ty: &Ty) -> Option<TyFingerprint> { | 37 | pub(crate) fn for_impl(ty: &Ty) -> Option<TyFingerprint> { |
38 | match ty { | 38 | match ty { |
39 | Ty::Apply(a_ty) => Some(TyFingerprint::Apply(a_ty.ctor)), | 39 | Ty::Apply(a_ty) => Some(TyFingerprint::Apply(a_ty.ctor)), |
40 | _ => None, | 40 | _ => None, |
@@ -45,7 +45,7 @@ impl TyFingerprint { | |||
45 | #[derive(Debug, PartialEq, Eq)] | 45 | #[derive(Debug, PartialEq, Eq)] |
46 | pub struct CrateImplDefs { | 46 | pub struct CrateImplDefs { |
47 | impls: FxHashMap<TyFingerprint, Vec<ImplId>>, | 47 | impls: FxHashMap<TyFingerprint, Vec<ImplId>>, |
48 | impls_by_trait: FxHashMap<TraitId, Vec<ImplId>>, | 48 | impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>, |
49 | } | 49 | } |
50 | 50 | ||
51 | impl CrateImplDefs { | 51 | impl CrateImplDefs { |
@@ -59,7 +59,14 @@ impl CrateImplDefs { | |||
59 | for impl_id in module_data.scope.impls() { | 59 | for impl_id in module_data.scope.impls() { |
60 | match db.impl_trait(impl_id) { | 60 | match db.impl_trait(impl_id) { |
61 | Some(tr) => { | 61 | Some(tr) => { |
62 | res.impls_by_trait.entry(tr.value.trait_).or_default().push(impl_id); | 62 | let self_ty = db.impl_self_ty(impl_id); |
63 | let self_ty_fp = TyFingerprint::for_impl(&self_ty.value); | ||
64 | res.impls_by_trait | ||
65 | .entry(tr.value.trait_) | ||
66 | .or_default() | ||
67 | .entry(self_ty_fp) | ||
68 | .or_default() | ||
69 | .push(impl_id); | ||
63 | } | 70 | } |
64 | None => { | 71 | None => { |
65 | let self_ty = db.impl_self_ty(impl_id); | 72 | let self_ty = db.impl_self_ty(impl_id); |
@@ -79,11 +86,39 @@ impl CrateImplDefs { | |||
79 | } | 86 | } |
80 | 87 | ||
81 | pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ { | 88 | pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ { |
82 | self.impls_by_trait.get(&tr).into_iter().flatten().copied() | 89 | self.impls_by_trait |
90 | .get(&tr) | ||
91 | .into_iter() | ||
92 | .flat_map(|m| m.values().flat_map(|v| v.iter().copied())) | ||
93 | } | ||
94 | |||
95 | pub fn lookup_impl_defs_for_trait_and_ty( | ||
96 | &self, | ||
97 | tr: TraitId, | ||
98 | fp: TyFingerprint, | ||
99 | ) -> impl Iterator<Item = ImplId> + '_ { | ||
100 | self.impls_by_trait | ||
101 | .get(&tr) | ||
102 | .and_then(|m| m.get(&Some(fp))) | ||
103 | .into_iter() | ||
104 | .flatten() | ||
105 | .copied() | ||
106 | .chain( | ||
107 | self.impls_by_trait | ||
108 | .get(&tr) | ||
109 | .and_then(|m| m.get(&None)) | ||
110 | .into_iter() | ||
111 | .flatten() | ||
112 | .copied(), | ||
113 | ) | ||
83 | } | 114 | } |
84 | 115 | ||
85 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { | 116 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { |
86 | self.impls.values().chain(self.impls_by_trait.values()).flatten().copied() | 117 | self.impls |
118 | .values() | ||
119 | .chain(self.impls_by_trait.values().flat_map(|m| m.values())) | ||
120 | .flatten() | ||
121 | .copied() | ||
87 | } | 122 | } |
88 | } | 123 | } |
89 | 124 | ||
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 08723068f..81fc0f63a 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs | |||
@@ -23,7 +23,7 @@ use insta::assert_snapshot; | |||
23 | use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; | 23 | use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; |
24 | use ra_syntax::{ | 24 | use ra_syntax::{ |
25 | algo, | 25 | algo, |
26 | ast::{self, AstNode, AstToken}, | 26 | ast::{self, AstNode}, |
27 | }; | 27 | }; |
28 | use stdx::format_to; | 28 | use stdx::format_to; |
29 | 29 | ||
@@ -82,12 +82,10 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { | |||
82 | 82 | ||
83 | for (expr, ty) in inference_result.type_of_expr.iter() { | 83 | for (expr, ty) in inference_result.type_of_expr.iter() { |
84 | let syntax_ptr = match body_source_map.expr_syntax(expr) { | 84 | let syntax_ptr = match body_source_map.expr_syntax(expr) { |
85 | Ok(sp) => { | 85 | Ok(sp) => sp.map(|ast| ast.syntax_node_ptr()), |
86 | sp.map(|ast| ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr())) | ||
87 | } | ||
88 | Err(SyntheticSyntax) => continue, | 86 | Err(SyntheticSyntax) => continue, |
89 | }; | 87 | }; |
90 | types.push((syntax_ptr, ty)); | 88 | types.push((syntax_ptr.clone(), ty)); |
91 | if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) { | 89 | if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) { |
92 | mismatches.push((syntax_ptr, mismatch)); | 90 | mismatches.push((syntax_ptr, mismatch)); |
93 | } | 91 | } |
@@ -101,7 +99,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { | |||
101 | let node = src_ptr.value.to_node(&src_ptr.file_syntax(&db)); | 99 | let node = src_ptr.value.to_node(&src_ptr.file_syntax(&db)); |
102 | 100 | ||
103 | let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) { | 101 | let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) { |
104 | (self_param.self_kw().unwrap().syntax().text_range(), "self".to_string()) | 102 | (self_param.self_token().unwrap().text_range(), "self".to_string()) |
105 | } else { | 103 | } else { |
106 | (src_ptr.value.range(), node.text().to_string().replace("\n", " ")) | 104 | (src_ptr.value.range(), node.text().to_string().replace("\n", " ")) |
107 | }; | 105 | }; |
@@ -409,3 +407,43 @@ fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() { | |||
409 | 407 | ||
410 | assert_snapshot!(diagnostics, @r###""###); | 408 | assert_snapshot!(diagnostics, @r###""###); |
411 | } | 409 | } |
410 | |||
411 | #[test] | ||
412 | fn missing_record_pat_field_diagnostic() { | ||
413 | let diagnostics = TestDB::with_files( | ||
414 | r" | ||
415 | //- /lib.rs | ||
416 | struct S { foo: i32, bar: () } | ||
417 | fn baz(s: S) { | ||
418 | let S { foo: _ } = s; | ||
419 | } | ||
420 | ", | ||
421 | ) | ||
422 | .diagnostics() | ||
423 | .0; | ||
424 | |||
425 | assert_snapshot!(diagnostics, @r###" | ||
426 | "{ foo: _ }": Missing structure fields: | ||
427 | - bar | ||
428 | "### | ||
429 | ); | ||
430 | } | ||
431 | |||
432 | #[test] | ||
433 | fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() { | ||
434 | let diagnostics = TestDB::with_files( | ||
435 | r" | ||
436 | //- /lib.rs | ||
437 | struct S { foo: i32, bar: () } | ||
438 | fn baz(s: S) -> i32 { | ||
439 | match s { | ||
440 | S { foo, .. } => foo, | ||
441 | } | ||
442 | } | ||
443 | ", | ||
444 | ) | ||
445 | .diagnostics() | ||
446 | .0; | ||
447 | |||
448 | assert_snapshot!(diagnostics, @""); | ||
449 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index ff4599b71..f2a9b1c40 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs | |||
@@ -1,10 +1,13 @@ | |||
1 | use std::fs; | ||
2 | |||
1 | use insta::assert_snapshot; | 3 | use insta::assert_snapshot; |
2 | use ra_db::fixture::WithFixture; | 4 | use ra_db::fixture::WithFixture; |
3 | 5 | use test_utils::project_dir; | |
4 | use super::{infer, type_at, type_at_pos}; | ||
5 | 6 | ||
6 | use crate::test_db::TestDB; | 7 | use crate::test_db::TestDB; |
7 | 8 | ||
9 | use super::{infer, type_at, type_at_pos}; | ||
10 | |||
8 | #[test] | 11 | #[test] |
9 | fn cfg_impl_def() { | 12 | fn cfg_impl_def() { |
10 | let (db, pos) = TestDB::with_position( | 13 | let (db, pos) = TestDB::with_position( |
@@ -482,6 +485,30 @@ fn bar() -> u32 {0} | |||
482 | } | 485 | } |
483 | 486 | ||
484 | #[test] | 487 | #[test] |
488 | #[ignore] | ||
489 | fn include_accidentally_quadratic() { | ||
490 | let file = project_dir().join("crates/ra_syntax/test_data/accidentally_quadratic"); | ||
491 | let big_file = fs::read_to_string(file).unwrap(); | ||
492 | let big_file = vec![big_file; 10].join("\n"); | ||
493 | |||
494 | let fixture = r#" | ||
495 | //- /main.rs | ||
496 | #[rustc_builtin_macro] | ||
497 | macro_rules! include {() => {}} | ||
498 | |||
499 | include!("foo.rs"); | ||
500 | |||
501 | fn main() { | ||
502 | RegisterBlock { }<|>; | ||
503 | } | ||
504 | "#; | ||
505 | let fixture = format!("{}\n//- /foo.rs\n{}", fixture, big_file); | ||
506 | |||
507 | let (db, pos) = TestDB::with_position(&fixture); | ||
508 | assert_eq!("RegisterBlock", type_at_pos(&db, pos)); | ||
509 | } | ||
510 | |||
511 | #[test] | ||
485 | fn infer_builtin_macros_include_concat() { | 512 | fn infer_builtin_macros_include_concat() { |
486 | let (db, pos) = TestDB::with_position( | 513 | let (db, pos) = TestDB::with_position( |
487 | r#" | 514 | r#" |
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index 5a1e12ce9..43d8d1e80 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs | |||
@@ -7,7 +7,7 @@ use ra_db::{impl_intern_key, salsa, CrateId}; | |||
7 | use ra_prof::profile; | 7 | use ra_prof::profile; |
8 | use rustc_hash::FxHashSet; | 8 | use rustc_hash::FxHashSet; |
9 | 9 | ||
10 | use crate::{db::HirDatabase, DebruijnIndex}; | 10 | use crate::{db::HirDatabase, method_resolution::TyFingerprint, DebruijnIndex}; |
11 | 11 | ||
12 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; | 12 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; |
13 | 13 | ||
@@ -40,7 +40,12 @@ pub(crate) fn impls_for_trait_query( | |||
40 | db: &dyn HirDatabase, | 40 | db: &dyn HirDatabase, |
41 | krate: CrateId, | 41 | krate: CrateId, |
42 | trait_: TraitId, | 42 | trait_: TraitId, |
43 | self_ty_fp: Option<TyFingerprint>, | ||
43 | ) -> Arc<[ImplId]> { | 44 | ) -> Arc<[ImplId]> { |
45 | // FIXME: We could be a lot smarter here - because of the orphan rules and | ||
46 | // the fact that the trait and the self type need to be in the dependency | ||
47 | // tree of a crate somewhere for an impl to exist, we could skip looking in | ||
48 | // a lot of crates completely | ||
44 | let mut impls = FxHashSet::default(); | 49 | let mut impls = FxHashSet::default(); |
45 | // We call the query recursively here. On the one hand, this means we can | 50 | // We call the query recursively here. On the one hand, this means we can |
46 | // reuse results from queries for different crates; on the other hand, this | 51 | // reuse results from queries for different crates; on the other hand, this |
@@ -48,10 +53,13 @@ pub(crate) fn impls_for_trait_query( | |||
48 | // ones the user is editing), so this may actually be a waste of memory. I'm | 53 | // ones the user is editing), so this may actually be a waste of memory. I'm |
49 | // doing it like this mainly for simplicity for now. | 54 | // doing it like this mainly for simplicity for now. |
50 | for dep in &db.crate_graph()[krate].dependencies { | 55 | for dep in &db.crate_graph()[krate].dependencies { |
51 | impls.extend(db.impls_for_trait(dep.crate_id, trait_).iter()); | 56 | impls.extend(db.impls_for_trait(dep.crate_id, trait_, self_ty_fp).iter()); |
52 | } | 57 | } |
53 | let crate_impl_defs = db.impls_in_crate(krate); | 58 | let crate_impl_defs = db.impls_in_crate(krate); |
54 | impls.extend(crate_impl_defs.lookup_impl_defs_for_trait(trait_)); | 59 | match self_ty_fp { |
60 | Some(fp) => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait_and_ty(trait_, fp)), | ||
61 | None => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait(trait_)), | ||
62 | } | ||
55 | impls.into_iter().collect() | 63 | impls.into_iter().collect() |
56 | } | 64 | } |
57 | 65 | ||
@@ -177,7 +185,7 @@ fn solve( | |||
177 | 185 | ||
178 | let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL); | 186 | let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL); |
179 | 187 | ||
180 | let solution = solver.solve_limited(&context, goal, || { | 188 | let should_continue = || { |
181 | context.db.check_canceled(); | 189 | context.db.check_canceled(); |
182 | let remaining = fuel.get(); | 190 | let remaining = fuel.get(); |
183 | fuel.set(remaining - 1); | 191 | fuel.set(remaining - 1); |
@@ -185,12 +193,21 @@ fn solve( | |||
185 | log::debug!("fuel exhausted"); | 193 | log::debug!("fuel exhausted"); |
186 | } | 194 | } |
187 | remaining > 0 | 195 | remaining > 0 |
188 | }); | 196 | }; |
197 | let mut solve = || solver.solve_limited(&context, goal, should_continue); | ||
198 | // don't set the TLS for Chalk unless Chalk debugging is active, to make | ||
199 | // extra sure we only use it for debugging | ||
200 | let solution = | ||
201 | if is_chalk_debug() { chalk::tls::set_current_program(db, solve) } else { solve() }; | ||
189 | 202 | ||
190 | log::debug!("solve({:?}) => {:?}", goal, solution); | 203 | log::debug!("solve({:?}) => {:?}", goal, solution); |
191 | solution | 204 | solution |
192 | } | 205 | } |
193 | 206 | ||
207 | fn is_chalk_debug() -> bool { | ||
208 | std::env::var("CHALK_DEBUG").is_ok() | ||
209 | } | ||
210 | |||
194 | fn solution_from_chalk( | 211 | fn solution_from_chalk( |
195 | db: &dyn HirDatabase, | 212 | db: &dyn HirDatabase, |
196 | solution: chalk_solve::Solution<Interner>, | 213 | solution: chalk_solve::Solution<Interner>, |
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index 1bc0f0713..e05fea843 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs | |||
@@ -16,10 +16,12 @@ use ra_db::{ | |||
16 | 16 | ||
17 | use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; | 17 | use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; |
18 | use crate::{ | 18 | use crate::{ |
19 | db::HirDatabase, display::HirDisplay, utils::generics, ApplicationTy, GenericPredicate, | 19 | db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics, |
20 | ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | 20 | ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, |
21 | }; | 21 | }; |
22 | 22 | ||
23 | pub(super) mod tls; | ||
24 | |||
23 | #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] | 25 | #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] |
24 | pub struct Interner; | 26 | pub struct Interner; |
25 | 27 | ||
@@ -33,90 +35,85 @@ impl chalk_ir::interner::Interner for Interner { | |||
33 | type Identifier = TypeAliasId; | 35 | type Identifier = TypeAliasId; |
34 | type DefId = InternId; | 36 | type DefId = InternId; |
35 | 37 | ||
36 | // FIXME: implement these | ||
37 | fn debug_struct_id( | 38 | fn debug_struct_id( |
38 | _type_kind_id: chalk_ir::StructId<Self>, | 39 | type_kind_id: StructId, |
39 | _fmt: &mut fmt::Formatter<'_>, | 40 | fmt: &mut fmt::Formatter<'_>, |
40 | ) -> Option<fmt::Result> { | 41 | ) -> Option<fmt::Result> { |
41 | None | 42 | tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt))) |
42 | } | 43 | } |
43 | 44 | ||
44 | fn debug_trait_id( | 45 | fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { |
45 | _type_kind_id: chalk_ir::TraitId<Self>, | 46 | tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt))) |
46 | _fmt: &mut fmt::Formatter<'_>, | ||
47 | ) -> Option<fmt::Result> { | ||
48 | None | ||
49 | } | 47 | } |
50 | 48 | ||
51 | fn debug_assoc_type_id( | 49 | fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { |
52 | _id: chalk_ir::AssocTypeId<Self>, | 50 | tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt))) |
53 | _fmt: &mut fmt::Formatter<'_>, | ||
54 | ) -> Option<fmt::Result> { | ||
55 | None | ||
56 | } | 51 | } |
57 | 52 | ||
58 | fn debug_alias( | 53 | fn debug_alias( |
59 | _projection: &chalk_ir::AliasTy<Self>, | 54 | alias: &chalk_ir::AliasTy<Interner>, |
60 | _fmt: &mut fmt::Formatter<'_>, | 55 | fmt: &mut fmt::Formatter<'_>, |
61 | ) -> Option<fmt::Result> { | 56 | ) -> Option<fmt::Result> { |
62 | None | 57 | tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt))) |
63 | } | 58 | } |
64 | 59 | ||
65 | fn debug_ty(_ty: &chalk_ir::Ty<Self>, _fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | 60 | fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { |
66 | None | 61 | tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt))) |
67 | } | 62 | } |
68 | 63 | ||
69 | fn debug_lifetime( | 64 | fn debug_lifetime( |
70 | _lifetime: &chalk_ir::Lifetime<Self>, | 65 | lifetime: &chalk_ir::Lifetime<Interner>, |
71 | _fmt: &mut fmt::Formatter<'_>, | 66 | fmt: &mut fmt::Formatter<'_>, |
72 | ) -> Option<fmt::Result> { | 67 | ) -> Option<fmt::Result> { |
73 | None | 68 | tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt))) |
74 | } | 69 | } |
75 | 70 | ||
76 | fn debug_parameter( | 71 | fn debug_parameter( |
77 | _parameter: &Parameter<Self>, | 72 | parameter: &Parameter<Interner>, |
78 | _fmt: &mut fmt::Formatter<'_>, | 73 | fmt: &mut fmt::Formatter<'_>, |
79 | ) -> Option<fmt::Result> { | 74 | ) -> Option<fmt::Result> { |
80 | None | 75 | tls::with_current_program(|prog| Some(prog?.debug_parameter(parameter, fmt))) |
81 | } | 76 | } |
82 | 77 | ||
83 | fn debug_goal(_goal: &Goal<Self>, _fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { | 78 | fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { |
84 | None | 79 | tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt))) |
85 | } | 80 | } |
86 | 81 | ||
87 | fn debug_goals( | 82 | fn debug_goals( |
88 | _goals: &chalk_ir::Goals<Self>, | 83 | goals: &chalk_ir::Goals<Interner>, |
89 | _fmt: &mut fmt::Formatter<'_>, | 84 | fmt: &mut fmt::Formatter<'_>, |
90 | ) -> Option<fmt::Result> { | 85 | ) -> Option<fmt::Result> { |
91 | None | 86 | tls::with_current_program(|prog| Some(prog?.debug_goals(goals, fmt))) |
92 | } | 87 | } |
93 | 88 | ||
94 | fn debug_program_clause_implication( | 89 | fn debug_program_clause_implication( |
95 | _pci: &chalk_ir::ProgramClauseImplication<Self>, | 90 | pci: &chalk_ir::ProgramClauseImplication<Interner>, |
96 | _fmt: &mut fmt::Formatter<'_>, | 91 | fmt: &mut fmt::Formatter<'_>, |
97 | ) -> Option<fmt::Result> { | 92 | ) -> Option<fmt::Result> { |
98 | None | 93 | tls::with_current_program(|prog| Some(prog?.debug_program_clause_implication(pci, fmt))) |
99 | } | 94 | } |
100 | 95 | ||
101 | fn debug_application_ty( | 96 | fn debug_application_ty( |
102 | _application_ty: &chalk_ir::ApplicationTy<Self>, | 97 | application_ty: &chalk_ir::ApplicationTy<Interner>, |
103 | _fmt: &mut fmt::Formatter<'_>, | 98 | fmt: &mut fmt::Formatter<'_>, |
104 | ) -> Option<fmt::Result> { | 99 | ) -> Option<fmt::Result> { |
105 | None | 100 | tls::with_current_program(|prog| Some(prog?.debug_application_ty(application_ty, fmt))) |
106 | } | 101 | } |
107 | 102 | ||
108 | fn debug_substitution( | 103 | fn debug_substitution( |
109 | _substitution: &chalk_ir::Substitution<Self>, | 104 | substitution: &chalk_ir::Substitution<Interner>, |
110 | _fmt: &mut fmt::Formatter<'_>, | 105 | fmt: &mut fmt::Formatter<'_>, |
111 | ) -> Option<fmt::Result> { | 106 | ) -> Option<fmt::Result> { |
112 | None | 107 | tls::with_current_program(|prog| Some(prog?.debug_substitution(substitution, fmt))) |
113 | } | 108 | } |
114 | 109 | ||
115 | fn debug_separator_trait_ref( | 110 | fn debug_separator_trait_ref( |
116 | _separator_trait_ref: &chalk_ir::SeparatorTraitRef<Self>, | 111 | separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>, |
117 | _fmt: &mut fmt::Formatter<'_>, | 112 | fmt: &mut fmt::Formatter<'_>, |
118 | ) -> Option<fmt::Result> { | 113 | ) -> Option<fmt::Result> { |
119 | None | 114 | tls::with_current_program(|prog| { |
115 | Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt)) | ||
116 | }) | ||
120 | } | 117 | } |
121 | 118 | ||
122 | fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> { | 119 | fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> { |
@@ -650,19 +647,22 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
650 | debug!("impls_for_trait {:?}", trait_id); | 647 | debug!("impls_for_trait {:?}", trait_id); |
651 | let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); | 648 | let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); |
652 | 649 | ||
650 | let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone()); | ||
651 | |||
652 | let self_ty_fp = TyFingerprint::for_impl(&ty); | ||
653 | |||
653 | // Note: Since we're using impls_for_trait, only impls where the trait | 654 | // Note: Since we're using impls_for_trait, only impls where the trait |
654 | // can be resolved should ever reach Chalk. `impl_datum` relies on that | 655 | // can be resolved should ever reach Chalk. `impl_datum` relies on that |
655 | // and will panic if the trait can't be resolved. | 656 | // and will panic if the trait can't be resolved. |
656 | let mut result: Vec<_> = self | 657 | let mut result: Vec<_> = self |
657 | .db | 658 | .db |
658 | .impls_for_trait(self.krate, trait_) | 659 | .impls_for_trait(self.krate, trait_, self_ty_fp) |
659 | .iter() | 660 | .iter() |
660 | .copied() | 661 | .copied() |
661 | .map(Impl::ImplDef) | 662 | .map(Impl::ImplDef) |
662 | .map(|impl_| impl_.to_chalk(self.db)) | 663 | .map(|impl_| impl_.to_chalk(self.db)) |
663 | .collect(); | 664 | .collect(); |
664 | 665 | ||
665 | let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone()); | ||
666 | let arg: Option<Ty> = | 666 | let arg: Option<Ty> = |
667 | parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref(&Interner).clone())); | 667 | parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref(&Interner).clone())); |
668 | 668 | ||
diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs new file mode 100644 index 000000000..d9bbb54a5 --- /dev/null +++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs | |||
@@ -0,0 +1,231 @@ | |||
1 | //! Implementation of Chalk debug helper functions using TLS. | ||
2 | use std::fmt; | ||
3 | |||
4 | use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplication, TypeName}; | ||
5 | |||
6 | use super::{from_chalk, Interner}; | ||
7 | use crate::{db::HirDatabase, CallableDef, TypeCtor}; | ||
8 | use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId}; | ||
9 | |||
10 | pub use unsafe_tls::{set_current_program, with_current_program}; | ||
11 | |||
12 | pub struct DebugContext<'a>(&'a (dyn HirDatabase + 'a)); | ||
13 | |||
14 | impl DebugContext<'_> { | ||
15 | pub fn debug_struct_id( | ||
16 | &self, | ||
17 | id: super::StructId, | ||
18 | f: &mut fmt::Formatter<'_>, | ||
19 | ) -> Result<(), fmt::Error> { | ||
20 | let type_ctor: TypeCtor = from_chalk(self.0, TypeName::Struct(id)); | ||
21 | match type_ctor { | ||
22 | TypeCtor::Bool => write!(f, "bool")?, | ||
23 | TypeCtor::Char => write!(f, "char")?, | ||
24 | TypeCtor::Int(t) => write!(f, "{}", t)?, | ||
25 | TypeCtor::Float(t) => write!(f, "{}", t)?, | ||
26 | TypeCtor::Str => write!(f, "str")?, | ||
27 | TypeCtor::Slice => write!(f, "slice")?, | ||
28 | TypeCtor::Array => write!(f, "array")?, | ||
29 | TypeCtor::RawPtr(m) => write!(f, "*{}", m.as_keyword_for_ptr())?, | ||
30 | TypeCtor::Ref(m) => write!(f, "&{}", m.as_keyword_for_ref())?, | ||
31 | TypeCtor::Never => write!(f, "!")?, | ||
32 | TypeCtor::Tuple { .. } => { | ||
33 | write!(f, "()")?; | ||
34 | } | ||
35 | TypeCtor::FnPtr { .. } => { | ||
36 | write!(f, "fn")?; | ||
37 | } | ||
38 | TypeCtor::FnDef(def) => { | ||
39 | let name = match def { | ||
40 | CallableDef::FunctionId(ff) => self.0.function_data(ff).name.clone(), | ||
41 | CallableDef::StructId(s) => self.0.struct_data(s).name.clone(), | ||
42 | CallableDef::EnumVariantId(e) => { | ||
43 | let enum_data = self.0.enum_data(e.parent); | ||
44 | enum_data.variants[e.local_id].name.clone() | ||
45 | } | ||
46 | }; | ||
47 | match def { | ||
48 | CallableDef::FunctionId(_) => write!(f, "{{fn {}}}", name)?, | ||
49 | CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => { | ||
50 | write!(f, "{{ctor {}}}", name)? | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | TypeCtor::Adt(def_id) => { | ||
55 | let name = match def_id { | ||
56 | AdtId::StructId(it) => self.0.struct_data(it).name.clone(), | ||
57 | AdtId::UnionId(it) => self.0.union_data(it).name.clone(), | ||
58 | AdtId::EnumId(it) => self.0.enum_data(it).name.clone(), | ||
59 | }; | ||
60 | write!(f, "{}", name)?; | ||
61 | } | ||
62 | TypeCtor::AssociatedType(type_alias) => { | ||
63 | let trait_ = match type_alias.lookup(self.0.upcast()).container { | ||
64 | AssocContainerId::TraitId(it) => it, | ||
65 | _ => panic!("not an associated type"), | ||
66 | }; | ||
67 | let trait_name = self.0.trait_data(trait_).name.clone(); | ||
68 | let name = self.0.type_alias_data(type_alias).name.clone(); | ||
69 | write!(f, "{}::{}", trait_name, name)?; | ||
70 | } | ||
71 | TypeCtor::Closure { def, expr } => { | ||
72 | write!(f, "{{closure {:?} in {:?}}}", expr.into_raw(), def)?; | ||
73 | } | ||
74 | } | ||
75 | Ok(()) | ||
76 | } | ||
77 | |||
78 | pub fn debug_trait_id( | ||
79 | &self, | ||
80 | id: super::TraitId, | ||
81 | fmt: &mut fmt::Formatter<'_>, | ||
82 | ) -> Result<(), fmt::Error> { | ||
83 | let trait_: hir_def::TraitId = from_chalk(self.0, id); | ||
84 | let trait_data = self.0.trait_data(trait_); | ||
85 | write!(fmt, "{}", trait_data.name) | ||
86 | } | ||
87 | |||
88 | pub fn debug_assoc_type_id( | ||
89 | &self, | ||
90 | id: super::AssocTypeId, | ||
91 | fmt: &mut fmt::Formatter<'_>, | ||
92 | ) -> Result<(), fmt::Error> { | ||
93 | let type_alias: TypeAliasId = from_chalk(self.0, id); | ||
94 | let type_alias_data = self.0.type_alias_data(type_alias); | ||
95 | let trait_ = match type_alias.lookup(self.0.upcast()).container { | ||
96 | AssocContainerId::TraitId(t) => t, | ||
97 | _ => panic!("associated type not in trait"), | ||
98 | }; | ||
99 | let trait_data = self.0.trait_data(trait_); | ||
100 | write!(fmt, "{}::{}", trait_data.name, type_alias_data.name) | ||
101 | } | ||
102 | |||
103 | pub fn debug_alias( | ||
104 | &self, | ||
105 | alias: &AliasTy<Interner>, | ||
106 | fmt: &mut fmt::Formatter<'_>, | ||
107 | ) -> Result<(), fmt::Error> { | ||
108 | let type_alias: TypeAliasId = from_chalk(self.0, alias.associated_ty_id); | ||
109 | let type_alias_data = self.0.type_alias_data(type_alias); | ||
110 | let trait_ = match type_alias.lookup(self.0.upcast()).container { | ||
111 | AssocContainerId::TraitId(t) => t, | ||
112 | _ => panic!("associated type not in trait"), | ||
113 | }; | ||
114 | let trait_data = self.0.trait_data(trait_); | ||
115 | let params = alias.substitution.parameters(&Interner); | ||
116 | write!( | ||
117 | fmt, | ||
118 | "<{:?} as {}<{:?}>>::{}", | ||
119 | ¶ms[0], | ||
120 | trait_data.name, | ||
121 | ¶ms[1..], | ||
122 | type_alias_data.name | ||
123 | ) | ||
124 | } | ||
125 | |||
126 | pub fn debug_ty( | ||
127 | &self, | ||
128 | ty: &chalk_ir::Ty<Interner>, | ||
129 | fmt: &mut fmt::Formatter<'_>, | ||
130 | ) -> Result<(), fmt::Error> { | ||
131 | write!(fmt, "{:?}", ty.data(&Interner)) | ||
132 | } | ||
133 | |||
134 | pub fn debug_lifetime( | ||
135 | &self, | ||
136 | lifetime: &Lifetime<Interner>, | ||
137 | fmt: &mut fmt::Formatter<'_>, | ||
138 | ) -> Result<(), fmt::Error> { | ||
139 | write!(fmt, "{:?}", lifetime.data(&Interner)) | ||
140 | } | ||
141 | |||
142 | pub fn debug_parameter( | ||
143 | &self, | ||
144 | parameter: &Parameter<Interner>, | ||
145 | fmt: &mut fmt::Formatter<'_>, | ||
146 | ) -> Result<(), fmt::Error> { | ||
147 | write!(fmt, "{:?}", parameter.data(&Interner).inner_debug()) | ||
148 | } | ||
149 | |||
150 | pub fn debug_goal( | ||
151 | &self, | ||
152 | goal: &Goal<Interner>, | ||
153 | fmt: &mut fmt::Formatter<'_>, | ||
154 | ) -> Result<(), fmt::Error> { | ||
155 | let goal_data = goal.data(&Interner); | ||
156 | write!(fmt, "{:?}", goal_data) | ||
157 | } | ||
158 | |||
159 | pub fn debug_goals( | ||
160 | &self, | ||
161 | goals: &Goals<Interner>, | ||
162 | fmt: &mut fmt::Formatter<'_>, | ||
163 | ) -> Result<(), fmt::Error> { | ||
164 | write!(fmt, "{:?}", goals.debug(&Interner)) | ||
165 | } | ||
166 | |||
167 | pub fn debug_program_clause_implication( | ||
168 | &self, | ||
169 | pci: &ProgramClauseImplication<Interner>, | ||
170 | fmt: &mut fmt::Formatter<'_>, | ||
171 | ) -> Result<(), fmt::Error> { | ||
172 | write!(fmt, "{:?}", pci.debug(&Interner)) | ||
173 | } | ||
174 | |||
175 | pub fn debug_application_ty( | ||
176 | &self, | ||
177 | application_ty: &chalk_ir::ApplicationTy<Interner>, | ||
178 | fmt: &mut fmt::Formatter<'_>, | ||
179 | ) -> Result<(), fmt::Error> { | ||
180 | write!(fmt, "{:?}", application_ty.debug(&Interner)) | ||
181 | } | ||
182 | |||
183 | pub fn debug_substitution( | ||
184 | &self, | ||
185 | substitution: &chalk_ir::Substitution<Interner>, | ||
186 | fmt: &mut fmt::Formatter<'_>, | ||
187 | ) -> Result<(), fmt::Error> { | ||
188 | write!(fmt, "{:?}", substitution.debug(&Interner)) | ||
189 | } | ||
190 | |||
191 | pub fn debug_separator_trait_ref( | ||
192 | &self, | ||
193 | separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>, | ||
194 | fmt: &mut fmt::Formatter<'_>, | ||
195 | ) -> Result<(), fmt::Error> { | ||
196 | write!(fmt, "{:?}", separator_trait_ref.debug(&Interner)) | ||
197 | } | ||
198 | } | ||
199 | |||
200 | mod unsafe_tls { | ||
201 | use super::DebugContext; | ||
202 | use crate::db::HirDatabase; | ||
203 | use scoped_tls::scoped_thread_local; | ||
204 | |||
205 | scoped_thread_local!(static PROGRAM: DebugContext); | ||
206 | |||
207 | pub fn with_current_program<R>( | ||
208 | op: impl for<'a> FnOnce(Option<&'a DebugContext<'a>>) -> R, | ||
209 | ) -> R { | ||
210 | if PROGRAM.is_set() { | ||
211 | PROGRAM.with(|prog| op(Some(prog))) | ||
212 | } else { | ||
213 | op(None) | ||
214 | } | ||
215 | } | ||
216 | |||
217 | pub fn set_current_program<OP, R>(p: &dyn HirDatabase, op: OP) -> R | ||
218 | where | ||
219 | OP: FnOnce() -> R, | ||
220 | { | ||
221 | let ctx = DebugContext(p); | ||
222 | // we're transmuting the lifetime in the DebugContext to static. This is | ||
223 | // fine because we only keep the reference for the lifetime of this | ||
224 | // function, *and* the only way to access the context is through | ||
225 | // `with_current_program`, which hides the lifetime through the `for` | ||
226 | // type. | ||
227 | let static_p: &DebugContext<'static> = | ||
228 | unsafe { std::mem::transmute::<&DebugContext, &DebugContext<'static>>(&ctx) }; | ||
229 | PROGRAM.set(static_p, || op()) | ||
230 | } | ||
231 | } | ||
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index 358b041aa..b5448af5c 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs | |||
@@ -72,7 +72,6 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: &Ty | |||
72 | } | 72 | } |
73 | for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() { | 73 | for (i, ty) in receiver.tuple_fields(ctx.db).into_iter().enumerate() { |
74 | // FIXME: Handle visibility | 74 | // FIXME: Handle visibility |
75 | // TODO: add the same behavior with type ? | ||
76 | acc.add_tuple_field(ctx, i, &ty); | 75 | acc.add_tuple_field(ctx, i, &ty); |
77 | } | 76 | } |
78 | } | 77 | } |
diff --git a/crates/ra_ide/src/completion/complete_fn_param.rs b/crates/ra_ide/src/completion/complete_fn_param.rs index 62ae5ccb4..f84b559fc 100644 --- a/crates/ra_ide/src/completion/complete_fn_param.rs +++ b/crates/ra_ide/src/completion/complete_fn_param.rs | |||
@@ -1,6 +1,9 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use ra_syntax::{ast, match_ast, AstNode}; | 3 | use ra_syntax::{ |
4 | ast::{self, ModuleItemOwner}, | ||
5 | match_ast, AstNode, | ||
6 | }; | ||
4 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::FxHashMap; |
5 | 8 | ||
6 | use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions}; | 9 | use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions}; |
@@ -16,11 +19,19 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) | |||
16 | 19 | ||
17 | let mut params = FxHashMap::default(); | 20 | let mut params = FxHashMap::default(); |
18 | for node in ctx.token.parent().ancestors() { | 21 | for node in ctx.token.parent().ancestors() { |
19 | match_ast! { | 22 | let items = match_ast! { |
20 | match node { | 23 | match node { |
21 | ast::SourceFile(it) => process(it, &mut params), | 24 | ast::SourceFile(it) => it.items(), |
22 | ast::ItemList(it) => process(it, &mut params), | 25 | ast::ItemList(it) => it.items(), |
23 | _ => (), | 26 | _ => continue, |
27 | } | ||
28 | }; | ||
29 | for item in items { | ||
30 | if let ast::ModuleItem::FnDef(func) = item { | ||
31 | func.param_list().into_iter().flat_map(|it| it.params()).for_each(|param| { | ||
32 | let text = param.syntax().text().to_string(); | ||
33 | params.entry(text).or_insert((0, param)).0 += 1; | ||
34 | }) | ||
24 | } | 35 | } |
25 | } | 36 | } |
26 | } | 37 | } |
@@ -39,15 +50,6 @@ pub(super) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext) | |||
39 | .lookup_by(lookup) | 50 | .lookup_by(lookup) |
40 | .add_to(acc) | 51 | .add_to(acc) |
41 | }); | 52 | }); |
42 | |||
43 | fn process<N: ast::FnDefOwner>(node: N, params: &mut FxHashMap<String, (u32, ast::Param)>) { | ||
44 | node.functions().filter_map(|it| it.param_list()).flat_map(|it| it.params()).for_each( | ||
45 | |param| { | ||
46 | let text = param.syntax().text().to_string(); | ||
47 | params.entry(text).or_insert((0, param)).0 += 1; | ||
48 | }, | ||
49 | ) | ||
50 | } | ||
51 | } | 53 | } |
52 | 54 | ||
53 | #[cfg(test)] | 55 | #[cfg(test)] |
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index ded1ff3bc..fab02945c 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs | |||
@@ -35,7 +35,7 @@ use hir::{self, Docs, HasSource}; | |||
35 | use ra_assists::utils::get_missing_impl_items; | 35 | use ra_assists::utils::get_missing_impl_items; |
36 | use ra_syntax::{ | 36 | use ra_syntax::{ |
37 | ast::{self, edit, ImplDef}, | 37 | ast::{self, edit, ImplDef}, |
38 | AstNode, SyntaxKind, SyntaxNode, TextRange, | 38 | AstNode, SyntaxKind, SyntaxNode, TextRange, T, |
39 | }; | 39 | }; |
40 | use ra_text_edit::TextEdit; | 40 | use ra_text_edit::TextEdit; |
41 | 41 | ||
@@ -204,7 +204,7 @@ fn make_const_compl_syntax(const_: &ast::ConstDef) -> String { | |||
204 | let end = const_ | 204 | let end = const_ |
205 | .syntax() | 205 | .syntax() |
206 | .children_with_tokens() | 206 | .children_with_tokens() |
207 | .find(|s| s.kind() == SyntaxKind::SEMI || s.kind() == SyntaxKind::EQ) | 207 | .find(|s| s.kind() == T![;] || s.kind() == T![=]) |
208 | .map_or(const_end, |f| f.text_range().start()); | 208 | .map_or(const_end, |f| f.text_range().start()); |
209 | 209 | ||
210 | let len = end - start; | 210 | let len = end - start; |
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs index efde9bf73..0b0da6ee4 100644 --- a/crates/ra_ide/src/completion/complete_unqualified_path.rs +++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use crate::completion::{CompletionContext, Completions}; | 3 | use crate::completion::{CompletionContext, Completions}; |
4 | 4 | ||
5 | pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 5 | pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { |
6 | if !(ctx.is_trivial_path && !ctx.is_pat_binding_or_const) { | 6 | if !(ctx.is_trivial_path && !ctx.is_pat_binding_or_const && !ctx.record_lit_syntax.is_some()) { |
7 | return; | 7 | return; |
8 | } | 8 | } |
9 | 9 | ||
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index fddaf21e4..eb8016dd1 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs | |||
@@ -1,13 +1,11 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use hir::{db::HirDatabase, Semantics, SemanticsScope}; | 3 | use hir::{Semantics, SemanticsScope}; |
4 | use ra_db::SourceDatabase; | 4 | use ra_db::SourceDatabase; |
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::{ | 6 | use ra_syntax::{ |
7 | algo::{find_covering_element, find_node_at_offset}, | 7 | algo::{find_covering_element, find_node_at_offset}, |
8 | ast, | 8 | ast, AstNode, |
9 | ast::ArgListOwner, | ||
10 | AstNode, | ||
11 | SyntaxKind::*, | 9 | SyntaxKind::*, |
12 | SyntaxNode, SyntaxToken, TextRange, TextUnit, | 10 | SyntaxNode, SyntaxToken, TextRange, TextUnit, |
13 | }; | 11 | }; |
@@ -196,7 +194,10 @@ impl<'a> CompletionContext<'a> { | |||
196 | if let Some(name) = find_node_at_offset::<ast::Name>(&file_with_fake_ident, offset) { | 194 | if let Some(name) = find_node_at_offset::<ast::Name>(&file_with_fake_ident, offset) { |
197 | if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) { | 195 | if let Some(bind_pat) = name.syntax().ancestors().find_map(ast::BindPat::cast) { |
198 | self.is_pat_binding_or_const = true; | 196 | self.is_pat_binding_or_const = true; |
199 | if bind_pat.has_at() || bind_pat.is_ref() || bind_pat.is_mutable() { | 197 | if bind_pat.at_token().is_some() |
198 | || bind_pat.ref_token().is_some() | ||
199 | || bind_pat.mut_token().is_some() | ||
200 | { | ||
200 | self.is_pat_binding_or_const = false; | 201 | self.is_pat_binding_or_const = false; |
201 | } | 202 | } |
202 | if bind_pat.syntax().parent().and_then(ast::RecordFieldPatList::cast).is_some() { | 203 | if bind_pat.syntax().parent().and_then(ast::RecordFieldPatList::cast).is_some() { |
@@ -230,7 +231,7 @@ impl<'a> CompletionContext<'a> { | |||
230 | self.name_ref_syntax = | 231 | self.name_ref_syntax = |
231 | find_node_at_offset(&original_file, name_ref.syntax().text_range().start()); | 232 | find_node_at_offset(&original_file, name_ref.syntax().text_range().start()); |
232 | let name_range = name_ref.syntax().text_range(); | 233 | let name_range = name_ref.syntax().text_range(); |
233 | if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() { | 234 | if ast::RecordField::for_field_name(&name_ref).is_some() { |
234 | self.record_lit_syntax = | 235 | self.record_lit_syntax = |
235 | self.sema.find_node_at_offset_with_macros(&original_file, offset); | 236 | self.sema.find_node_at_offset_with_macros(&original_file, offset); |
236 | } | 237 | } |
diff --git a/crates/ra_ide/src/display/function_signature.rs b/crates/ra_ide/src/display/function_signature.rs index e58a78271..2d175882b 100644 --- a/crates/ra_ide/src/display/function_signature.rs +++ b/crates/ra_ide/src/display/function_signature.rs | |||
@@ -69,7 +69,13 @@ impl FunctionSignature { | |||
69 | for field in st.fields(db).into_iter() { | 69 | for field in st.fields(db).into_iter() { |
70 | let ty = field.signature_ty(db); | 70 | let ty = field.signature_ty(db); |
71 | let raw_param = format!("{}", ty.display(db)); | 71 | let raw_param = format!("{}", ty.display(db)); |
72 | parameter_types.push(raw_param.split(':').nth(1).unwrap()[1..].to_string()); | 72 | |
73 | if let Some(param_type) = raw_param.split(':').nth(1) { | ||
74< |