diff options
-rw-r--r-- | Cargo.lock | 34 | ||||
-rw-r--r-- | crates/assists/src/handlers/ignore_test.rs | 83 | ||||
-rw-r--r-- | crates/completion/src/completions/unqualified_path.rs | 4 | ||||
-rw-r--r-- | crates/completion/src/config.rs | 2 | ||||
-rw-r--r-- | crates/completion/src/lib.rs | 7 | ||||
-rw-r--r-- | crates/flycheck/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/hir/src/db.rs | 2 | ||||
-rw-r--r-- | crates/hir/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/hir_expand/src/db.rs | 141 | ||||
-rw-r--r-- | crates/hir_expand/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/match_check.rs | 248 | ||||
-rw-r--r-- | crates/hir_ty/src/infer/pat.rs | 46 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/patterns.rs | 95 | ||||
-rw-r--r-- | crates/ide/src/status.rs | 10 | ||||
-rw-r--r-- | crates/ide_db/src/apply_change.rs | 4 | ||||
-rw-r--r-- | crates/ide_db/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/proc_macro_srv/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/project_model/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 3 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 8 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 21 | ||||
-rw-r--r-- | editors/code/package.json | 8 |
23 files changed, 544 insertions, 188 deletions
diff --git a/Cargo.lock b/Cargo.lock index edadd1057..051d9e734 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -81,9 +81,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" | |||
81 | 81 | ||
82 | [[package]] | 82 | [[package]] |
83 | name = "backtrace" | 83 | name = "backtrace" |
84 | version = "0.3.54" | 84 | version = "0.3.55" |
85 | source = "registry+https://github.com/rust-lang/crates.io-index" | 85 | source = "registry+https://github.com/rust-lang/crates.io-index" |
86 | checksum = "2baad346b2d4e94a24347adeee9c7a93f412ee94b9cc26e5b59dea23848e9f28" | 86 | checksum = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598" |
87 | dependencies = [ | 87 | dependencies = [ |
88 | "addr2line", | 88 | "addr2line", |
89 | "cfg-if 1.0.0", | 89 | "cfg-if 1.0.0", |
@@ -139,9 +139,9 @@ dependencies = [ | |||
139 | 139 | ||
140 | [[package]] | 140 | [[package]] |
141 | name = "cc" | 141 | name = "cc" |
142 | version = "1.0.63" | 142 | version = "1.0.65" |
143 | source = "registry+https://github.com/rust-lang/crates.io-index" | 143 | source = "registry+https://github.com/rust-lang/crates.io-index" |
144 | checksum = "ad9c6140b5a2c7db40ea56eb1821245e5362b44385c05b76288b1a599934ac87" | 144 | checksum = "95752358c8f7552394baf48cd82695b345628ad3f170d607de3ca03b8dacca15" |
145 | 145 | ||
146 | [[package]] | 146 | [[package]] |
147 | name = "cfg" | 147 | name = "cfg" |
@@ -865,9 +865,9 @@ dependencies = [ | |||
865 | 865 | ||
866 | [[package]] | 866 | [[package]] |
867 | name = "lsp-types" | 867 | name = "lsp-types" |
868 | version = "0.83.1" | 868 | version = "0.84.0" |
869 | source = "registry+https://github.com/rust-lang/crates.io-index" | 869 | source = "registry+https://github.com/rust-lang/crates.io-index" |
870 | checksum = "c4e79f39834b97271f9f5ecec573e42c7d9c5bdbd2620b30a851054ece6aab6d" | 870 | checksum = "3b95be71fe205e44de754185bcf86447b65813ce1ceb298f8d3793ade5fff08d" |
871 | dependencies = [ | 871 | dependencies = [ |
872 | "base64", | 872 | "base64", |
873 | "bitflags", | 873 | "bitflags", |
@@ -1072,9 +1072,9 @@ checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" | |||
1072 | 1072 | ||
1073 | [[package]] | 1073 | [[package]] |
1074 | name = "oorandom" | 1074 | name = "oorandom" |
1075 | version = "11.1.2" | 1075 | version = "11.1.3" |
1076 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1076 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1077 | checksum = "a170cebd8021a008ea92e4db85a72f80b35df514ec664b296fdcbb654eac0b2c" | 1077 | checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" |
1078 | 1078 | ||
1079 | [[package]] | 1079 | [[package]] |
1080 | name = "parking_lot" | 1080 | name = "parking_lot" |
@@ -1165,9 +1165,9 @@ checksum = "28b9b4df73455c861d7cbf8be42f01d3b373ed7f02e378d55fa84eafc6f638b1" | |||
1165 | 1165 | ||
1166 | [[package]] | 1166 | [[package]] |
1167 | name = "pin-project-lite" | 1167 | name = "pin-project-lite" |
1168 | version = "0.1.11" | 1168 | version = "0.2.0" |
1169 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1169 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1170 | checksum = "c917123afa01924fc84bb20c4c03f004d9c38e5127e3c039bbf7f4b9c76a2f6b" | 1170 | checksum = "6b063f57ec186e6140e2b8b6921e5f1bd89c7356dda5b33acc5401203ca6131c" |
1171 | 1171 | ||
1172 | [[package]] | 1172 | [[package]] |
1173 | name = "plain" | 1173 | name = "plain" |
@@ -1627,9 +1627,9 @@ version = "0.0.0" | |||
1627 | 1627 | ||
1628 | [[package]] | 1628 | [[package]] |
1629 | name = "syn" | 1629 | name = "syn" |
1630 | version = "1.0.48" | 1630 | version = "1.0.51" |
1631 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1631 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1632 | checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" | 1632 | checksum = "3b4f34193997d92804d359ed09953e25d5138df6bcc055a71bf68ee89fdf9223" |
1633 | dependencies = [ | 1633 | dependencies = [ |
1634 | "proc-macro2", | 1634 | "proc-macro2", |
1635 | "quote", | 1635 | "quote", |
@@ -1740,9 +1740,9 @@ dependencies = [ | |||
1740 | 1740 | ||
1741 | [[package]] | 1741 | [[package]] |
1742 | name = "tinyvec" | 1742 | name = "tinyvec" |
1743 | version = "1.0.1" | 1743 | version = "1.1.0" |
1744 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1744 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1745 | checksum = "b78a366903f506d2ad52ca8dc552102ffdd3e937ba8a227f024dc1d1eae28575" | 1745 | checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" |
1746 | dependencies = [ | 1746 | dependencies = [ |
1747 | "tinyvec_macros", | 1747 | "tinyvec_macros", |
1748 | ] | 1748 | ] |
@@ -1762,11 +1762,11 @@ dependencies = [ | |||
1762 | 1762 | ||
1763 | [[package]] | 1763 | [[package]] |
1764 | name = "tracing" | 1764 | name = "tracing" |
1765 | version = "0.1.21" | 1765 | version = "0.1.22" |
1766 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1766 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1767 | checksum = "b0987850db3733619253fe60e17cb59b82d37c7e6c0236bb81e4d6b87c879f27" | 1767 | checksum = "9f47026cdc4080c07e49b37087de021820269d996f581aac150ef9e5583eefe3" |
1768 | dependencies = [ | 1768 | dependencies = [ |
1769 | "cfg-if 0.1.10", | 1769 | "cfg-if 1.0.0", |
1770 | "pin-project-lite", | 1770 | "pin-project-lite", |
1771 | "tracing-attributes", | 1771 | "tracing-attributes", |
1772 | "tracing-core", | 1772 | "tracing-core", |
diff --git a/crates/assists/src/handlers/ignore_test.rs b/crates/assists/src/handlers/ignore_test.rs index d2339184f..5096a0005 100644 --- a/crates/assists/src/handlers/ignore_test.rs +++ b/crates/assists/src/handlers/ignore_test.rs | |||
@@ -1,4 +1,7 @@ | |||
1 | use syntax::{ast, AstNode}; | 1 | use syntax::{ |
2 | ast::{self, AttrsOwner}, | ||
3 | AstNode, AstToken, | ||
4 | }; | ||
2 | 5 | ||
3 | use crate::{utils::test_related_attribute, AssistContext, AssistId, AssistKind, Assists}; | 6 | use crate::{utils::test_related_attribute, AssistContext, AssistId, AssistKind, Assists}; |
4 | 7 | ||
@@ -25,10 +28,76 @@ pub(crate) fn ignore_test(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
25 | let func = attr.syntax().parent().and_then(ast::Fn::cast)?; | 28 | let func = attr.syntax().parent().and_then(ast::Fn::cast)?; |
26 | let attr = test_related_attribute(&func)?; | 29 | let attr = test_related_attribute(&func)?; |
27 | 30 | ||
28 | acc.add( | 31 | match has_ignore_attribute(&func) { |
29 | AssistId("ignore_test", AssistKind::None), | 32 | None => acc.add( |
30 | "Ignore this test", | 33 | AssistId("ignore_test", AssistKind::None), |
31 | attr.syntax().text_range(), | 34 | "Ignore this test", |
32 | |builder| builder.insert(attr.syntax().text_range().end(), &format!("\n#[ignore]")), | 35 | attr.syntax().text_range(), |
33 | ) | 36 | |builder| builder.insert(attr.syntax().text_range().end(), &format!("\n#[ignore]")), |
37 | ), | ||
38 | Some(ignore_attr) => acc.add( | ||
39 | AssistId("unignore_test", AssistKind::None), | ||
40 | "Re-enable this test", | ||
41 | ignore_attr.syntax().text_range(), | ||
42 | |builder| { | ||
43 | builder.delete(ignore_attr.syntax().text_range()); | ||
44 | let whitespace = ignore_attr | ||
45 | .syntax() | ||
46 | .next_sibling_or_token() | ||
47 | .and_then(|x| x.into_token()) | ||
48 | .and_then(ast::Whitespace::cast); | ||
49 | if let Some(whitespace) = whitespace { | ||
50 | builder.delete(whitespace.syntax().text_range()); | ||
51 | } | ||
52 | }, | ||
53 | ), | ||
54 | } | ||
55 | } | ||
56 | |||
57 | fn has_ignore_attribute(fn_def: &ast::Fn) -> Option<ast::Attr> { | ||
58 | fn_def.attrs().find_map(|attr| { | ||
59 | if attr.path()?.syntax().text() == "ignore" { | ||
60 | Some(attr) | ||
61 | } else { | ||
62 | None | ||
63 | } | ||
64 | }) | ||
65 | } | ||
66 | |||
67 | #[cfg(test)] | ||
68 | mod tests { | ||
69 | use super::ignore_test; | ||
70 | use crate::tests::check_assist; | ||
71 | |||
72 | #[test] | ||
73 | fn test_base_case() { | ||
74 | check_assist( | ||
75 | ignore_test, | ||
76 | r#" | ||
77 | #[test<|>] | ||
78 | fn test() {} | ||
79 | "#, | ||
80 | r#" | ||
81 | #[test] | ||
82 | #[ignore] | ||
83 | fn test() {} | ||
84 | "#, | ||
85 | ) | ||
86 | } | ||
87 | |||
88 | #[test] | ||
89 | fn test_unignore() { | ||
90 | check_assist( | ||
91 | ignore_test, | ||
92 | r#" | ||
93 | #[test<|>] | ||
94 | #[ignore] | ||
95 | fn test() {} | ||
96 | "#, | ||
97 | r#" | ||
98 | #[test] | ||
99 | fn test() {} | ||
100 | "#, | ||
101 | ) | ||
102 | } | ||
34 | } | 103 | } |
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs index f452c98e4..3bd776905 100644 --- a/crates/completion/src/completions/unqualified_path.rs +++ b/crates/completion/src/completions/unqualified_path.rs | |||
@@ -44,7 +44,9 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
44 | acc.add_resolution(ctx, name.to_string(), &res) | 44 | acc.add_resolution(ctx, name.to_string(), &res) |
45 | }); | 45 | }); |
46 | 46 | ||
47 | fuzzy_completion(acc, ctx).unwrap_or_default() | 47 | if ctx.config.enable_experimental_completions { |
48 | fuzzy_completion(acc, ctx).unwrap_or_default() | ||
49 | } | ||
48 | } | 50 | } |
49 | 51 | ||
50 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { | 52 | fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { |
diff --git a/crates/completion/src/config.rs b/crates/completion/src/config.rs index 82874ff25..f50735372 100644 --- a/crates/completion/src/config.rs +++ b/crates/completion/src/config.rs | |||
@@ -9,6 +9,7 @@ use assists::utils::MergeBehaviour; | |||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
10 | pub struct CompletionConfig { | 10 | pub struct CompletionConfig { |
11 | pub enable_postfix_completions: bool, | 11 | pub enable_postfix_completions: bool, |
12 | pub enable_experimental_completions: bool, | ||
12 | pub add_call_parenthesis: bool, | 13 | pub add_call_parenthesis: bool, |
13 | pub add_call_argument_snippets: bool, | 14 | pub add_call_argument_snippets: bool, |
14 | pub snippet_cap: Option<SnippetCap>, | 15 | pub snippet_cap: Option<SnippetCap>, |
@@ -30,6 +31,7 @@ impl Default for CompletionConfig { | |||
30 | fn default() -> Self { | 31 | fn default() -> Self { |
31 | CompletionConfig { | 32 | CompletionConfig { |
32 | enable_postfix_completions: true, | 33 | enable_postfix_completions: true, |
34 | enable_experimental_completions: true, | ||
33 | add_call_parenthesis: true, | 35 | add_call_parenthesis: true, |
34 | add_call_argument_snippets: true, | 36 | add_call_argument_snippets: true, |
35 | snippet_cap: Some(SnippetCap { _private: () }), | 37 | snippet_cap: Some(SnippetCap { _private: () }), |
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs index cb6e0554e..aecc1378b 100644 --- a/crates/completion/src/lib.rs +++ b/crates/completion/src/lib.rs | |||
@@ -67,6 +67,13 @@ pub use crate::{ | |||
67 | // fn test_name() {} | 67 | // fn test_name() {} |
68 | // } | 68 | // } |
69 | // ``` | 69 | // ``` |
70 | // | ||
71 | // And experimental completions, enabled with the `rust-analyzer.completion.enableExperimental` setting. | ||
72 | // This flag enables or disables: | ||
73 | // | ||
74 | // - Auto import: additional completion options with automatic `use` import and options from all project importable items, matched for the input | ||
75 | // | ||
76 | // Experimental completions might cause issues with performance and completion list look. | ||
70 | 77 | ||
71 | /// Main entry point for completion. We run completion as a two-phase process. | 78 | /// Main entry point for completion. We run completion as a two-phase process. |
72 | /// | 79 | /// |
diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml index 44499bc79..3d9436d69 100644 --- a/crates/flycheck/Cargo.toml +++ b/crates/flycheck/Cargo.toml | |||
@@ -12,7 +12,7 @@ doctest = false | |||
12 | [dependencies] | 12 | [dependencies] |
13 | crossbeam-channel = "0.5.0" | 13 | crossbeam-channel = "0.5.0" |
14 | log = "0.4.8" | 14 | log = "0.4.8" |
15 | cargo_metadata = "0.12.0" | 15 | cargo_metadata = "=0.12.0" |
16 | serde_json = "1.0.48" | 16 | serde_json = "1.0.48" |
17 | jod-thread = "0.1.1" | 17 | jod-thread = "0.1.1" |
18 | 18 | ||
diff --git a/crates/hir/src/db.rs b/crates/hir/src/db.rs index 07333c453..8c767b249 100644 --- a/crates/hir/src/db.rs +++ b/crates/hir/src/db.rs | |||
@@ -11,7 +11,7 @@ pub use hir_def::db::{ | |||
11 | }; | 11 | }; |
12 | pub use hir_expand::db::{ | 12 | pub use hir_expand::db::{ |
13 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery, | 13 | AstDatabase, AstDatabaseStorage, AstIdMapQuery, InternEagerExpansionQuery, InternMacroQuery, |
14 | MacroArgTextQuery, MacroDefQuery, MacroExpandQuery, ParseMacroQuery, | 14 | MacroArgTextQuery, MacroDefQuery, MacroExpandQuery, ParseMacroExpansionQuery, |
15 | }; | 15 | }; |
16 | pub use hir_ty::db::*; | 16 | pub use hir_ty::db::*; |
17 | 17 | ||
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 5fea25ef1..ed110329d 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -57,8 +57,8 @@ pub use hir_def::{ | |||
57 | visibility::Visibility, | 57 | visibility::Visibility, |
58 | }; | 58 | }; |
59 | pub use hir_expand::{ | 59 | pub use hir_expand::{ |
60 | name::known, name::AsName, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, | 60 | db::MacroResult, name::known, name::AsName, name::Name, HirFileId, InFile, MacroCallId, |
61 | /* FIXME */ MacroDefId, MacroFile, Origin, | 61 | MacroCallLoc, /* FIXME */ MacroDefId, MacroFile, Origin, |
62 | }; | 62 | }; |
63 | pub use hir_ty::display::HirDisplay; | 63 | pub use hir_ty::display::HirDisplay; |
64 | 64 | ||
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index ade57ac1b..a9099eb22 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -13,6 +13,19 @@ use crate::{ | |||
13 | MacroFile, ProcMacroExpander, | 13 | MacroFile, ProcMacroExpander, |
14 | }; | 14 | }; |
15 | 15 | ||
16 | /// A result of some macro expansion. | ||
17 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
18 | pub struct MacroResult<T> { | ||
19 | /// The result of the expansion. Might be `None` when error recovery was impossible and no | ||
20 | /// usable result was produced. | ||
21 | pub value: Option<T>, | ||
22 | |||
23 | /// The error that occurred during expansion or processing. | ||
24 | /// | ||
25 | /// Since we do error recovery, getting an error here does not mean that `value` will be absent. | ||
26 | pub error: Option<String>, | ||
27 | } | ||
28 | |||
16 | #[derive(Debug, Clone, Eq, PartialEq)] | 29 | #[derive(Debug, Clone, Eq, PartialEq)] |
17 | pub enum TokenExpander { | 30 | pub enum TokenExpander { |
18 | MacroRules(mbe::MacroRules), | 31 | MacroRules(mbe::MacroRules), |
@@ -75,9 +88,11 @@ pub trait AstDatabase: SourceDatabase { | |||
75 | #[salsa::transparent] | 88 | #[salsa::transparent] |
76 | fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>; | 89 | fn macro_arg(&self, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>>; |
77 | fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>; | 90 | fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>; |
78 | fn parse_macro(&self, macro_file: MacroFile) | 91 | fn parse_macro_expansion( |
79 | -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>; | 92 | &self, |
80 | fn macro_expand(&self, macro_call: MacroCallId) -> (Option<Arc<tt::Subtree>>, Option<String>); | 93 | macro_file: MacroFile, |
94 | ) -> MacroResult<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>; | ||
95 | fn macro_expand(&self, macro_call: MacroCallId) -> MacroResult<Arc<tt::Subtree>>; | ||
81 | 96 | ||
82 | #[salsa::interned] | 97 | #[salsa::interned] |
83 | fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId; | 98 | fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId; |
@@ -85,6 +100,20 @@ pub trait AstDatabase: SourceDatabase { | |||
85 | fn expand_proc_macro(&self, call: MacroCallId) -> Result<tt::Subtree, mbe::ExpandError>; | 100 | fn expand_proc_macro(&self, call: MacroCallId) -> Result<tt::Subtree, mbe::ExpandError>; |
86 | } | 101 | } |
87 | 102 | ||
103 | impl<T> MacroResult<T> { | ||
104 | fn error(message: String) -> Self { | ||
105 | Self { value: None, error: Some(message) } | ||
106 | } | ||
107 | |||
108 | fn map<U>(self, f: impl FnOnce(T) -> U) -> MacroResult<U> { | ||
109 | MacroResult { value: self.value.map(f), error: self.error } | ||
110 | } | ||
111 | |||
112 | fn drop_value<U>(self) -> MacroResult<U> { | ||
113 | MacroResult { value: None, error: self.error } | ||
114 | } | ||
115 | } | ||
116 | |||
88 | /// This expands the given macro call, but with different arguments. This is | 117 | /// This expands the given macro call, but with different arguments. This is |
89 | /// used for completion, where we want to see what 'would happen' if we insert a | 118 | /// used for completion, where we want to see what 'would happen' if we insert a |
90 | /// token. The `token_to_map` mapped down into the expansion, with the mapped | 119 | /// token. The `token_to_map` mapped down into the expansion, with the mapped |
@@ -102,23 +131,20 @@ pub fn expand_hypothetical( | |||
102 | let token_id = tmap_1.token_by_range(range)?; | 131 | let token_id = tmap_1.token_by_range(range)?; |
103 | let macro_def = expander(db, actual_macro_call)?; | 132 | let macro_def = expander(db, actual_macro_call)?; |
104 | let (node, tmap_2) = | 133 | let (node, tmap_2) = |
105 | parse_macro_with_arg(db, macro_file, Some(std::sync::Arc::new((tt, tmap_1))))?; | 134 | parse_macro_with_arg(db, macro_file, Some(std::sync::Arc::new((tt, tmap_1)))).value?; |
106 | let token_id = macro_def.0.map_id_down(token_id); | 135 | let token_id = macro_def.0.map_id_down(token_id); |
107 | let range = tmap_2.range_by_token(token_id)?.by_kind(token_to_map.kind())?; | 136 | let range = tmap_2.range_by_token(token_id)?.by_kind(token_to_map.kind())?; |
108 | let token = syntax::algo::find_covering_element(&node.syntax_node(), range).into_token()?; | 137 | let token = syntax::algo::find_covering_element(&node.syntax_node(), range).into_token()?; |
109 | Some((node.syntax_node(), token)) | 138 | Some((node.syntax_node(), token)) |
110 | } | 139 | } |
111 | 140 | ||
112 | pub(crate) fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> { | 141 | fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> { |
113 | let map = | 142 | let map = |
114 | db.parse_or_expand(file_id).map_or_else(AstIdMap::default, |it| AstIdMap::from_source(&it)); | 143 | db.parse_or_expand(file_id).map_or_else(AstIdMap::default, |it| AstIdMap::from_source(&it)); |
115 | Arc::new(map) | 144 | Arc::new(map) |
116 | } | 145 | } |
117 | 146 | ||
118 | pub(crate) fn macro_def( | 147 | fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { |
119 | db: &dyn AstDatabase, | ||
120 | id: MacroDefId, | ||
121 | ) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { | ||
122 | match id.kind { | 148 | match id.kind { |
123 | MacroDefKind::Declarative => { | 149 | MacroDefKind::Declarative => { |
124 | let macro_call = id.ast_id?.to_node(db); | 150 | let macro_call = id.ast_id?.to_node(db); |
@@ -149,7 +175,7 @@ pub(crate) fn macro_def( | |||
149 | } | 175 | } |
150 | } | 176 | } |
151 | 177 | ||
152 | pub(crate) fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> { | 178 | fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> { |
153 | let id = match id { | 179 | let id = match id { |
154 | MacroCallId::LazyMacro(id) => id, | 180 | MacroCallId::LazyMacro(id) => id, |
155 | MacroCallId::EagerMacro(_id) => { | 181 | MacroCallId::EagerMacro(_id) => { |
@@ -162,19 +188,13 @@ pub(crate) fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<Gr | |||
162 | Some(arg.green().clone()) | 188 | Some(arg.green().clone()) |
163 | } | 189 | } |
164 | 190 | ||
165 | pub(crate) fn macro_arg( | 191 | fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { |
166 | db: &dyn AstDatabase, | ||
167 | id: MacroCallId, | ||
168 | ) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { | ||
169 | let arg = db.macro_arg_text(id)?; | 192 | let arg = db.macro_arg_text(id)?; |
170 | let (tt, tmap) = mbe::syntax_node_to_token_tree(&SyntaxNode::new_root(arg))?; | 193 | let (tt, tmap) = mbe::syntax_node_to_token_tree(&SyntaxNode::new_root(arg))?; |
171 | Some(Arc::new((tt, tmap))) | 194 | Some(Arc::new((tt, tmap))) |
172 | } | 195 | } |
173 | 196 | ||
174 | pub(crate) fn macro_expand( | 197 | fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> MacroResult<Arc<tt::Subtree>> { |
175 | db: &dyn AstDatabase, | ||
176 | id: MacroCallId, | ||
177 | ) -> (Option<Arc<tt::Subtree>>, Option<String>) { | ||
178 | macro_expand_with_arg(db, id, None) | 198 | macro_expand_with_arg(db, id, None) |
179 | } | 199 | } |
180 | 200 | ||
@@ -195,17 +215,19 @@ fn macro_expand_with_arg( | |||
195 | db: &dyn AstDatabase, | 215 | db: &dyn AstDatabase, |
196 | id: MacroCallId, | 216 | id: MacroCallId, |
197 | arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>, | 217 | arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>, |
198 | ) -> (Option<Arc<tt::Subtree>>, Option<String>) { | 218 | ) -> MacroResult<Arc<tt::Subtree>> { |
199 | let lazy_id = match id { | 219 | let lazy_id = match id { |
200 | MacroCallId::LazyMacro(id) => id, | 220 | MacroCallId::LazyMacro(id) => id, |
201 | MacroCallId::EagerMacro(id) => { | 221 | MacroCallId::EagerMacro(id) => { |
202 | if arg.is_some() { | 222 | if arg.is_some() { |
203 | return ( | 223 | return MacroResult::error( |
204 | None, | 224 | "hypothetical macro expansion not implemented for eager macro".to_owned(), |
205 | Some("hypothetical macro expansion not implemented for eager macro".to_owned()), | ||
206 | ); | 225 | ); |
207 | } else { | 226 | } else { |
208 | return (Some(db.lookup_intern_eager_expansion(id).subtree), None); | 227 | return MacroResult { |
228 | value: Some(db.lookup_intern_eager_expansion(id).subtree), | ||
229 | error: None, | ||
230 | }; | ||
209 | } | 231 | } |
210 | } | 232 | } |
211 | }; | 233 | }; |
@@ -213,23 +235,24 @@ fn macro_expand_with_arg( | |||
213 | let loc = db.lookup_intern_macro(lazy_id); | 235 | let loc = db.lookup_intern_macro(lazy_id); |
214 | let macro_arg = match arg.or_else(|| db.macro_arg(id)) { | 236 | let macro_arg = match arg.or_else(|| db.macro_arg(id)) { |
215 | Some(it) => it, | 237 | Some(it) => it, |
216 | None => return (None, Some("Fail to args in to tt::TokenTree".into())), | 238 | None => return MacroResult::error("Fail to args in to tt::TokenTree".into()), |
217 | }; | 239 | }; |
218 | 240 | ||
219 | let macro_rules = match db.macro_def(loc.def) { | 241 | let macro_rules = match db.macro_def(loc.def) { |
220 | Some(it) => it, | 242 | Some(it) => it, |
221 | None => return (None, Some("Fail to find macro definition".into())), | 243 | None => return MacroResult::error("Fail to find macro definition".into()), |
222 | }; | 244 | }; |
223 | let ExpandResult(tt, err) = macro_rules.0.expand(db, lazy_id, ¯o_arg.0); | 245 | let ExpandResult(tt, err) = macro_rules.0.expand(db, lazy_id, ¯o_arg.0); |
224 | // Set a hard limit for the expanded tt | 246 | // Set a hard limit for the expanded tt |
225 | let count = tt.count(); | 247 | let count = tt.count(); |
226 | if count > 262144 { | 248 | if count > 262144 { |
227 | return (None, Some(format!("Total tokens count exceed limit : count = {}", count))); | 249 | return MacroResult::error(format!("Total tokens count exceed limit : count = {}", count)); |
228 | } | 250 | } |
229 | (Some(Arc::new(tt)), err.map(|e| format!("{:?}", e))) | 251 | |
252 | MacroResult { value: Some(Arc::new(tt)), error: err.map(|e| format!("{:?}", e)) } | ||
230 | } | 253 | } |
231 | 254 | ||
232 | pub(crate) fn expand_proc_macro( | 255 | fn expand_proc_macro( |
233 | db: &dyn AstDatabase, | 256 | db: &dyn AstDatabase, |
234 | id: MacroCallId, | 257 | id: MacroCallId, |
235 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 258 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
@@ -256,36 +279,36 @@ pub(crate) fn expand_proc_macro( | |||
256 | expander.expand(db, lazy_id, ¯o_arg.0) | 279 | expander.expand(db, lazy_id, ¯o_arg.0) |
257 | } | 280 | } |
258 | 281 | ||
259 | pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> { | 282 | fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> { |
260 | match file_id.0 { | 283 | match file_id.0 { |
261 | HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), | 284 | HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), |
262 | HirFileIdRepr::MacroFile(macro_file) => { | 285 | HirFileIdRepr::MacroFile(macro_file) => { |
263 | db.parse_macro(macro_file).map(|(it, _)| it.syntax_node()) | 286 | db.parse_macro_expansion(macro_file).map(|(it, _)| it.syntax_node()).value |
264 | } | 287 | } |
265 | } | 288 | } |
266 | } | 289 | } |
267 | 290 | ||
268 | pub(crate) fn parse_macro( | 291 | fn parse_macro_expansion( |
269 | db: &dyn AstDatabase, | 292 | db: &dyn AstDatabase, |
270 | macro_file: MacroFile, | 293 | macro_file: MacroFile, |
271 | ) -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)> { | 294 | ) -> MacroResult<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)> { |
272 | parse_macro_with_arg(db, macro_file, None) | 295 | parse_macro_with_arg(db, macro_file, None) |
273 | } | 296 | } |
274 | 297 | ||
275 | pub fn parse_macro_with_arg( | 298 | fn parse_macro_with_arg( |
276 | db: &dyn AstDatabase, | 299 | db: &dyn AstDatabase, |
277 | macro_file: MacroFile, | 300 | macro_file: MacroFile, |
278 | arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>, | 301 | arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>, |
279 | ) -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)> { | 302 | ) -> MacroResult<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)> { |
280 | let _p = profile::span("parse_macro_query"); | 303 | let _p = profile::span("parse_macro_query"); |
281 | 304 | ||
282 | let macro_call_id = macro_file.macro_call_id; | 305 | let macro_call_id = macro_file.macro_call_id; |
283 | let (tt, err) = if let Some(arg) = arg { | 306 | let result = if let Some(arg) = arg { |
284 | macro_expand_with_arg(db, macro_call_id, Some(arg)) | 307 | macro_expand_with_arg(db, macro_call_id, Some(arg)) |
285 | } else { | 308 | } else { |
286 | db.macro_expand(macro_call_id) | 309 | db.macro_expand(macro_call_id) |
287 | }; | 310 | }; |
288 | if let Some(err) = &err { | 311 | if let Some(err) = &result.error { |
289 | // Note: | 312 | // Note: |
290 | // The final goal we would like to make all parse_macro success, | 313 | // The final goal we would like to make all parse_macro success, |
291 | // such that the following log will not call anyway. | 314 | // such that the following log will not call anyway. |
@@ -313,30 +336,40 @@ pub fn parse_macro_with_arg( | |||
313 | log::warn!("fail on macro_parse: (reason: {})", err); | 336 | log::warn!("fail on macro_parse: (reason: {})", err); |
314 | } | 337 | } |
315 | } | 338 | } |
339 | } | ||
340 | let tt = match result.value { | ||
341 | Some(tt) => tt, | ||
342 | None => return result.drop_value(), | ||
316 | }; | 343 | }; |
317 | let tt = tt?; | ||
318 | 344 | ||
319 | let fragment_kind = to_fragment_kind(db, macro_call_id); | 345 | let fragment_kind = to_fragment_kind(db, macro_call_id); |
320 | 346 | ||
321 | let (parse, rev_token_map) = mbe::token_tree_to_syntax_node(&tt, fragment_kind).ok()?; | 347 | let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) { |
348 | Ok(it) => it, | ||
349 | Err(err) => { | ||
350 | return MacroResult::error(format!("{:?}", err)); | ||
351 | } | ||
352 | }; | ||
322 | 353 | ||
323 | if err.is_none() { | 354 | match result.error { |
324 | Some((parse, Arc::new(rev_token_map))) | 355 | Some(error) => { |
325 | } else { | 356 | // Safety check for recursive identity macro. |
326 | // FIXME: | 357 | let node = parse.syntax_node(); |
327 | // In future, we should propagate the actual error with recovery information | 358 | let file: HirFileId = macro_file.into(); |
328 | // instead of ignore the error here. | 359 | let call_node = match file.call_node(db) { |
329 | 360 | Some(it) => it, | |
330 | // Safe check for recurisve identity macro | 361 | None => { |
331 | let node = parse.syntax_node(); | 362 | return MacroResult::error(error); |
332 | let file: HirFileId = macro_file.into(); | 363 | } |
333 | let call_node = file.call_node(db)?; | 364 | }; |
334 | 365 | ||
335 | if !diff(&node, &call_node.value).is_empty() { | 366 | if !diff(&node, &call_node.value).is_empty() { |
336 | Some((parse, Arc::new(rev_token_map))) | 367 | MacroResult { value: Some((parse, Arc::new(rev_token_map))), error: Some(error) } |
337 | } else { | 368 | } else { |
338 | None | 369 | return MacroResult::error(error); |
370 | } | ||
339 | } | 371 | } |
372 | None => MacroResult { value: Some((parse, Arc::new(rev_token_map))), error: None }, | ||
340 | } | 373 | } |
341 | } | 374 | } |
342 | 375 | ||
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 17f1178ed..83e09738b 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -144,7 +144,7 @@ impl HirFileId { | |||
144 | let def_tt = loc.def.ast_id?.to_node(db).token_tree()?; | 144 | let def_tt = loc.def.ast_id?.to_node(db).token_tree()?; |
145 | 145 | ||
146 | let macro_def = db.macro_def(loc.def)?; | 146 | let macro_def = db.macro_def(loc.def)?; |
147 | let (parse, exp_map) = db.parse_macro(macro_file)?; | 147 | let (parse, exp_map) = db.parse_macro_expansion(macro_file).value?; |
148 | let macro_arg = db.macro_arg(macro_file.macro_call_id)?; | 148 | let macro_arg = db.macro_arg(macro_file.macro_call_id)?; |
149 | 149 | ||
150 | Some(ExpansionInfo { | 150 | Some(ExpansionInfo { |
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs index 5bd03f2ac..62c329731 100644 --- a/crates/hir_ty/src/diagnostics/match_check.rs +++ b/crates/hir_ty/src/diagnostics/match_check.rs | |||
@@ -216,14 +216,14 @@ | |||
216 | //! U(P, p) := U(P, (r_1, p_2, .., p_n)) | 216 | //! U(P, p) := U(P, (r_1, p_2, .., p_n)) |
217 | //! || U(P, (r_2, p_2, .., p_n)) | 217 | //! || U(P, (r_2, p_2, .., p_n)) |
218 | //! ``` | 218 | //! ``` |
219 | use std::sync::Arc; | 219 | use std::{iter, sync::Arc}; |
220 | 220 | ||
221 | use arena::Idx; | 221 | use arena::Idx; |
222 | use hir_def::{ | 222 | use hir_def::{ |
223 | adt::VariantData, | 223 | adt::VariantData, |
224 | body::Body, | 224 | body::Body, |
225 | expr::{Expr, Literal, Pat, PatId}, | 225 | expr::{Expr, Literal, Pat, PatId}, |
226 | AdtId, EnumVariantId, VariantId, | 226 | AdtId, EnumVariantId, StructId, VariantId, |
227 | }; | 227 | }; |
228 | use smallvec::{smallvec, SmallVec}; | 228 | use smallvec::{smallvec, SmallVec}; |
229 | 229 | ||
@@ -366,16 +366,17 @@ impl PatStack { | |||
366 | 366 | ||
367 | let head_pat = head.as_pat(cx); | 367 | let head_pat = head.as_pat(cx); |
368 | let result = match (head_pat, constructor) { | 368 | let result = match (head_pat, constructor) { |
369 | (Pat::Tuple { args: ref pat_ids, ellipsis }, Constructor::Tuple { arity: _ }) => { | 369 | (Pat::Tuple { args: pat_ids, ellipsis }, &Constructor::Tuple { arity }) => { |
370 | if ellipsis.is_some() { | 370 | if let Some(ellipsis) = ellipsis { |
371 | // If there are ellipsis here, we should add the correct number of | 371 | let (pre, post) = pat_ids.split_at(ellipsis); |
372 | // Pat::Wild patterns to `pat_ids`. We should be able to use the | 372 | let n_wild_pats = arity.saturating_sub(pat_ids.len()); |
373 | // constructors arity for this, but at the time of writing we aren't | 373 | let pre_iter = pre.iter().map(Into::into); |
374 | // correctly calculating this arity when ellipsis are present. | 374 | let wildcards = iter::repeat(PatIdOrWild::Wild).take(n_wild_pats); |
375 | return Err(MatchCheckErr::NotImplemented); | 375 | let post_iter = post.iter().map(Into::into); |
376 | Some(self.replace_head_with(pre_iter.chain(wildcards).chain(post_iter))) | ||
377 | } else { | ||
378 | Some(self.replace_head_with(pat_ids.iter())) | ||
376 | } | 379 | } |
377 | |||
378 | Some(self.replace_head_with(pat_ids.iter())) | ||
379 | } | 380 | } |
380 | (Pat::Lit(lit_expr), Constructor::Bool(constructor_val)) => { | 381 | (Pat::Lit(lit_expr), Constructor::Bool(constructor_val)) => { |
381 | match cx.body.exprs[lit_expr] { | 382 | match cx.body.exprs[lit_expr] { |
@@ -390,21 +391,28 @@ impl PatStack { | |||
390 | } | 391 | } |
391 | } | 392 | } |
392 | (Pat::Wild, constructor) => Some(self.expand_wildcard(cx, constructor)?), | 393 | (Pat::Wild, constructor) => Some(self.expand_wildcard(cx, constructor)?), |
393 | (Pat::Path(_), Constructor::Enum(constructor)) => { | 394 | (Pat::Path(_), constructor) => { |
394 | // unit enum variants become `Pat::Path` | 395 | // unit enum variants become `Pat::Path` |
395 | let pat_id = head.as_id().expect("we know this isn't a wild"); | 396 | let pat_id = head.as_id().expect("we know this isn't a wild"); |
396 | if !enum_variant_matches(cx, pat_id, *constructor) { | 397 | let variant_id: VariantId = match constructor { |
398 | &Constructor::Enum(e) => e.into(), | ||
399 | &Constructor::Struct(s) => s.into(), | ||
400 | _ => return Err(MatchCheckErr::NotImplemented), | ||
401 | }; | ||
402 | if Some(variant_id) != cx.infer.variant_resolution_for_pat(pat_id) { | ||
397 | None | 403 | None |
398 | } else { | 404 | } else { |
399 | Some(self.to_tail()) | 405 | Some(self.to_tail()) |
400 | } | 406 | } |
401 | } | 407 | } |
402 | ( | 408 | (Pat::TupleStruct { args: ref pat_ids, ellipsis, .. }, constructor) => { |
403 | Pat::TupleStruct { args: ref pat_ids, ellipsis, .. }, | ||
404 | Constructor::Enum(enum_constructor), | ||
405 | ) => { | ||
406 | let pat_id = head.as_id().expect("we know this isn't a wild"); | 409 | let pat_id = head.as_id().expect("we know this isn't a wild"); |
407 | if !enum_variant_matches(cx, pat_id, *enum_constructor) { | 410 | let variant_id: VariantId = match constructor { |
411 | &Constructor::Enum(e) => e.into(), | ||
412 | &Constructor::Struct(s) => s.into(), | ||
413 | _ => return Err(MatchCheckErr::MalformedMatchArm), | ||
414 | }; | ||
415 | if Some(variant_id) != cx.infer.variant_resolution_for_pat(pat_id) { | ||
408 | None | 416 | None |
409 | } else { | 417 | } else { |
410 | let constructor_arity = constructor.arity(cx)?; | 418 | let constructor_arity = constructor.arity(cx)?; |
@@ -442,12 +450,22 @@ impl PatStack { | |||
442 | } | 450 | } |
443 | } | 451 | } |
444 | } | 452 | } |
445 | (Pat::Record { args: ref arg_patterns, .. }, Constructor::Enum(e)) => { | 453 | (Pat::Record { args: ref arg_patterns, .. }, constructor) => { |
446 | let pat_id = head.as_id().expect("we know this isn't a wild"); | 454 | let pat_id = head.as_id().expect("we know this isn't a wild"); |
447 | if !enum_variant_matches(cx, pat_id, *e) { | 455 | let (variant_id, variant_data) = match constructor { |
456 | &Constructor::Enum(e) => ( | ||
457 | e.into(), | ||
458 | cx.db.enum_data(e.parent).variants[e.local_id].variant_data.clone(), | ||
459 | ), | ||
460 | &Constructor::Struct(s) => { | ||
461 | (s.into(), cx.db.struct_data(s).variant_data.clone()) | ||
462 | } | ||
463 | _ => return Err(MatchCheckErr::MalformedMatchArm), | ||
464 | }; | ||
465 | if Some(variant_id) != cx.infer.variant_resolution_for_pat(pat_id) { | ||
448 | None | 466 | None |
449 | } else { | 467 | } else { |
450 | match cx.db.enum_data(e.parent).variants[e.local_id].variant_data.as_ref() { | 468 | match variant_data.as_ref() { |
451 | VariantData::Record(struct_field_arena) => { | 469 | VariantData::Record(struct_field_arena) => { |
452 | // Here we treat any missing fields in the record as the wild pattern, as | 470 | // Here we treat any missing fields in the record as the wild pattern, as |
453 | // if the record has ellipsis. We want to do this here even if the | 471 | // if the record has ellipsis. We want to do this here even if the |
@@ -726,6 +744,7 @@ enum Constructor { | |||
726 | Bool(bool), | 744 | Bool(bool), |
727 | Tuple { arity: usize }, | 745 | Tuple { arity: usize }, |
728 | Enum(EnumVariantId), | 746 | Enum(EnumVariantId), |
747 | Struct(StructId), | ||
729 | } | 748 | } |
730 | 749 | ||
731 | impl Constructor { | 750 | impl Constructor { |
@@ -740,6 +759,11 @@ impl Constructor { | |||
740 | VariantData::Unit => 0, | 759 | VariantData::Unit => 0, |
741 | } | 760 | } |
742 | } | 761 | } |
762 | &Constructor::Struct(s) => match cx.db.struct_data(s).variant_data.as_ref() { | ||
763 | VariantData::Tuple(struct_field_data) => struct_field_data.len(), | ||
764 | VariantData::Record(struct_field_data) => struct_field_data.len(), | ||
765 | VariantData::Unit => 0, | ||
766 | }, | ||
743 | }; | 767 | }; |
744 | 768 | ||
745 | Ok(arity) | 769 | Ok(arity) |
@@ -748,7 +772,7 @@ impl Constructor { | |||
748 | fn all_constructors(&self, cx: &MatchCheckCtx) -> Vec<Constructor> { | 772 | fn all_constructors(&self, cx: &MatchCheckCtx) -> Vec<Constructor> { |
749 | match self { | 773 | match self { |
750 | Constructor::Bool(_) => vec![Constructor::Bool(true), Constructor::Bool(false)], | 774 | Constructor::Bool(_) => vec![Constructor::Bool(true), Constructor::Bool(false)], |
751 | Constructor::Tuple { .. } => vec![*self], | 775 | Constructor::Tuple { .. } | Constructor::Struct(_) => vec![*self], |
752 | Constructor::Enum(e) => cx | 776 | Constructor::Enum(e) => cx |
753 | .db | 777 | .db |
754 | .enum_data(e.parent) | 778 | .enum_data(e.parent) |
@@ -767,10 +791,11 @@ impl Constructor { | |||
767 | fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> { | 791 | fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> { |
768 | let res = match pat.as_pat(cx) { | 792 | let res = match pat.as_pat(cx) { |
769 | Pat::Wild => None, | 793 | Pat::Wild => None, |
770 | // FIXME somehow create the Tuple constructor with the proper arity. If there are | 794 | Pat::Tuple { .. } => { |
771 | // ellipsis, the arity is not equal to the number of patterns. | 795 | let pat_id = pat.as_id().expect("we already know this pattern is not a wild"); |
772 | Pat::Tuple { args: pats, ellipsis } if ellipsis.is_none() => { | 796 | Some(Constructor::Tuple { |
773 | Some(Constructor::Tuple { arity: pats.len() }) | 797 | arity: cx.infer.type_of_pat[pat_id].as_tuple().ok_or(MatchCheckErr::Unknown)?.len(), |
798 | }) | ||
774 | } | 799 | } |
775 | Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] { | 800 | Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] { |
776 | Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)), | 801 | Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)), |
@@ -784,6 +809,7 @@ fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Opt | |||
784 | VariantId::EnumVariantId(enum_variant_id) => { | 809 | VariantId::EnumVariantId(enum_variant_id) => { |
785 | Some(Constructor::Enum(enum_variant_id)) | 810 | Some(Constructor::Enum(enum_variant_id)) |
786 | } | 811 | } |
812 | VariantId::StructId(struct_id) => Some(Constructor::Struct(struct_id)), | ||
787 | _ => return Err(MatchCheckErr::NotImplemented), | 813 | _ => return Err(MatchCheckErr::NotImplemented), |
788 | } | 814 | } |
789 | } | 815 | } |
@@ -828,13 +854,13 @@ fn all_constructors_covered( | |||
828 | 854 | ||
829 | false | 855 | false |
830 | }), | 856 | }), |
857 | &Constructor::Struct(s) => used_constructors.iter().any(|constructor| match constructor { | ||
858 | &Constructor::Struct(sid) => sid == s, | ||
859 | _ => false, | ||
860 | }), | ||
831 | } | 861 | } |
832 | } | 862 | } |
833 | 863 | ||
834 | fn enum_variant_matches(cx: &MatchCheckCtx, pat_id: PatId, enum_variant_id: EnumVariantId) -> bool { | ||
835 | Some(enum_variant_id.into()) == cx.infer.variant_resolution_for_pat(pat_id) | ||
836 | } | ||
837 | |||
838 | #[cfg(test)] | 864 | #[cfg(test)] |
839 | mod tests { | 865 | mod tests { |
840 | use crate::diagnostics::tests::check_diagnostics; | 866 | use crate::diagnostics::tests::check_diagnostics; |
@@ -846,8 +872,8 @@ mod tests { | |||
846 | fn main() { | 872 | fn main() { |
847 | match () { } | 873 | match () { } |
848 | //^^ Missing match arm | 874 | //^^ Missing match arm |
849 | match (()) { } | 875 | match (()) { } |
850 | //^^^^ Missing match arm | 876 | //^^^^ Missing match arm |
851 | 877 | ||
852 | match () { _ => (), } | 878 | match () { _ => (), } |
853 | match () { () => (), } | 879 | match () { () => (), } |
@@ -1352,6 +1378,123 @@ fn main() { | |||
1352 | ); | 1378 | ); |
1353 | } | 1379 | } |
1354 | 1380 | ||
1381 | #[test] | ||
1382 | fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { | ||
1383 | check_diagnostics( | ||
1384 | r#" | ||
1385 | fn main() { | ||
1386 | match (false, true, false) { | ||
1387 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1388 | (false, ..) => (), | ||
1389 | } | ||
1390 | }"#, | ||
1391 | ); | ||
1392 | } | ||
1393 | |||
1394 | #[test] | ||
1395 | fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { | ||
1396 | check_diagnostics( | ||
1397 | r#" | ||
1398 | fn main() { | ||
1399 | match (false, true, false) { | ||
1400 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1401 | (.., false) => (), | ||
1402 | } | ||
1403 | }"#, | ||
1404 | ); | ||
1405 | } | ||
1406 | |||
1407 | #[test] | ||
1408 | fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() { | ||
1409 | check_diagnostics( | ||
1410 | r#" | ||
1411 | fn main() { | ||
1412 | match (false, true, false) { | ||
1413 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1414 | (true, .., false) => (), | ||
1415 | } | ||
1416 | }"#, | ||
1417 | ); | ||
1418 | } | ||
1419 | |||
1420 | #[test] | ||
1421 | fn record_struct() { | ||
1422 | check_diagnostics( | ||
1423 | r#"struct Foo { a: bool } | ||
1424 | fn main(f: Foo) { | ||
1425 | match f {} | ||
1426 | //^ Missing match arm | ||
1427 | match f { Foo { a: true } => () } | ||
1428 | //^ Missing match arm | ||
1429 | match &f { Foo { a: true } => () } | ||
1430 | //^^ Missing match arm | ||
1431 | match f { Foo { a: _ } => () } | ||
1432 | match f { | ||
1433 | Foo { a: true } => (), | ||
1434 | Foo { a: false } => (), | ||
1435 | } | ||
1436 | match &f { | ||
1437 | Foo { a: true } => (), | ||
1438 | Foo { a: false } => (), | ||
1439 | } | ||
1440 | } | ||
1441 | "#, | ||
1442 | ); | ||
1443 | } | ||
1444 | |||
1445 | #[test] | ||
1446 | fn tuple_struct() { | ||
1447 | check_diagnostics( | ||
1448 | r#"struct Foo(bool); | ||
1449 | fn main(f: Foo) { | ||
1450 | match f {} | ||
1451 | //^ Missing match arm | ||
1452 | match f { Foo(true) => () } | ||
1453 | //^ Missing match arm | ||
1454 | match f { | ||
1455 | Foo(true) => (), | ||
1456 | Foo(false) => (), | ||
1457 | } | ||
1458 | } | ||
1459 | "#, | ||
1460 | ); | ||
1461 | } | ||
1462 | |||
1463 | #[test] | ||
1464 | fn unit_struct() { | ||
1465 | check_diagnostics( | ||
1466 | r#"struct Foo; | ||
1467 | fn main(f: Foo) { | ||
1468 | match f {} | ||
1469 | //^ Missing match arm | ||
1470 | match f { Foo => () } | ||
1471 | } | ||
1472 | "#, | ||
1473 | ); | ||
1474 | } | ||
1475 | |||
1476 | #[test] | ||
1477 | fn record_struct_ellipsis() { | ||
1478 | check_diagnostics( | ||
1479 | r#"struct Foo { foo: bool, bar: bool } | ||
1480 | fn main(f: Foo) { | ||
1481 | match f { Foo { foo: true, .. } => () } | ||
1482 | //^ Missing match arm | ||
1483 | match f { | ||
1484 | //^ Missing match arm | ||
1485 | Foo { foo: true, .. } => (), | ||
1486 | Foo { bar: false, .. } => () | ||
1487 | } | ||
1488 | match f { Foo { .. } => () } | ||
1489 | match f { | ||
1490 | Foo { foo: true, .. } => (), | ||
1491 | Foo { foo: false, .. } => () | ||
1492 | } | ||
1493 | } | ||
1494 | "#, | ||
1495 | ); | ||
1496 | } | ||
1497 | |||
1355 | mod false_negatives { | 1498 | mod false_negatives { |
1356 | //! The implementation of match checking here is a work in progress. As we roll this out, we | 1499 | //! The implementation of match checking here is a work in progress. As we roll this out, we |
1357 | //! prefer false negatives to false positives (ideally there would be no false positives). This | 1500 | //! prefer false negatives to false positives (ideally there would be no false positives). This |
@@ -1393,46 +1536,5 @@ fn main() { | |||
1393 | "#, | 1536 | "#, |
1394 | ); | 1537 | ); |
1395 | } | 1538 | } |
1396 | |||
1397 | #[test] | ||
1398 | fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { | ||
1399 | // We don't currently handle tuple patterns with ellipsis. | ||
1400 | check_diagnostics( | ||
1401 | r#" | ||
1402 | fn main() { | ||
1403 | match (false, true, false) { | ||
1404 | (false, ..) => (), | ||
1405 | } | ||
1406 | } | ||
1407 | "#, | ||
1408 | ); | ||
1409 | } | ||
1410 | |||
1411 | #[test] | ||
1412 | fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { | ||
1413 | // We don't currently handle tuple patterns with ellipsis. | ||
1414 | check_diagnostics( | ||
1415 | r#" | ||
1416 | fn main() { | ||
1417 | match (false, true, false) { | ||
1418 | (.., false) => (), | ||
1419 | } | ||
1420 | } | ||
1421 | "#, | ||
1422 | ); | ||
1423 | } | ||
1424 | |||
1425 | #[test] | ||
1426 | fn struct_missing_arm() { | ||
1427 | // We don't currently handle structs. | ||
1428 | check_diagnostics( | ||
1429 | r#" | ||
1430 | struct Foo { a: bool } | ||
1431 | fn main(f: Foo) { | ||
1432 | match f { Foo { a: true } => () } | ||
1433 | } | ||
1434 | "#, | ||
1435 | ); | ||
1436 | } | ||
1437 | } | 1539 | } |
1438 | } | 1540 | } |
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index cde2ab82b..b70ec55eb 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs | |||
@@ -23,6 +23,7 @@ impl<'a> InferenceContext<'a> { | |||
23 | expected: &Ty, | 23 | expected: &Ty, |
24 | default_bm: BindingMode, | 24 | default_bm: BindingMode, |
25 | id: PatId, | 25 | id: PatId, |
26 | ellipsis: Option<usize>, | ||
26 | ) -> Ty { | 27 | ) -> Ty { |
27 | let (ty, def) = self.resolve_variant(path); | 28 | let (ty, def) = self.resolve_variant(path); |
28 | let var_data = def.map(|it| variant_data(self.db.upcast(), it)); | 29 | let var_data = def.map(|it| variant_data(self.db.upcast(), it)); |
@@ -34,8 +35,15 @@ impl<'a> InferenceContext<'a> { | |||
34 | let substs = ty.substs().unwrap_or_else(Substs::empty); | 35 | let substs = ty.substs().unwrap_or_else(Substs::empty); |
35 | 36 | ||
36 | let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); | 37 | let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); |
38 | let (pre, post) = match ellipsis { | ||
39 | Some(idx) => subpats.split_at(idx), | ||
40 | None => (&subpats[..], &[][..]), | ||
41 | }; | ||
42 | let post_idx_offset = field_tys.iter().count() - post.len(); | ||
37 | 43 | ||
38 | for (i, &subpat) in subpats.iter().enumerate() { | 44 | let pre_iter = pre.iter().enumerate(); |
45 | let post_iter = (post_idx_offset..).zip(post.iter()); | ||
46 | for (i, &subpat) in pre_iter.chain(post_iter) { | ||
39 | let expected_ty = var_data | 47 | let expected_ty = var_data |
40 | .as_ref() | 48 | .as_ref() |
41 | .and_then(|d| d.field(&Name::new_tuple_field(i))) | 49 | .and_then(|d| d.field(&Name::new_tuple_field(i))) |
@@ -111,20 +119,29 @@ impl<'a> InferenceContext<'a> { | |||
111 | let expected = expected; | 119 | let expected = expected; |
112 | 120 | ||
113 | let ty = match &body[pat] { | 121 | let ty = match &body[pat] { |
114 | Pat::Tuple { ref args, .. } => { | 122 | &Pat::Tuple { ref args, ellipsis } => { |
115 | let expectations = match expected.as_tuple() { | 123 | let expectations = match expected.as_tuple() { |
116 | Some(parameters) => &*parameters.0, | 124 | Some(parameters) => &*parameters.0, |
117 | _ => &[], | 125 | _ => &[], |
118 | }; | 126 | }; |
119 | let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown)); | ||
120 | 127 | ||
121 | let inner_tys = args | 128 | let (pre, post) = match ellipsis { |
122 | .iter() | 129 | Some(idx) => args.split_at(idx), |
123 | .zip(expectations_iter) | 130 | None => (&args[..], &[][..]), |
124 | .map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm)) | 131 | }; |
125 | .collect(); | 132 | let n_uncovered_patterns = expectations.len().saturating_sub(args.len()); |
133 | let mut expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown)); | ||
134 | let mut infer_pat = |(&pat, ty)| self.infer_pat(pat, ty, default_bm); | ||
135 | |||
136 | let mut inner_tys = Vec::with_capacity(n_uncovered_patterns + args.len()); | ||
137 | inner_tys.extend(pre.iter().zip(expectations_iter.by_ref()).map(&mut infer_pat)); | ||
138 | inner_tys.extend(expectations_iter.by_ref().take(n_uncovered_patterns).cloned()); | ||
139 | inner_tys.extend(post.iter().zip(expectations_iter).map(infer_pat)); | ||
126 | 140 | ||
127 | Ty::apply(TypeCtor::Tuple { cardinality: args.len() as u16 }, Substs(inner_tys)) | 141 | Ty::apply( |
142 | TypeCtor::Tuple { cardinality: inner_tys.len() as u16 }, | ||
143 | Substs(inner_tys.into()), | ||
144 | ) | ||
128 | } | 145 | } |
129 | Pat::Or(ref pats) => { | 146 | Pat::Or(ref pats) => { |
130 | if let Some((first_pat, rest)) = pats.split_first() { | 147 | if let Some((first_pat, rest)) = pats.split_first() { |
@@ -150,9 +167,14 @@ impl<'a> InferenceContext<'a> { | |||
150 | let subty = self.infer_pat(*pat, expectation, default_bm); | 167 | let subty = self.infer_pat(*pat, expectation, default_bm); |
151 | Ty::apply_one(TypeCtor::Ref(*mutability), subty) | 168 | Ty::apply_one(TypeCtor::Ref(*mutability), subty) |
152 | } | 169 | } |
153 | Pat::TupleStruct { path: p, args: subpats, .. } => { | 170 | Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat( |
154 | self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm, pat) | 171 | p.as_ref(), |
155 | } | 172 | subpats, |
173 | expected, | ||
174 | default_bm, | ||
175 | pat, | ||
176 | *ellipsis, | ||
177 | ), | ||
156 | Pat::Record { path: p, args: fields, ellipsis: _ } => { | 178 | Pat::Record { path: p, args: fields, ellipsis: _ } => { |
157 | self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat) | 179 | self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat) |
158 | } | 180 | } |
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs index 6a965ac4f..5a5f48fd0 100644 --- a/crates/hir_ty/src/tests/patterns.rs +++ b/crates/hir_ty/src/tests/patterns.rs | |||
@@ -679,3 +679,98 @@ fn box_pattern() { | |||
679 | "#]], | 679 | "#]], |
680 | ); | 680 | ); |
681 | } | 681 | } |
682 | |||
683 | #[test] | ||
684 | fn tuple_ellipsis_pattern() { | ||
685 | check_infer( | ||
686 | r#" | ||
687 | fn foo(tuple: (u8, i16, f32)) { | ||
688 | match tuple { | ||
689 | (.., b, c) => {}, | ||
690 | (a, .., c) => {}, | ||
691 | (a, b, ..) => {}, | ||
692 | (a, b) => {/*too short*/} | ||
693 | (a, b, c, d) => {/*too long*/} | ||
694 | _ => {} | ||
695 | } | ||
696 | }"#, | ||
697 | expect![[r#" | ||
698 | 7..12 'tuple': (u8, i16, f32) | ||
699 | 30..224 '{ ... } }': () | ||
700 | 36..222 'match ... }': () | ||
701 | 42..47 'tuple': (u8, i16, f32) | ||
702 | 58..68 '(.., b, c)': (u8, i16, f32) | ||
703 | 63..64 'b': i16 | ||
704 | 66..67 'c': f32 | ||
705 | 72..74 '{}': () | ||
706 | 84..94 '(a, .., c)': (u8, i16, f32) | ||
707 | 85..86 'a': u8 | ||
708 | 92..93 'c': f32 | ||
709 | 98..100 '{}': () | ||
710 | 110..120 '(a, b, ..)': (u8, i16, f32) | ||
711 | 111..112 'a': u8 | ||
712 | 114..115 'b': i16 | ||
713 | 124..126 '{}': () | ||
714 | 136..142 '(a, b)': (u8, i16, f32) | ||
715 | 137..138 'a': u8 | ||
716 | 140..141 'b': i16 | ||
717 | 146..161 '{/*too short*/}': () | ||
718 | 170..182 '(a, b, c, d)': (u8, i16, f32, {unknown}) | ||
719 | 171..172 'a': u8 | ||
720 | 174..175 'b': i16 | ||
721 | 177..178 'c': f32 | ||
722 | 180..181 'd': {unknown} | ||
723 | 186..200 '{/*too long*/}': () | ||
724 | 209..210 '_': (u8, i16, f32) | ||
725 | 214..216 '{}': () | ||
726 | "#]], | ||
727 | ); | ||
728 | } | ||
729 | |||
730 | #[test] | ||
731 | fn tuple_struct_ellipsis_pattern() { | ||
732 | check_infer( | ||
733 | r#" | ||
734 | struct Tuple(u8, i16, f32); | ||
735 | fn foo(tuple: Tuple) { | ||
736 | match tuple { | ||
737 | Tuple(.., b, c) => {}, | ||
738 | Tuple(a, .., c) => {}, | ||
739 | Tuple(a, b, ..) => {}, | ||
740 | Tuple(a, b) => {/*too short*/} | ||
741 | Tuple(a, b, c, d) => {/*too long*/} | ||
742 | _ => {} | ||
743 | } | ||
744 | }"#, | ||
745 | expect![[r#" | ||
746 | 35..40 'tuple': Tuple | ||
747 | 49..268 '{ ... } }': () | ||
748 | 55..266 'match ... }': () | ||
749 | 61..66 'tuple': Tuple | ||
750 | 77..92 'Tuple(.., b, c)': Tuple | ||
751 | 87..88 'b': i16 | ||
752 | 90..91 'c': f32 | ||
753 | 96..98 '{}': () | ||
754 | 108..123 'Tuple(a, .., c)': Tuple | ||
755 | 114..115 'a': u8 | ||
756 | 121..122 'c': f32 | ||
757 | 127..129 '{}': () | ||
758 | 139..154 'Tuple(a, b, ..)': Tuple | ||
759 | 145..146 'a': u8 | ||
760 | 148..149 'b': i16 | ||
761 | 158..160 '{}': () | ||
762 | 170..181 'Tuple(a, b)': Tuple | ||
763 | 176..177 'a': u8 | ||
764 | 179..180 'b': i16 | ||
765 | 185..200 '{/*too short*/}': () | ||
766 | 209..226 'Tuple(... c, d)': Tuple | ||
767 | 215..216 'a': u8 | ||
768 | 218..219 'b': i16 | ||
769 | 221..222 'c': f32 | ||
770 | 224..225 'd': {unknown} | ||
771 | 230..244 '{/*too long*/}': () | ||
772 | 253..254 '_': Tuple | ||
773 | 258..260 '{}': () | ||
774 | "#]], | ||
775 | ); | ||
776 | } | ||
diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs index 8e91c99d7..b75f88ed9 100644 --- a/crates/ide/src/status.rs +++ b/crates/ide/src/status.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use std::{fmt, iter::FromIterator, sync::Arc}; | 1 | use std::{fmt, iter::FromIterator, sync::Arc}; |
2 | 2 | ||
3 | use hir::MacroFile; | 3 | use hir::{MacroFile, MacroResult}; |
4 | use ide_db::base_db::{ | 4 | use ide_db::base_db::{ |
5 | salsa::debug::{DebugQueryTable, TableEntry}, | 5 | salsa::debug::{DebugQueryTable, TableEntry}, |
6 | CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId, | 6 | CrateId, FileId, FileTextQuery, SourceDatabase, SourceRootId, |
@@ -19,7 +19,7 @@ fn syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { | |||
19 | ide_db::base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>() | 19 | ide_db::base_db::ParseQuery.in_db(db).entries::<SyntaxTreeStats>() |
20 | } | 20 | } |
21 | fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { | 21 | fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats { |
22 | hir::db::ParseMacroQuery.in_db(db).entries::<SyntaxTreeStats>() | 22 | hir::db::ParseMacroExpansionQuery.in_db(db).entries::<SyntaxTreeStats>() |
23 | } | 23 | } |
24 | 24 | ||
25 | // Feature: Status | 25 | // Feature: Status |
@@ -115,10 +115,12 @@ impl FromIterator<TableEntry<FileId, Parse<ast::SourceFile>>> for SyntaxTreeStat | |||
115 | } | 115 | } |
116 | } | 116 | } |
117 | 117 | ||
118 | impl<M> FromIterator<TableEntry<MacroFile, Option<(Parse<SyntaxNode>, M)>>> for SyntaxTreeStats { | 118 | impl<M> FromIterator<TableEntry<MacroFile, MacroResult<(Parse<SyntaxNode>, M)>>> |
119 | for SyntaxTreeStats | ||
120 | { | ||
119 | fn from_iter<T>(iter: T) -> SyntaxTreeStats | 121 | fn from_iter<T>(iter: T) -> SyntaxTreeStats |
120 | where | 122 | where |
121 | T: IntoIterator<Item = TableEntry<MacroFile, Option<(Parse<SyntaxNode>, M)>>>, | 123 | T: IntoIterator<Item = TableEntry<MacroFile, MacroResult<(Parse<SyntaxNode>, M)>>>, |
122 | { | 124 | { |
123 | let mut res = SyntaxTreeStats::default(); | 125 | let mut res = SyntaxTreeStats::default(); |
124 | for entry in iter { | 126 | for entry in iter { |
diff --git a/crates/ide_db/src/apply_change.rs b/crates/ide_db/src/apply_change.rs index da16fa21d..987191fe3 100644 --- a/crates/ide_db/src/apply_change.rs +++ b/crates/ide_db/src/apply_change.rs | |||
@@ -76,7 +76,7 @@ impl RootDatabase { | |||
76 | let sweep = SweepStrategy::default().discard_values().sweep_all_revisions(); | 76 | let sweep = SweepStrategy::default().discard_values().sweep_all_revisions(); |
77 | 77 | ||
78 | base_db::ParseQuery.in_db(self).sweep(sweep); | 78 | base_db::ParseQuery.in_db(self).sweep(sweep); |
79 | hir::db::ParseMacroQuery.in_db(self).sweep(sweep); | 79 | hir::db::ParseMacroExpansionQuery.in_db(self).sweep(sweep); |
80 | 80 | ||
81 | // Macros do take significant space, but less then the syntax trees | 81 | // Macros do take significant space, but less then the syntax trees |
82 | // self.query(hir::db::MacroDefQuery).sweep(sweep); | 82 | // self.query(hir::db::MacroDefQuery).sweep(sweep); |
@@ -143,7 +143,7 @@ impl RootDatabase { | |||
143 | hir::db::AstIdMapQuery | 143 | hir::db::AstIdMapQuery |
144 | hir::db::MacroArgTextQuery | 144 | hir::db::MacroArgTextQuery |
145 | hir::db::MacroDefQuery | 145 | hir::db::MacroDefQuery |
146 | hir::db::ParseMacroQuery | 146 | hir::db::ParseMacroExpansionQuery |
147 | hir::db::MacroExpandQuery | 147 | hir::db::MacroExpandQuery |
148 | 148 | ||
149 | // DefDatabase | 149 | // DefDatabase |
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs index 38ebdbf79..05139a651 100644 --- a/crates/ide_db/src/lib.rs +++ b/crates/ide_db/src/lib.rs | |||
@@ -113,7 +113,7 @@ impl RootDatabase { | |||
113 | pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) { | 113 | pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) { |
114 | let lru_capacity = lru_capacity.unwrap_or(base_db::DEFAULT_LRU_CAP); | 114 | let lru_capacity = lru_capacity.unwrap_or(base_db::DEFAULT_LRU_CAP); |
115 | base_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity); | 115 | base_db::ParseQuery.in_db_mut(self).set_lru_capacity(lru_capacity); |
116 | hir::db::ParseMacroQuery.in_db_mut(self).set_lru_capacity(lru_capacity); | 116 | hir::db::ParseMacroExpansionQuery.in_db_mut(self).set_lru_capacity(lru_capacity); |
117 | hir::db::MacroExpandQuery.in_db_mut(self).set_lru_capacity(lru_capacity); | 117 | hir::db::MacroExpandQuery.in_db_mut(self).set_lru_capacity(lru_capacity); |
118 | } | 118 | } |
119 | } | 119 | } |
diff --git a/crates/proc_macro_srv/Cargo.toml b/crates/proc_macro_srv/Cargo.toml index 048b32186..729372968 100644 --- a/crates/proc_macro_srv/Cargo.toml +++ b/crates/proc_macro_srv/Cargo.toml | |||
@@ -20,7 +20,7 @@ proc_macro_api = { path = "../proc_macro_api", version = "0.0.0" } | |||
20 | test_utils = { path = "../test_utils", version = "0.0.0" } | 20 | test_utils = { path = "../test_utils", version = "0.0.0" } |
21 | 21 | ||
22 | [dev-dependencies] | 22 | [dev-dependencies] |
23 | cargo_metadata = "0.12.0" | 23 | cargo_metadata = "=0.12.0" |
24 | difference = "2.0.0" | 24 | difference = "2.0.0" |
25 | 25 | ||
26 | # used as proc macro test targets | 26 | # used as proc macro test targets |
diff --git a/crates/project_model/Cargo.toml b/crates/project_model/Cargo.toml index 2d53bcbcc..e0c591603 100644 --- a/crates/project_model/Cargo.toml +++ b/crates/project_model/Cargo.toml | |||
@@ -12,7 +12,7 @@ doctest = false | |||
12 | [dependencies] | 12 | [dependencies] |
13 | log = "0.4.8" | 13 | log = "0.4.8" |
14 | rustc-hash = "1.1.0" | 14 | rustc-hash = "1.1.0" |
15 | cargo_metadata = "0.12.0" | 15 | cargo_metadata = "=0.12.0" |
16 | serde = { version = "1.0.106", features = ["derive"] } | 16 | serde = { version = "1.0.106", features = ["derive"] } |
17 | serde_json = "1.0.48" | 17 | serde_json = "1.0.48" |
18 | anyhow = "1.0.26" | 18 | anyhow = "1.0.26" |
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 56c51486f..436f5041b 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml | |||
@@ -21,7 +21,7 @@ env_logger = { version = "0.8.1", default-features = false } | |||
21 | itertools = "0.9.0" | 21 | itertools = "0.9.0" |
22 | jod-thread = "0.1.0" | 22 | jod-thread = "0.1.0" |
23 | log = "0.4.8" | 23 | log = "0.4.8" |
24 | lsp-types = { version = "0.83.1", features = ["proposed"] } | 24 | lsp-types = { version = "0.84.0", features = ["proposed"] } |
25 | parking_lot = "0.11.0" | 25 | parking_lot = "0.11.0" |
26 | pico-args = "0.3.1" | 26 | pico-args = "0.3.1" |
27 | oorandom = "11.1.2" | 27 | oorandom = "11.1.2" |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 5fc6800cf..a334cdb11 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -184,6 +184,7 @@ impl Config { | |||
184 | }, | 184 | }, |
185 | completion: CompletionConfig { | 185 | completion: CompletionConfig { |
186 | enable_postfix_completions: true, | 186 | enable_postfix_completions: true, |
187 | enable_experimental_completions: true, | ||
187 | add_call_parenthesis: true, | 188 | add_call_parenthesis: true, |
188 | add_call_argument_snippets: true, | 189 | add_call_argument_snippets: true, |
189 | ..CompletionConfig::default() | 190 | ..CompletionConfig::default() |
@@ -306,6 +307,7 @@ impl Config { | |||
306 | }; | 307 | }; |
307 | 308 | ||
308 | self.completion.enable_postfix_completions = data.completion_postfix_enable; | 309 | self.completion.enable_postfix_completions = data.completion_postfix_enable; |
310 | self.completion.enable_experimental_completions = data.completion_enableExperimental; | ||
309 | self.completion.add_call_parenthesis = data.completion_addCallParenthesis; | 311 | self.completion.add_call_parenthesis = data.completion_addCallParenthesis; |
310 | self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets; | 312 | self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets; |
311 | self.completion.merge = self.assist.insert_use.merge; | 313 | self.completion.merge = self.assist.insert_use.merge; |
@@ -506,6 +508,7 @@ config_data! { | |||
506 | completion_addCallArgumentSnippets: bool = true, | 508 | completion_addCallArgumentSnippets: bool = true, |
507 | completion_addCallParenthesis: bool = true, | 509 | completion_addCallParenthesis: bool = true, |
508 | completion_postfix_enable: bool = true, | 510 | completion_postfix_enable: bool = true, |
511 | completion_enableExperimental: bool = true, | ||
509 | 512 | ||
510 | diagnostics_enable: bool = true, | 513 | diagnostics_enable: bool = true, |
511 | diagnostics_enableExperimental: bool = true, | 514 | diagnostics_enableExperimental: bool = true, |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 6ea08adce..b34ff092d 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -503,7 +503,13 @@ impl GlobalState { | |||
503 | })? | 503 | })? |
504 | .on::<lsp_types::notification::DidChangeTextDocument>(|this, params| { | 504 | .on::<lsp_types::notification::DidChangeTextDocument>(|this, params| { |
505 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { | 505 | if let Ok(path) = from_proto::vfs_path(¶ms.text_document.uri) { |
506 | let doc = this.mem_docs.get_mut(&path).unwrap(); | 506 | let doc = match this.mem_docs.get_mut(&path) { |
507 | Some(doc) => doc, | ||
508 | None => { | ||
509 | log::error!("expected DidChangeTextDocument: {}", path); | ||
510 | return Ok(()); | ||
511 | } | ||
512 | }; | ||
507 | let vfs = &mut this.vfs.write().0; | 513 | let vfs = &mut this.vfs.write().0; |
508 | let file_id = vfs.file_id(&path).unwrap(); | 514 | let file_id = vfs.file_id(&path).unwrap(); |
509 | let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap(); | 515 | let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap(); |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 2f35425bb..2052b800c 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -629,12 +629,21 @@ pub(crate) fn resource_op( | |||
629 | match file_system_edit { | 629 | match file_system_edit { |
630 | FileSystemEdit::CreateFile { anchor, dst } => { | 630 | FileSystemEdit::CreateFile { anchor, dst } => { |
631 | let uri = snap.anchored_path(anchor, &dst); | 631 | let uri = snap.anchored_path(anchor, &dst); |
632 | lsp_types::ResourceOp::Create(lsp_types::CreateFile { uri, options: None }) | 632 | lsp_types::ResourceOp::Create(lsp_types::CreateFile { |
633 | uri, | ||
634 | options: None, | ||
635 | annotation: None, | ||
636 | }) | ||
633 | } | 637 | } |
634 | FileSystemEdit::MoveFile { src, anchor, dst } => { | 638 | FileSystemEdit::MoveFile { src, anchor, dst } => { |
635 | let old_uri = snap.file_id_to_url(src); | 639 | let old_uri = snap.file_id_to_url(src); |
636 | let new_uri = snap.anchored_path(anchor, &dst); | 640 | let new_uri = snap.anchored_path(anchor, &dst); |
637 | lsp_types::ResourceOp::Rename(lsp_types::RenameFile { old_uri, new_uri, options: None }) | 641 | lsp_types::ResourceOp::Rename(lsp_types::RenameFile { |
642 | old_uri, | ||
643 | new_uri, | ||
644 | options: None, | ||
645 | annotation: None, | ||
646 | }) | ||
638 | } | 647 | } |
639 | } | 648 | } |
640 | } | 649 | } |
@@ -684,9 +693,11 @@ impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit { | |||
684 | edits: edit | 693 | edits: edit |
685 | .edits | 694 | .edits |
686 | .into_iter() | 695 | .into_iter() |
687 | .map(|edit| lsp_types::TextEdit { | 696 | .map(|edit| { |
688 | range: edit.range, | 697 | lsp_types::OneOf::Left(lsp_types::TextEdit { |
689 | new_text: edit.new_text, | 698 | range: edit.range, |
699 | new_text: edit.new_text, | ||
700 | }) | ||
690 | }) | 701 | }) |
691 | .collect(), | 702 | .collect(), |
692 | }, | 703 | }, |
diff --git a/editors/code/package.json b/editors/code/package.json index a2d6b1148..c3f1a0d8d 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -460,6 +460,11 @@ | |||
460 | "default": true, | 460 | "default": true, |
461 | "markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc." | 461 | "markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc." |
462 | }, | 462 | }, |
463 | "rust-analyzer.completion.enableExperimental": { | ||
464 | "type": "boolean", | ||
465 | "default": true, | ||
466 | "markdownDescription": "Display additional completions with potential false positives and performance issues" | ||
467 | }, | ||
463 | "rust-analyzer.callInfo.full": { | 468 | "rust-analyzer.callInfo.full": { |
464 | "type": "boolean", | 469 | "type": "boolean", |
465 | "default": true, | 470 | "default": true, |
@@ -952,9 +957,6 @@ | |||
952 | { | 957 | { |
953 | "language": "rust", | 958 | "language": "rust", |
954 | "scopes": { | 959 | "scopes": { |
955 | "macro": [ | ||
956 | "entity.name.function.macro.rust" | ||
957 | ], | ||
958 | "attribute": [ | 960 | "attribute": [ |
959 | "meta.attribute.rust" | 961 | "meta.attribute.rust" |
960 | ], | 962 | ], |