diff options
40 files changed, 713 insertions, 240 deletions
diff --git a/Cargo.lock b/Cargo.lock index 9ebb15a96..f5b1a4747 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -720,9 +720,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" | |||
720 | 720 | ||
721 | [[package]] | 721 | [[package]] |
722 | name = "libc" | 722 | name = "libc" |
723 | version = "0.2.76" | 723 | version = "0.2.77" |
724 | source = "registry+https://github.com/rust-lang/crates.io-index" | 724 | source = "registry+https://github.com/rust-lang/crates.io-index" |
725 | checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" | 725 | checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" |
726 | 726 | ||
727 | [[package]] | 727 | [[package]] |
728 | name = "libloading" | 728 | name = "libloading" |
@@ -1071,9 +1071,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" | |||
1071 | 1071 | ||
1072 | [[package]] | 1072 | [[package]] |
1073 | name = "proc-macro2" | 1073 | name = "proc-macro2" |
1074 | version = "1.0.20" | 1074 | version = "1.0.21" |
1075 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1075 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1076 | checksum = "175c513d55719db99da20232b06cda8bab6b83ec2d04e3283edf0213c37c1a29" | 1076 | checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" |
1077 | dependencies = [ | 1077 | dependencies = [ |
1078 | "unicode-xid", | 1078 | "unicode-xid", |
1079 | ] | 1079 | ] |
@@ -1401,18 +1401,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" | |||
1401 | 1401 | ||
1402 | [[package]] | 1402 | [[package]] |
1403 | name = "serde" | 1403 | name = "serde" |
1404 | version = "1.0.115" | 1404 | version = "1.0.116" |
1405 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1405 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1406 | checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" | 1406 | checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" |
1407 | dependencies = [ | 1407 | dependencies = [ |
1408 | "serde_derive", | 1408 | "serde_derive", |
1409 | ] | 1409 | ] |
1410 | 1410 | ||
1411 | [[package]] | 1411 | [[package]] |
1412 | name = "serde_derive" | 1412 | name = "serde_derive" |
1413 | version = "1.0.115" | 1413 | version = "1.0.116" |
1414 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1414 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1415 | checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" | 1415 | checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" |
1416 | dependencies = [ | 1416 | dependencies = [ |
1417 | "proc-macro2", | 1417 | "proc-macro2", |
1418 | "quote", | 1418 | "quote", |
@@ -1639,9 +1639,9 @@ dependencies = [ | |||
1639 | 1639 | ||
1640 | [[package]] | 1640 | [[package]] |
1641 | name = "tracing-core" | 1641 | name = "tracing-core" |
1642 | version = "0.1.15" | 1642 | version = "0.1.16" |
1643 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1643 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1644 | checksum = "4f0e00789804e99b20f12bc7003ca416309d28a6f495d6af58d1e2c2842461b5" | 1644 | checksum = "5bcf46c1f1f06aeea2d6b81f3c863d0930a596c86ad1920d4e5bad6dd1d7119a" |
1645 | dependencies = [ | 1645 | dependencies = [ |
1646 | "lazy_static", | 1646 | "lazy_static", |
1647 | ] | 1647 | ] |
diff --git a/crates/assists/src/assist_config.rs b/crates/assists/src/assist_config.rs index cda2abfb9..adf02edab 100644 --- a/crates/assists/src/assist_config.rs +++ b/crates/assists/src/assist_config.rs | |||
@@ -4,12 +4,13 @@ | |||
4 | //! module, and we use to statically check that we only produce snippet | 4 | //! module, and we use to statically check that we only produce snippet |
5 | //! assists if we are allowed to. | 5 | //! assists if we are allowed to. |
6 | 6 | ||
7 | use crate::AssistKind; | 7 | use crate::{utils::MergeBehaviour, AssistKind}; |
8 | 8 | ||
9 | #[derive(Clone, Debug, PartialEq, Eq)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
10 | pub struct AssistConfig { | 10 | pub struct AssistConfig { |
11 | pub snippet_cap: Option<SnippetCap>, | 11 | pub snippet_cap: Option<SnippetCap>, |
12 | pub allowed: Option<Vec<AssistKind>>, | 12 | pub allowed: Option<Vec<AssistKind>>, |
13 | pub insert_use: InsertUseConfig, | ||
13 | } | 14 | } |
14 | 15 | ||
15 | impl AssistConfig { | 16 | impl AssistConfig { |
@@ -25,6 +26,21 @@ pub struct SnippetCap { | |||
25 | 26 | ||
26 | impl Default for AssistConfig { | 27 | impl Default for AssistConfig { |
27 | fn default() -> Self { | 28 | fn default() -> Self { |
28 | AssistConfig { snippet_cap: Some(SnippetCap { _private: () }), allowed: None } | 29 | AssistConfig { |
30 | snippet_cap: Some(SnippetCap { _private: () }), | ||
31 | allowed: None, | ||
32 | insert_use: InsertUseConfig::default(), | ||
33 | } | ||
34 | } | ||
35 | } | ||
36 | |||
37 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||
38 | pub struct InsertUseConfig { | ||
39 | pub merge: Option<MergeBehaviour>, | ||
40 | } | ||
41 | |||
42 | impl Default for InsertUseConfig { | ||
43 | fn default() -> Self { | ||
44 | InsertUseConfig { merge: Some(MergeBehaviour::Full) } | ||
29 | } | 45 | } |
30 | } | 46 | } |
diff --git a/crates/assists/src/handlers/auto_import.rs b/crates/assists/src/handlers/auto_import.rs index 66e819154..b5eb2c722 100644 --- a/crates/assists/src/handlers/auto_import.rs +++ b/crates/assists/src/handlers/auto_import.rs | |||
@@ -14,10 +14,7 @@ use syntax::{ | |||
14 | SyntaxNode, | 14 | SyntaxNode, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | use crate::{ | 17 | use crate::{utils::insert_use, AssistContext, AssistId, AssistKind, Assists, GroupLabel}; |
18 | utils::{insert_use, MergeBehaviour}, | ||
19 | AssistContext, AssistId, AssistKind, Assists, GroupLabel, | ||
20 | }; | ||
21 | 18 | ||
22 | // Assist: auto_import | 19 | // Assist: auto_import |
23 | // | 20 | // |
@@ -60,7 +57,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
60 | let new_syntax = insert_use( | 57 | let new_syntax = insert_use( |
61 | &scope, | 58 | &scope, |
62 | make::path_from_text(&import.to_string()), | 59 | make::path_from_text(&import.to_string()), |
63 | Some(MergeBehaviour::Full), | 60 | ctx.config.insert_use.merge, |
64 | ); | 61 | ); |
65 | builder.replace(syntax.text_range(), new_syntax.to_string()) | 62 | builder.replace(syntax.text_range(), new_syntax.to_string()) |
66 | }, | 63 | }, |
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs index 80c62d8bb..3ea50f375 100644 --- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -10,9 +10,7 @@ use syntax::{ | |||
10 | }; | 10 | }; |
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | assist_context::AssistBuilder, | 13 | assist_context::AssistBuilder, utils::insert_use, AssistContext, AssistId, AssistKind, Assists, |
14 | utils::{insert_use, MergeBehaviour}, | ||
15 | AssistContext, AssistId, AssistKind, Assists, | ||
16 | }; | 14 | }; |
17 | use ast::make; | 15 | use ast::make; |
18 | use insert_use::ImportScope; | 16 | use insert_use::ImportScope; |
@@ -117,7 +115,7 @@ fn insert_import( | |||
117 | let new_syntax = insert_use( | 115 | let new_syntax = insert_use( |
118 | &scope, | 116 | &scope, |
119 | make::path_from_text(&mod_path.to_string()), | 117 | make::path_from_text(&mod_path.to_string()), |
120 | Some(MergeBehaviour::Full), | 118 | ctx.config.insert_use.merge, |
121 | ); | 119 | ); |
122 | // FIXME: this will currently panic as multiple imports will have overlapping text ranges | 120 | // FIXME: this will currently panic as multiple imports will have overlapping text ranges |
123 | builder.replace(syntax.text_range(), new_syntax.to_string()) | 121 | builder.replace(syntax.text_range(), new_syntax.to_string()) |
diff --git a/crates/assists/src/handlers/merge_imports.rs b/crates/assists/src/handlers/merge_imports.rs index 35b884206..0bd679260 100644 --- a/crates/assists/src/handlers/merge_imports.rs +++ b/crates/assists/src/handlers/merge_imports.rs | |||
@@ -1,14 +1,14 @@ | |||
1 | use std::iter::successors; | ||
2 | |||
3 | use syntax::{ | 1 | use syntax::{ |
4 | algo::{neighbor, skip_trivia_token, SyntaxRewriter}, | 2 | algo::{neighbor, SyntaxRewriter}, |
5 | ast::{self, edit::AstNodeEdit, make}, | 3 | ast, AstNode, |
6 | AstNode, Direction, InsertPosition, SyntaxElement, T, | ||
7 | }; | 4 | }; |
8 | 5 | ||
9 | use crate::{ | 6 | use crate::{ |
10 | assist_context::{AssistContext, Assists}, | 7 | assist_context::{AssistContext, Assists}, |
11 | utils::next_prev, | 8 | utils::{ |
9 | insert_use::{try_merge_imports, try_merge_trees}, | ||
10 | next_prev, MergeBehaviour, | ||
11 | }, | ||
12 | AssistId, AssistKind, | 12 | AssistId, AssistKind, |
13 | }; | 13 | }; |
14 | 14 | ||
@@ -30,23 +30,22 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<() | |||
30 | let mut offset = ctx.offset(); | 30 | let mut offset = ctx.offset(); |
31 | 31 | ||
32 | if let Some(use_item) = tree.syntax().parent().and_then(ast::Use::cast) { | 32 | if let Some(use_item) = tree.syntax().parent().and_then(ast::Use::cast) { |
33 | let (merged, to_delete) = next_prev() | 33 | let (merged, to_delete) = |
34 | .filter_map(|dir| neighbor(&use_item, dir)) | 34 | next_prev().filter_map(|dir| neighbor(&use_item, dir)).find_map(|use_item2| { |
35 | .filter_map(|it| Some((it.clone(), it.use_tree()?))) | 35 | try_merge_imports(&use_item, &use_item2, MergeBehaviour::Full).zip(Some(use_item2)) |
36 | .find_map(|(use_item, use_tree)| { | ||
37 | Some((try_merge_trees(&tree, &use_tree)?, use_item)) | ||
38 | })?; | 36 | })?; |
39 | 37 | ||
40 | rewriter.replace_ast(&tree, &merged); | 38 | rewriter.replace_ast(&use_item, &merged); |
41 | rewriter += to_delete.remove(); | 39 | rewriter += to_delete.remove(); |
42 | 40 | ||
43 | if to_delete.syntax().text_range().end() < offset { | 41 | if to_delete.syntax().text_range().end() < offset { |
44 | offset -= to_delete.syntax().text_range().len(); | 42 | offset -= to_delete.syntax().text_range().len(); |
45 | } | 43 | } |
46 | } else { | 44 | } else { |
47 | let (merged, to_delete) = next_prev() | 45 | let (merged, to_delete) = |
48 | .filter_map(|dir| neighbor(&tree, dir)) | 46 | next_prev().filter_map(|dir| neighbor(&tree, dir)).find_map(|use_tree| { |
49 | .find_map(|use_tree| Some((try_merge_trees(&tree, &use_tree)?, use_tree.clone())))?; | 47 | try_merge_trees(&tree, &use_tree, MergeBehaviour::Full).zip(Some(use_tree)) |
48 | })?; | ||
50 | 49 | ||
51 | rewriter.replace_ast(&tree, &merged); | 50 | rewriter.replace_ast(&tree, &merged); |
52 | rewriter += to_delete.remove(); | 51 | rewriter += to_delete.remove(); |
@@ -67,66 +66,6 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<() | |||
67 | ) | 66 | ) |
68 | } | 67 | } |
69 | 68 | ||
70 | fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option<ast::UseTree> { | ||
71 | let lhs_path = old.path()?; | ||
72 | let rhs_path = new.path()?; | ||
73 | |||
74 | let (lhs_prefix, rhs_prefix) = common_prefix(&lhs_path, &rhs_path)?; | ||
75 | |||
76 | let lhs = old.split_prefix(&lhs_prefix); | ||
77 | let rhs = new.split_prefix(&rhs_prefix); | ||
78 | |||
79 | let should_insert_comma = lhs | ||
80 | .use_tree_list()? | ||
81 | .r_curly_token() | ||
82 | .and_then(|it| skip_trivia_token(it.prev_token()?, Direction::Prev)) | ||
83 | .map(|it| it.kind() != T![,]) | ||
84 | .unwrap_or(true); | ||
85 | |||
86 | let mut to_insert: Vec<SyntaxElement> = Vec::new(); | ||
87 | if should_insert_comma { | ||
88 | to_insert.push(make::token(T![,]).into()); | ||
89 | to_insert.push(make::tokens::single_space().into()); | ||
90 | } | ||
91 | to_insert.extend( | ||
92 | rhs.use_tree_list()? | ||
93 | .syntax() | ||
94 | .children_with_tokens() | ||
95 | .filter(|it| it.kind() != T!['{'] && it.kind() != T!['}']), | ||
96 | ); | ||
97 | let use_tree_list = lhs.use_tree_list()?; | ||
98 | let pos = InsertPosition::Before(use_tree_list.r_curly_token()?.into()); | ||
99 | let use_tree_list = use_tree_list.insert_children(pos, to_insert); | ||
100 | Some(lhs.with_use_tree_list(use_tree_list)) | ||
101 | } | ||
102 | |||
103 | fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Path)> { | ||
104 | let mut res = None; | ||
105 | let mut lhs_curr = first_path(&lhs); | ||
106 | let mut rhs_curr = first_path(&rhs); | ||
107 | loop { | ||
108 | match (lhs_curr.segment(), rhs_curr.segment()) { | ||
109 | (Some(lhs), Some(rhs)) if lhs.syntax().text() == rhs.syntax().text() => (), | ||
110 | _ => break, | ||
111 | } | ||
112 | res = Some((lhs_curr.clone(), rhs_curr.clone())); | ||
113 | |||
114 | match (lhs_curr.parent_path(), rhs_curr.parent_path()) { | ||
115 | (Some(lhs), Some(rhs)) => { | ||
116 | lhs_curr = lhs; | ||
117 | rhs_curr = rhs; | ||
118 | } | ||
119 | _ => break, | ||
120 | } | ||
121 | } | ||
122 | |||
123 | res | ||
124 | } | ||
125 | |||
126 | fn first_path(path: &ast::Path) -> ast::Path { | ||
127 | successors(Some(path.clone()), |it| it.qualifier()).last().unwrap() | ||
128 | } | ||
129 | |||
130 | #[cfg(test)] | 69 | #[cfg(test)] |
131 | mod tests { | 70 | mod tests { |
132 | use crate::tests::{check_assist, check_assist_not_applicable}; | 71 | use crate::tests::{check_assist, check_assist_not_applicable}; |
@@ -189,6 +128,78 @@ use std::{fmt::{Display, self}}; | |||
189 | } | 128 | } |
190 | 129 | ||
191 | #[test] | 130 | #[test] |
131 | fn skip_pub1() { | ||
132 | check_assist_not_applicable( | ||
133 | merge_imports, | ||
134 | r" | ||
135 | pub use std::fmt<|>::Debug; | ||
136 | use std::fmt::Display; | ||
137 | ", | ||
138 | ); | ||
139 | } | ||
140 | |||
141 | #[test] | ||
142 | fn skip_pub_last() { | ||
143 | check_assist_not_applicable( | ||
144 | merge_imports, | ||
145 | r" | ||
146 | use std::fmt<|>::Debug; | ||
147 | pub use std::fmt::Display; | ||
148 | ", | ||
149 | ); | ||
150 | } | ||
151 | |||
152 | #[test] | ||
153 | fn skip_pub_crate_pub() { | ||
154 | check_assist_not_applicable( | ||
155 | merge_imports, | ||
156 | r" | ||
157 | pub(crate) use std::fmt<|>::Debug; | ||
158 | pub use std::fmt::Display; | ||
159 | ", | ||
160 | ); | ||
161 | } | ||
162 | |||
163 | #[test] | ||
164 | fn skip_pub_pub_crate() { | ||
165 | check_assist_not_applicable( | ||
166 | merge_imports, | ||
167 | r" | ||
168 | pub use std::fmt<|>::Debug; | ||
169 | pub(crate) use std::fmt::Display; | ||
170 | ", | ||
171 | ); | ||
172 | } | ||
173 | |||
174 | #[test] | ||
175 | fn merge_pub() { | ||
176 | check_assist( | ||
177 | merge_imports, | ||
178 | r" | ||
179 | pub use std::fmt<|>::Debug; | ||
180 | pub use std::fmt::Display; | ||
181 | ", | ||
182 | r" | ||
183 | pub use std::fmt::{Debug, Display}; | ||
184 | ", | ||
185 | ) | ||
186 | } | ||
187 | |||
188 | #[test] | ||
189 | fn merge_pub_crate() { | ||
190 | check_assist( | ||
191 | merge_imports, | ||
192 | r" | ||
193 | pub(crate) use std::fmt<|>::Debug; | ||
194 | pub(crate) use std::fmt::Display; | ||
195 | ", | ||
196 | r" | ||
197 | pub(crate) use std::fmt::{Debug, Display}; | ||
198 | ", | ||
199 | ) | ||
200 | } | ||
201 | |||
202 | #[test] | ||
192 | fn test_merge_nested() { | 203 | fn test_merge_nested() { |
193 | check_assist( | 204 | check_assist( |
194 | merge_imports, | 205 | merge_imports, |
diff --git a/crates/assists/src/handlers/remove_dbg.rs b/crates/assists/src/handlers/remove_dbg.rs index 4e252edf0..a8ab2aecc 100644 --- a/crates/assists/src/handlers/remove_dbg.rs +++ b/crates/assists/src/handlers/remove_dbg.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use syntax::{ | 1 | use syntax::{ |
2 | ast::{self, AstNode}, | 2 | ast::{self, AstNode}, |
3 | TextRange, TextSize, T, | 3 | SyntaxElement, TextRange, TextSize, T, |
4 | }; | 4 | }; |
5 | 5 | ||
6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 6 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
@@ -22,62 +22,108 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; | |||
22 | // ``` | 22 | // ``` |
23 | pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 23 | pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
24 | let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?; | 24 | let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?; |
25 | let new_contents = adjusted_macro_contents(¯o_call)?; | ||
25 | 26 | ||
26 | if !is_valid_macrocall(¯o_call, "dbg")? { | 27 | let macro_text_range = macro_call.syntax().text_range(); |
27 | return None; | ||
28 | } | ||
29 | |||
30 | let is_leaf = macro_call.syntax().next_sibling().is_none(); | ||
31 | |||
32 | let macro_end = if macro_call.semicolon_token().is_some() { | 28 | let macro_end = if macro_call.semicolon_token().is_some() { |
33 | macro_call.syntax().text_range().end() - TextSize::of(';') | 29 | macro_text_range.end() - TextSize::of(';') |
34 | } else { | 30 | } else { |
35 | macro_call.syntax().text_range().end() | 31 | macro_text_range.end() |
36 | }; | 32 | }; |
37 | 33 | ||
38 | // macro_range determines what will be deleted and replaced with macro_content | 34 | acc.add( |
39 | let macro_range = TextRange::new(macro_call.syntax().text_range().start(), macro_end); | 35 | AssistId("remove_dbg", AssistKind::Refactor), |
40 | let paste_instead_of_dbg = { | 36 | "Remove dbg!()", |
41 | let text = macro_call.token_tree()?.syntax().text(); | 37 | macro_text_range, |
42 | 38 | |builder| { | |
43 | // leafiness determines if we should include the parenthesis or not | 39 | builder.replace(TextRange::new(macro_text_range.start(), macro_end), new_contents); |
44 | let slice_index: TextRange = if is_leaf { | 40 | }, |
45 | // leaf means - we can extract the contents of the dbg! in text | 41 | ) |
46 | TextRange::new(TextSize::of('('), text.len() - TextSize::of(')')) | 42 | } |
47 | } else { | ||
48 | // not leaf - means we should keep the parens | ||
49 | TextRange::up_to(text.len()) | ||
50 | }; | ||
51 | text.slice(slice_index).to_string() | ||
52 | }; | ||
53 | 43 | ||
54 | let target = macro_call.syntax().text_range(); | 44 | fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> { |
55 | acc.add(AssistId("remove_dbg", AssistKind::Refactor), "Remove dbg!()", target, |builder| { | 45 | let contents = get_valid_macrocall_contents(¯o_call, "dbg")?; |
56 | builder.replace(macro_range, paste_instead_of_dbg); | 46 | let macro_text_with_brackets = macro_call.token_tree()?.syntax().text(); |
47 | let macro_text_in_brackets = macro_text_with_brackets.slice(TextRange::new( | ||
48 | TextSize::of('('), | ||
49 | macro_text_with_brackets.len() - TextSize::of(')'), | ||
50 | )); | ||
51 | |||
52 | let is_leaf = macro_call.syntax().next_sibling().is_none(); | ||
53 | Some(if !is_leaf && needs_parentheses_around_macro_contents(contents) { | ||
54 | format!("({})", macro_text_in_brackets) | ||
55 | } else { | ||
56 | macro_text_in_brackets.to_string() | ||
57 | }) | 57 | }) |
58 | } | 58 | } |
59 | 59 | ||
60 | /// Verifies that the given macro_call actually matches the given name | 60 | /// Verifies that the given macro_call actually matches the given name |
61 | /// and contains proper ending tokens | 61 | /// and contains proper ending tokens, then returns the contents between the ending tokens |
62 | fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<bool> { | 62 | fn get_valid_macrocall_contents( |
63 | macro_call: &ast::MacroCall, | ||
64 | macro_name: &str, | ||
65 | ) -> Option<Vec<SyntaxElement>> { | ||
63 | let path = macro_call.path()?; | 66 | let path = macro_call.path()?; |
64 | let name_ref = path.segment()?.name_ref()?; | 67 | let name_ref = path.segment()?.name_ref()?; |
65 | 68 | ||
66 | // Make sure it is actually a dbg-macro call, dbg followed by ! | 69 | // Make sure it is actually a dbg-macro call, dbg followed by ! |
67 | let excl = path.syntax().next_sibling_or_token()?; | 70 | let excl = path.syntax().next_sibling_or_token()?; |
68 | |||
69 | if name_ref.text() != macro_name || excl.kind() != T![!] { | 71 | if name_ref.text() != macro_name || excl.kind() != T![!] { |
70 | return None; | 72 | return None; |
71 | } | 73 | } |
72 | 74 | ||
73 | let node = macro_call.token_tree()?.syntax().clone(); | 75 | let mut children_with_tokens = macro_call.token_tree()?.syntax().children_with_tokens(); |
74 | let first_child = node.first_child_or_token()?; | 76 | let first_child = children_with_tokens.next()?; |
75 | let last_child = node.last_child_or_token()?; | 77 | let mut contents_between_brackets = children_with_tokens.collect::<Vec<_>>(); |
78 | let last_child = contents_between_brackets.pop()?; | ||
79 | |||
80 | if contents_between_brackets.is_empty() { | ||
81 | None | ||
82 | } else { | ||
83 | match (first_child.kind(), last_child.kind()) { | ||
84 | (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => { | ||
85 | Some(contents_between_brackets) | ||
86 | } | ||
87 | _ => None, | ||
88 | } | ||
89 | } | ||
90 | } | ||
76 | 91 | ||
77 | match (first_child.kind(), last_child.kind()) { | 92 | fn needs_parentheses_around_macro_contents(macro_contents: Vec<SyntaxElement>) -> bool { |
78 | (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => Some(true), | 93 | if macro_contents.len() < 2 { |
79 | _ => Some(false), | 94 | return false; |
80 | } | 95 | } |
96 | let mut unpaired_brackets_in_contents = Vec::new(); | ||
97 | for element in macro_contents { | ||
98 | match element.kind() { | ||
99 | T!['('] | T!['['] | T!['{'] => unpaired_brackets_in_contents.push(element), | ||
100 | T![')'] => { | ||
101 | if !matches!(unpaired_brackets_in_contents.pop(), Some(correct_bracket) if correct_bracket.kind() == T!['(']) | ||
102 | { | ||
103 | return true; | ||
104 | } | ||
105 | } | ||
106 | T![']'] => { | ||
107 | if !matches!(unpaired_brackets_in_contents.pop(), Some(correct_bracket) if correct_bracket.kind() == T!['[']) | ||
108 | { | ||
109 | return true; | ||
110 | } | ||
111 | } | ||
112 | T!['}'] => { | ||
113 | if !matches!(unpaired_brackets_in_contents.pop(), Some(correct_bracket) if correct_bracket.kind() == T!['{']) | ||
114 | { | ||
115 | return true; | ||
116 | } | ||
117 | } | ||
118 | symbol_kind => { | ||
119 | let symbol_not_in_bracket = unpaired_brackets_in_contents.is_empty(); | ||
120 | if symbol_not_in_bracket && symbol_kind.is_punct() { | ||
121 | return true; | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | !unpaired_brackets_in_contents.is_empty() | ||
81 | } | 127 | } |
82 | 128 | ||
83 | #[cfg(test)] | 129 | #[cfg(test)] |
@@ -157,12 +203,38 @@ fn foo(n: usize) { | |||
157 | } | 203 | } |
158 | 204 | ||
159 | #[test] | 205 | #[test] |
206 | fn remove_dbg_from_non_leaf_simple_expression() { | ||
207 | check_assist( | ||
208 | remove_dbg, | ||
209 | " | ||
210 | fn main() { | ||
211 | let mut a = 1; | ||
212 | while dbg!<|>(a) < 10000 { | ||
213 | a += 1; | ||
214 | } | ||
215 | } | ||
216 | ", | ||
217 | " | ||
218 | fn main() { | ||
219 | let mut a = 1; | ||
220 | while a < 10000 { | ||
221 | a += 1; | ||
222 | } | ||
223 | } | ||
224 | ", | ||
225 | ); | ||
226 | } | ||
227 | |||
228 | #[test] | ||
160 | fn test_remove_dbg_keep_expression() { | 229 | fn test_remove_dbg_keep_expression() { |
161 | check_assist( | 230 | check_assist( |
162 | remove_dbg, | 231 | remove_dbg, |
163 | r#"let res = <|>dbg!(a + b).foo();"#, | 232 | r#"let res = <|>dbg!(a + b).foo();"#, |
164 | r#"let res = (a + b).foo();"#, | 233 | r#"let res = (a + b).foo();"#, |
165 | ); | 234 | ); |
235 | |||
236 | check_assist(remove_dbg, r#"let res = <|>dbg!(2 + 2) * 5"#, r#"let res = (2 + 2) * 5"#); | ||
237 | check_assist(remove_dbg, r#"let res = <|>dbg![2 + 2] * 5"#, r#"let res = (2 + 2) * 5"#); | ||
166 | } | 238 | } |
167 | 239 | ||
168 | #[test] | 240 | #[test] |
diff --git a/crates/assists/src/handlers/replace_qualified_name_with_use.rs b/crates/assists/src/handlers/replace_qualified_name_with_use.rs index 85c70d16b..e48407fcc 100644 --- a/crates/assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -2,7 +2,7 @@ use syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SyntaxNode, TextRang | |||
2 | use test_utils::mark; | 2 | use test_utils::mark; |
3 | 3 | ||
4 | use crate::{ | 4 | use crate::{ |
5 | utils::{insert_use, ImportScope, MergeBehaviour}, | 5 | utils::{insert_use, ImportScope}, |
6 | AssistContext, AssistId, AssistKind, Assists, | 6 | AssistContext, AssistId, AssistKind, Assists, |
7 | }; | 7 | }; |
8 | use ast::make; | 8 | use ast::make; |
@@ -60,7 +60,7 @@ pub(crate) fn replace_qualified_name_with_use( | |||
60 | let new_syntax = insert_use( | 60 | let new_syntax = insert_use( |
61 | import_scope, | 61 | import_scope, |
62 | make::path_from_text(path_to_import), | 62 | make::path_from_text(path_to_import), |
63 | Some(MergeBehaviour::Full), | 63 | ctx.config.insert_use.merge, |
64 | ); | 64 | ); |
65 | builder.replace(syntax.text_range(), new_syntax.to_string()) | 65 | builder.replace(syntax.text_range(), new_syntax.to_string()) |
66 | } | 66 | } |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index 7559ddd63..b0511ceb6 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -16,7 +16,8 @@ use syntax::{ | |||
16 | 16 | ||
17 | use crate::assist_config::SnippetCap; | 17 | use crate::assist_config::SnippetCap; |
18 | 18 | ||
19 | pub(crate) use insert_use::{insert_use, ImportScope, MergeBehaviour}; | 19 | pub use insert_use::MergeBehaviour; |
20 | pub(crate) use insert_use::{insert_use, ImportScope}; | ||
20 | 21 | ||
21 | pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { | 22 | pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { |
22 | extract_trivial_expression(&block) | 23 | extract_trivial_expression(&block) |
diff --git a/crates/assists/src/utils/insert_use.rs b/crates/assists/src/utils/insert_use.rs index 8a4c8520d..6d110aaaf 100644 --- a/crates/assists/src/utils/insert_use.rs +++ b/crates/assists/src/utils/insert_use.rs | |||
@@ -138,13 +138,23 @@ pub(crate) fn insert_use( | |||
138 | algo::insert_children(scope.as_syntax_node(), insert_position, to_insert) | 138 | algo::insert_children(scope.as_syntax_node(), insert_position, to_insert) |
139 | } | 139 | } |
140 | 140 | ||
141 | fn try_merge_imports( | 141 | fn eq_visibility(vis0: Option<ast::Visibility>, vis1: Option<ast::Visibility>) -> bool { |
142 | match (vis0, vis1) { | ||
143 | (None, None) => true, | ||
144 | // FIXME: Don't use the string representation to check for equality | ||
145 | // spaces inside of the node would break this comparison | ||
146 | (Some(vis0), Some(vis1)) => vis0.to_string() == vis1.to_string(), | ||
147 | _ => false, | ||
148 | } | ||
149 | } | ||
150 | |||
151 | pub(crate) fn try_merge_imports( | ||
142 | old: &ast::Use, | 152 | old: &ast::Use, |
143 | new: &ast::Use, | 153 | new: &ast::Use, |
144 | merge_behaviour: MergeBehaviour, | 154 | merge_behaviour: MergeBehaviour, |
145 | ) -> Option<ast::Use> { | 155 | ) -> Option<ast::Use> { |
146 | // don't merge into re-exports | 156 | // don't merge imports with different visibilities |
147 | if old.visibility().and_then(|vis| vis.pub_token()).is_some() { | 157 | if !eq_visibility(old.visibility(), new.visibility()) { |
148 | return None; | 158 | return None; |
149 | } | 159 | } |
150 | let old_tree = old.use_tree()?; | 160 | let old_tree = old.use_tree()?; |
@@ -161,7 +171,7 @@ fn use_tree_list_is_nested(tl: &ast::UseTreeList) -> bool { | |||
161 | } | 171 | } |
162 | 172 | ||
163 | // FIXME: currently this merely prepends the new tree into old, ideally it would insert the items in a sorted fashion | 173 | // FIXME: currently this merely prepends the new tree into old, ideally it would insert the items in a sorted fashion |
164 | pub fn try_merge_trees( | 174 | pub(crate) fn try_merge_trees( |
165 | old: &ast::UseTree, | 175 | old: &ast::UseTree, |
166 | new: &ast::UseTree, | 176 | new: &ast::UseTree, |
167 | merge_behaviour: MergeBehaviour, | 177 | merge_behaviour: MergeBehaviour, |
@@ -226,7 +236,7 @@ fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Pa | |||
226 | } | 236 | } |
227 | 237 | ||
228 | /// What type of merges are allowed. | 238 | /// What type of merges are allowed. |
229 | #[derive(Copy, Clone, PartialEq, Eq)] | 239 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
230 | pub enum MergeBehaviour { | 240 | pub enum MergeBehaviour { |
231 | /// Merge everything together creating deeply nested imports. | 241 | /// Merge everything together creating deeply nested imports. |
232 | Full, | 242 | Full, |
@@ -278,7 +288,8 @@ fn first_path(path: &ast::Path) -> ast::Path { | |||
278 | } | 288 | } |
279 | 289 | ||
280 | fn segment_iter(path: &ast::Path) -> impl Iterator<Item = ast::PathSegment> + Clone { | 290 | fn segment_iter(path: &ast::Path) -> impl Iterator<Item = ast::PathSegment> + Clone { |
281 | path.syntax().children().flat_map(ast::PathSegment::cast) | 291 | // cant make use of SyntaxNode::siblings, because the returned Iterator is not clone |
292 | successors(first_segment(path), |p| p.parent_path().parent_path().and_then(|p| p.segment())) | ||
282 | } | 293 | } |
283 | 294 | ||
284 | #[derive(PartialEq, Eq)] | 295 | #[derive(PartialEq, Eq)] |
@@ -684,8 +695,18 @@ use std::io;", | |||
684 | check_last( | 695 | check_last( |
685 | "foo::bar", | 696 | "foo::bar", |
686 | r"use foo::bar::baz::Qux;", | 697 | r"use foo::bar::baz::Qux;", |
687 | r"use foo::bar::baz::Qux; | 698 | r"use foo::bar; |
688 | use foo::bar;", | 699 | use foo::bar::baz::Qux;", |
700 | ); | ||
701 | } | ||
702 | |||
703 | #[test] | ||
704 | fn insert_short_before_long() { | ||
705 | check_none( | ||
706 | "foo::bar", | ||
707 | r"use foo::bar::baz::Qux;", | ||
708 | r"use foo::bar; | ||
709 | use foo::bar::baz::Qux;", | ||
689 | ); | 710 | ); |
690 | } | 711 | } |
691 | 712 | ||
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index c2fc819e7..7a9747fc7 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -1283,6 +1283,8 @@ impl Type { | |||
1283 | /// Checks that particular type `ty` implements `std::future::Future`. | 1283 | /// Checks that particular type `ty` implements `std::future::Future`. |
1284 | /// This function is used in `.await` syntax completion. | 1284 | /// This function is used in `.await` syntax completion. |
1285 | pub fn impls_future(&self, db: &dyn HirDatabase) -> bool { | 1285 | pub fn impls_future(&self, db: &dyn HirDatabase) -> bool { |
1286 | // No special case for the type of async block, since Chalk can figure it out. | ||
1287 | |||
1286 | let krate = self.krate; | 1288 | let krate = self.krate; |
1287 | 1289 | ||
1288 | let std_future_trait = | 1290 | let std_future_trait = |
@@ -1600,6 +1602,11 @@ impl Type { | |||
1600 | cb(type_.derived(ty.clone())); | 1602 | cb(type_.derived(ty.clone())); |
1601 | } | 1603 | } |
1602 | } | 1604 | } |
1605 | TypeCtor::OpaqueType(..) => { | ||
1606 | if let Some(bounds) = ty.impl_trait_bounds(db) { | ||
1607 | walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); | ||
1608 | } | ||
1609 | } | ||
1603 | _ => (), | 1610 | _ => (), |
1604 | } | 1611 | } |
1605 | 1612 | ||
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 1594d4f0f..0516a05b4 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -207,8 +207,8 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
207 | self.imp.resolve_record_field(field) | 207 | self.imp.resolve_record_field(field) |
208 | } | 208 | } |
209 | 209 | ||
210 | pub fn resolve_record_field_pat(&self, field: &ast::RecordPatField) -> Option<Field> { | 210 | pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<Field> { |
211 | self.imp.resolve_record_field_pat(field) | 211 | self.imp.resolve_record_pat_field(field) |
212 | } | 212 | } |
213 | 213 | ||
214 | pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> { | 214 | pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> { |
@@ -433,8 +433,8 @@ impl<'db> SemanticsImpl<'db> { | |||
433 | self.analyze(field.syntax()).resolve_record_field(self.db, field) | 433 | self.analyze(field.syntax()).resolve_record_field(self.db, field) |
434 | } | 434 | } |
435 | 435 | ||
436 | fn resolve_record_field_pat(&self, field: &ast::RecordPatField) -> Option<Field> { | 436 | fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<Field> { |
437 | self.analyze(field.syntax()).resolve_record_field_pat(self.db, field) | 437 | self.analyze(field.syntax()).resolve_record_pat_field(self.db, field) |
438 | } | 438 | } |
439 | 439 | ||
440 | fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> { | 440 | fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> { |
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 1d13c4f1d..1aef0f33f 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs | |||
@@ -179,13 +179,13 @@ impl SourceAnalyzer { | |||
179 | Some((struct_field.into(), local)) | 179 | Some((struct_field.into(), local)) |
180 | } | 180 | } |
181 | 181 | ||
182 | pub(crate) fn resolve_record_field_pat( | 182 | pub(crate) fn resolve_record_pat_field( |
183 | &self, | 183 | &self, |
184 | _db: &dyn HirDatabase, | 184 | _db: &dyn HirDatabase, |
185 | field: &ast::RecordPatField, | 185 | field: &ast::RecordPatField, |
186 | ) -> Option<Field> { | 186 | ) -> Option<Field> { |
187 | let pat_id = self.pat_id(&field.pat()?)?; | 187 | let pat_id = self.pat_id(&field.pat()?)?; |
188 | let struct_field = self.infer.as_ref()?.record_field_pat_resolution(pat_id)?; | 188 | let struct_field = self.infer.as_ref()?.record_pat_field_resolution(pat_id)?; |
189 | Some(struct_field.into()) | 189 | Some(struct_field.into()) |
190 | } | 190 | } |
191 | 191 | ||
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 30ac12a12..2d91bb21f 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
@@ -239,7 +239,10 @@ impl ExprCollector<'_> { | |||
239 | None => self.missing_expr(), | 239 | None => self.missing_expr(), |
240 | }, | 240 | }, |
241 | // FIXME: we need to record these effects somewhere... | 241 | // FIXME: we need to record these effects somewhere... |
242 | ast::Effect::Async(_) => self.collect_block_opt(e.block_expr()), | 242 | ast::Effect::Async(_) => { |
243 | let body = self.collect_block_opt(e.block_expr()); | ||
244 | self.alloc_expr(Expr::Async { body }, syntax_ptr) | ||
245 | } | ||
243 | }, | 246 | }, |
244 | ast::Expr::BlockExpr(e) => self.collect_block(e), | 247 | ast::Expr::BlockExpr(e) => self.collect_block(e), |
245 | ast::Expr::LoopExpr(e) => { | 248 | ast::Expr::LoopExpr(e) => { |
@@ -835,8 +838,12 @@ impl ExprCollector<'_> { | |||
835 | 838 | ||
836 | Pat::Missing | 839 | Pat::Missing |
837 | } | 840 | } |
841 | ast::Pat::BoxPat(boxpat) => { | ||
842 | let inner = self.collect_pat_opt(boxpat.pat()); | ||
843 | Pat::Box { inner } | ||
844 | } | ||
838 | // FIXME: implement | 845 | // FIXME: implement |
839 | ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, | 846 | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, |
840 | }; | 847 | }; |
841 | let ptr = AstPtr::new(&pat); | 848 | let ptr = AstPtr::new(&pat); |
842 | self.alloc_pat(pattern, Either::Left(ptr)) | 849 | self.alloc_pat(pattern, Either::Left(ptr)) |
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs index c94b3a36f..e5d740a36 100644 --- a/crates/hir_def/src/expr.rs +++ b/crates/hir_def/src/expr.rs | |||
@@ -111,6 +111,9 @@ pub enum Expr { | |||
111 | TryBlock { | 111 | TryBlock { |
112 | body: ExprId, | 112 | body: ExprId, |
113 | }, | 113 | }, |
114 | Async { | ||
115 | body: ExprId, | ||
116 | }, | ||
114 | Cast { | 117 | Cast { |
115 | expr: ExprId, | 118 | expr: ExprId, |
116 | type_ref: TypeRef, | 119 | type_ref: TypeRef, |
@@ -250,7 +253,7 @@ impl Expr { | |||
250 | f(*expr); | 253 | f(*expr); |
251 | } | 254 | } |
252 | } | 255 | } |
253 | Expr::TryBlock { body } | Expr::Unsafe { body } => f(*body), | 256 | Expr::TryBlock { body } | Expr::Unsafe { body } | Expr::Async { body } => f(*body), |
254 | Expr::Loop { body, .. } => f(*body), | 257 | Expr::Loop { body, .. } => f(*body), |
255 | Expr::While { condition, body, .. } => { | 258 | Expr::While { condition, body, .. } => { |
256 | f(*condition); | 259 | f(*condition); |
@@ -395,6 +398,7 @@ pub enum Pat { | |||
395 | Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> }, | 398 | Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> }, |
396 | TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, | 399 | TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, |
397 | Ref { pat: PatId, mutability: Mutability }, | 400 | Ref { pat: PatId, mutability: Mutability }, |
401 | Box { inner: PatId }, | ||
398 | } | 402 | } |
399 | 403 | ||
400 | impl Pat { | 404 | impl Pat { |
@@ -415,6 +419,7 @@ impl Pat { | |||
415 | Pat::Record { args, .. } => { | 419 | Pat::Record { args, .. } => { |
416 | args.iter().map(|f| f.pat).for_each(f); | 420 | args.iter().map(|f| f.pat).for_each(f); |
417 | } | 421 | } |
422 | Pat::Box { inner } => f(*inner), | ||
418 | } | 423 | } |
419 | } | 424 | } |
420 | } | 425 | } |
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index 64b68014d..efb48c7ee 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -381,19 +381,24 @@ impl HirDisplay for ApplicationTy { | |||
381 | } | 381 | } |
382 | } | 382 | } |
383 | TypeCtor::OpaqueType(opaque_ty_id) => { | 383 | TypeCtor::OpaqueType(opaque_ty_id) => { |
384 | let bounds = match opaque_ty_id { | 384 | match opaque_ty_id { |
385 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { | 385 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { |
386 | let datas = | 386 | let datas = |
387 | f.db.return_type_impl_traits(func).expect("impl trait id without data"); | 387 | f.db.return_type_impl_traits(func).expect("impl trait id without data"); |
388 | let data = (*datas) | 388 | let data = (*datas) |
389 | .as_ref() | 389 | .as_ref() |
390 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | 390 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); |
391 | data.subst(&self.parameters) | 391 | let bounds = data.subst(&self.parameters); |
392 | write!(f, "impl ")?; | ||
393 | write_bounds_like_dyn_trait(&bounds.value, f)?; | ||
394 | // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution | ||
392 | } | 395 | } |
393 | }; | 396 | OpaqueTyId::AsyncBlockTypeImplTrait(..) => { |
394 | write!(f, "impl ")?; | 397 | write!(f, "impl Future<Output = ")?; |
395 | write_bounds_like_dyn_trait(&bounds.value, f)?; | 398 | self.parameters[0].hir_fmt(f)?; |
396 | // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution | 399 | write!(f, ">")?; |
400 | } | ||
401 | } | ||
397 | } | 402 | } |
398 | TypeCtor::Closure { .. } => { | 403 | TypeCtor::Closure { .. } => { |
399 | let sig = self.parameters[0].callable_sig(f.db); | 404 | let sig = self.parameters[0].callable_sig(f.db); |
@@ -474,18 +479,21 @@ impl HirDisplay for Ty { | |||
474 | write_bounds_like_dyn_trait(predicates, f)?; | 479 | write_bounds_like_dyn_trait(predicates, f)?; |
475 | } | 480 | } |
476 | Ty::Opaque(opaque_ty) => { | 481 | Ty::Opaque(opaque_ty) => { |
477 | let bounds = match opaque_ty.opaque_ty_id { | 482 | match opaque_ty.opaque_ty_id { |
478 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { | 483 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { |
479 | let datas = | 484 | let datas = |
480 | f.db.return_type_impl_traits(func).expect("impl trait id without data"); | 485 | f.db.return_type_impl_traits(func).expect("impl trait id without data"); |
481 | let data = (*datas) | 486 | let data = (*datas) |
482 | .as_ref() | 487 | .as_ref() |
483 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | 488 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); |
484 | data.subst(&opaque_ty.parameters) | 489 | let bounds = data.subst(&opaque_ty.parameters); |
490 | write!(f, "impl ")?; | ||
491 | write_bounds_like_dyn_trait(&bounds.value, f)?; | ||
492 | } | ||
493 | OpaqueTyId::AsyncBlockTypeImplTrait(..) => { | ||
494 | write!(f, "{{async block}}")?; | ||
485 | } | 495 | } |
486 | }; | 496 | }; |
487 | write!(f, "impl ")?; | ||
488 | write_bounds_like_dyn_trait(&bounds.value, f)?; | ||
489 | } | 497 | } |
490 | Ty::Unknown => write!(f, "{{unknown}}")?, | 498 | Ty::Unknown => write!(f, "{{unknown}}")?, |
491 | Ty::Infer(..) => write!(f, "_")?, | 499 | Ty::Infer(..) => write!(f, "_")?, |
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index 03b00b101..2b53b8297 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
@@ -125,7 +125,7 @@ pub struct InferenceResult { | |||
125 | field_resolutions: FxHashMap<ExprId, FieldId>, | 125 | field_resolutions: FxHashMap<ExprId, FieldId>, |
126 | /// For each field in record literal, records the field it resolves to. | 126 | /// For each field in record literal, records the field it resolves to. |
127 | record_field_resolutions: FxHashMap<ExprId, FieldId>, | 127 | record_field_resolutions: FxHashMap<ExprId, FieldId>, |
128 | record_field_pat_resolutions: FxHashMap<PatId, FieldId>, | 128 | record_pat_field_resolutions: FxHashMap<PatId, FieldId>, |
129 | /// For each struct literal, records the variant it resolves to. | 129 | /// For each struct literal, records the variant it resolves to. |
130 | variant_resolutions: FxHashMap<ExprOrPatId, VariantId>, | 130 | variant_resolutions: FxHashMap<ExprOrPatId, VariantId>, |
131 | /// For each associated item record what it resolves to | 131 | /// For each associated item record what it resolves to |
@@ -146,8 +146,8 @@ impl InferenceResult { | |||
146 | pub fn record_field_resolution(&self, expr: ExprId) -> Option<FieldId> { | 146 | pub fn record_field_resolution(&self, expr: ExprId) -> Option<FieldId> { |
147 | self.record_field_resolutions.get(&expr).copied() | 147 | self.record_field_resolutions.get(&expr).copied() |
148 | } | 148 | } |
149 | pub fn record_field_pat_resolution(&self, pat: PatId) -> Option<FieldId> { | 149 | pub fn record_pat_field_resolution(&self, pat: PatId) -> Option<FieldId> { |
150 | self.record_field_pat_resolutions.get(&pat).copied() | 150 | self.record_pat_field_resolutions.get(&pat).copied() |
151 | } | 151 | } |
152 | pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> { | 152 | pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> { |
153 | self.variant_resolutions.get(&id.into()).copied() | 153 | self.variant_resolutions.get(&id.into()).copied() |
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index a2f849d02..0a141b9cb 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs | |||
@@ -17,8 +17,8 @@ use crate::{ | |||
17 | autoderef, method_resolution, op, | 17 | autoderef, method_resolution, op, |
18 | traits::{FnTrait, InEnvironment}, | 18 | traits::{FnTrait, InEnvironment}, |
19 | utils::{generics, variant_data, Generics}, | 19 | utils::{generics, variant_data, Generics}, |
20 | ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, | 20 | ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, OpaqueTyId, |
21 | TraitRef, Ty, TypeCtor, | 21 | Rawness, Substs, TraitRef, Ty, TypeCtor, |
22 | }; | 22 | }; |
23 | 23 | ||
24 | use super::{ | 24 | use super::{ |
@@ -146,6 +146,13 @@ impl<'a> InferenceContext<'a> { | |||
146 | // FIXME should be std::result::Result<{inner}, _> | 146 | // FIXME should be std::result::Result<{inner}, _> |
147 | Ty::Unknown | 147 | Ty::Unknown |
148 | } | 148 | } |
149 | Expr::Async { body } => { | ||
150 | // Use the first type parameter as the output type of future. | ||
151 | // existenail type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType> | ||
152 | let inner_ty = self.infer_expr(*body, &Expectation::none()); | ||
153 | let opaque_ty_id = OpaqueTyId::AsyncBlockTypeImplTrait(self.owner, *body); | ||
154 | Ty::apply_one(TypeCtor::OpaqueType(opaque_ty_id), inner_ty) | ||
155 | } | ||
149 | Expr::Loop { body, label } => { | 156 | Expr::Loop { body, label } => { |
150 | self.breakables.push(BreakableContext { | 157 | self.breakables.push(BreakableContext { |
151 | may_break: false, | 158 | may_break: false, |
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index 4dd4f9802..cde2ab82b 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs | |||
@@ -70,7 +70,7 @@ impl<'a> InferenceContext<'a> { | |||
70 | let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name)); | 70 | let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name)); |
71 | if let Some(local_id) = matching_field { | 71 | if let Some(local_id) = matching_field { |
72 | let field_def = FieldId { parent: def.unwrap(), local_id }; | 72 | let field_def = FieldId { parent: def.unwrap(), local_id }; |
73 | self.result.record_field_pat_resolutions.insert(subpat.pat, field_def); | 73 | self.result.record_pat_field_resolutions.insert(subpat.pat, field_def); |
74 | } | 74 | } |
75 | 75 | ||
76 | let expected_ty = | 76 | let expected_ty = |
@@ -209,6 +209,18 @@ impl<'a> InferenceContext<'a> { | |||
209 | end_ty | 209 | end_ty |
210 | } | 210 | } |
211 | Pat::Lit(expr) => self.infer_expr(*expr, &Expectation::has_type(expected.clone())), | 211 | Pat::Lit(expr) => self.infer_expr(*expr, &Expectation::has_type(expected.clone())), |
212 | Pat::Box { inner } => match self.resolve_boxed_box() { | ||
213 | Some(box_adt) => { | ||
214 | let inner_expected = match expected.as_adt() { | ||
215 | Some((adt, substs)) if adt == box_adt => substs.as_single(), | ||
216 | _ => &Ty::Unknown, | ||
217 | }; | ||
218 | |||
219 | let inner_ty = self.infer_pat(*inner, inner_expected, default_bm); | ||
220 | Ty::apply_one(TypeCtor::Adt(box_adt), inner_ty) | ||
221 | } | ||
222 | None => Ty::Unknown, | ||
223 | }, | ||
212 | Pat::Missing => Ty::Unknown, | 224 | Pat::Missing => Ty::Unknown, |
213 | }; | 225 | }; |
214 | // use a new type variable if we got Ty::Unknown here | 226 | // use a new type variable if we got Ty::Unknown here |
@@ -236,6 +248,6 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { | |||
236 | Expr::Literal(Literal::String(..)) => false, | 248 | Expr::Literal(Literal::String(..)) => false, |
237 | _ => true, | 249 | _ => true, |
238 | }, | 250 | }, |
239 | Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false, | 251 | Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false, |
240 | } | 252 | } |
241 | } | 253 | } |
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs index 1e748476a..f16d1fc97 100644 --- a/crates/hir_ty/src/lib.rs +++ b/crates/hir_ty/src/lib.rs | |||
@@ -129,8 +129,9 @@ pub enum TypeCtor { | |||
129 | 129 | ||
130 | /// This represents a placeholder for an opaque type in situations where we | 130 | /// This represents a placeholder for an opaque type in situations where we |
131 | /// don't know the hidden type (i.e. currently almost always). This is | 131 | /// don't know the hidden type (i.e. currently almost always). This is |
132 | /// analogous to the `AssociatedType` type constructor. As with that one, | 132 | /// analogous to the `AssociatedType` type constructor. |
133 | /// these are only produced by Chalk. | 133 | /// It is also used as the type of async block, with one type parameter |
134 | /// representing the Future::Output type. | ||
134 | OpaqueType(OpaqueTyId), | 135 | OpaqueType(OpaqueTyId), |
135 | 136 | ||
136 | /// The type of a specific closure. | 137 | /// The type of a specific closure. |
@@ -173,6 +174,8 @@ impl TypeCtor { | |||
173 | let generic_params = generics(db.upcast(), func.into()); | 174 | let generic_params = generics(db.upcast(), func.into()); |
174 | generic_params.len() | 175 | generic_params.len() |
175 | } | 176 | } |
177 | // 1 param representing Future::Output type. | ||
178 | OpaqueTyId::AsyncBlockTypeImplTrait(..) => 1, | ||
176 | } | 179 | } |
177 | } | 180 | } |
178 | TypeCtor::FnPtr { num_args, is_varargs: _ } => num_args as usize + 1, | 181 | TypeCtor::FnPtr { num_args, is_varargs: _ } => num_args as usize + 1, |
@@ -205,6 +208,7 @@ impl TypeCtor { | |||
205 | OpaqueTyId::ReturnTypeImplTrait(func, _) => { | 208 | OpaqueTyId::ReturnTypeImplTrait(func, _) => { |
206 | Some(func.lookup(db.upcast()).module(db.upcast()).krate) | 209 | Some(func.lookup(db.upcast()).module(db.upcast()).krate) |
207 | } | 210 | } |
211 | OpaqueTyId::AsyncBlockTypeImplTrait(def, _) => Some(def.module(db.upcast()).krate), | ||
208 | }, | 212 | }, |
209 | } | 213 | } |
210 | } | 214 | } |
@@ -843,6 +847,29 @@ impl Ty { | |||
843 | 847 | ||
844 | pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> { | 848 | pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> { |
845 | match self { | 849 | match self { |
850 | Ty::Apply(ApplicationTy { ctor: TypeCtor::OpaqueType(opaque_ty_id), .. }) => { | ||
851 | match opaque_ty_id { | ||
852 | OpaqueTyId::AsyncBlockTypeImplTrait(def, _expr) => { | ||
853 | let krate = def.module(db.upcast()).krate; | ||
854 | if let Some(future_trait) = db | ||
855 | .lang_item(krate, "future_trait".into()) | ||
856 | .and_then(|item| item.as_trait()) | ||
857 | { | ||
858 | // This is only used by type walking. | ||
859 | // Parameters will be walked outside, and projection predicate is not used. | ||
860 | // So just provide the Future trait. | ||
861 | let impl_bound = GenericPredicate::Implemented(TraitRef { | ||
862 | trait_: future_trait, | ||
863 | substs: Substs::empty(), | ||
864 | }); | ||
865 | Some(vec![impl_bound]) | ||
866 | } else { | ||
867 | None | ||
868 | } | ||
869 | } | ||
870 | OpaqueTyId::ReturnTypeImplTrait(..) => None, | ||
871 | } | ||
872 | } | ||
846 | Ty::Opaque(opaque_ty) => { | 873 | Ty::Opaque(opaque_ty) => { |
847 | let predicates = match opaque_ty.opaque_ty_id { | 874 | let predicates = match opaque_ty.opaque_ty_id { |
848 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { | 875 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { |
@@ -853,6 +880,8 @@ impl Ty { | |||
853 | data.subst(&opaque_ty.parameters) | 880 | data.subst(&opaque_ty.parameters) |
854 | }) | 881 | }) |
855 | } | 882 | } |
883 | // It always has an parameter for Future::Output type. | ||
884 | OpaqueTyId::AsyncBlockTypeImplTrait(..) => unreachable!(), | ||
856 | }; | 885 | }; |
857 | 886 | ||
858 | predicates.map(|it| it.value) | 887 | predicates.map(|it| it.value) |
@@ -1065,6 +1094,7 @@ impl<T: TypeWalk> TypeWalk for Vec<T> { | |||
1065 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] | 1094 | #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] |
1066 | pub enum OpaqueTyId { | 1095 | pub enum OpaqueTyId { |
1067 | ReturnTypeImplTrait(hir_def::FunctionId, u16), | 1096 | ReturnTypeImplTrait(hir_def::FunctionId, u16), |
1097 | AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId), | ||
1068 | } | 1098 | } |
1069 | 1099 | ||
1070 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 1100 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs index aeb191c79..6a965ac4f 100644 --- a/crates/hir_ty/src/tests/patterns.rs +++ b/crates/hir_ty/src/tests/patterns.rs | |||
@@ -654,3 +654,28 @@ fn slice_tail_pattern() { | |||
654 | "#]], | 654 | "#]], |
655 | ); | 655 | ); |
656 | } | 656 | } |
657 | |||
658 | #[test] | ||
659 | fn box_pattern() { | ||
660 | check_infer( | ||
661 | r#" | ||
662 | #[lang = "owned_box"] | ||
663 | pub struct Box<T>(T); | ||
664 | |||
665 | fn foo(params: Box<i32>) { | ||
666 | match params { | ||
667 | box integer => {} | ||
668 | } | ||
669 | } | ||
670 | "#, | ||
671 | expect![[r#" | ||
672 | 52..58 'params': Box<i32> | ||
673 | 70..124 '{ ... } }': () | ||
674 | 76..122 'match ... }': () | ||
675 | 82..88 'params': Box<i32> | ||
676 | 99..110 'box integer': Box<i32> | ||
677 | 103..110 'integer': i32 | ||
678 | 114..116 '{}': () | ||
679 | "#]], | ||
680 | ); | ||
681 | } | ||
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index 48db23a34..5b07948f3 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs | |||
@@ -1889,31 +1889,40 @@ fn fn_pointer_return() { | |||
1889 | fn effects_smoke_test() { | 1889 | fn effects_smoke_test() { |
1890 | check_infer( | 1890 | check_infer( |
1891 | r#" | 1891 | r#" |
1892 | fn main() { | 1892 | async fn main() { |
1893 | let x = unsafe { 92 }; | 1893 | let x = unsafe { 92 }; |
1894 | let y = async { async { () }.await }; | 1894 | let y = async { async { () }.await }; |
1895 | let z = try { () }; | 1895 | let z = try { () }; |
1896 | let t = 'a: { 92 }; | 1896 | let t = 'a: { 92 }; |
1897 | } | 1897 | } |
1898 | |||
1899 | #[prelude_import] use future::*; | ||
1900 | |||
1901 | mod future { | ||
1902 | #[lang = "future_trait"] | ||
1903 | pub trait Future { type Output; } | ||
1904 | } | ||
1898 | "#, | 1905 | "#, |
1899 | expect![[r#" | 1906 | expect![[r#" |
1900 | 10..130 '{ ...2 }; }': () | 1907 | 16..136 '{ ...2 }; }': () |
1901 | 20..21 'x': i32 | 1908 | 26..27 'x': i32 |
1902 | 24..37 'unsafe { 92 }': i32 | 1909 | 30..43 'unsafe { 92 }': i32 |
1903 | 31..37 '{ 92 }': i32 | 1910 | 37..43 '{ 92 }': i32 |
1904 | 33..35 '92': i32 | 1911 | 39..41 '92': i32 |
1905 | 47..48 'y': {unknown} | 1912 | 53..54 'y': impl Future<Output = ()> |
1906 | 57..79 '{ asyn...wait }': {unknown} | 1913 | 57..85 'async ...wait }': impl Future<Output = ()> |
1907 | 59..77 'async ....await': {unknown} | 1914 | 63..85 '{ asyn...wait }': () |
1908 | 65..71 '{ () }': () | 1915 | 65..77 'async { () }': impl Future<Output = ()> |
1909 | 67..69 '()': () | 1916 | 65..83 'async ....await': () |
1910 | 89..90 'z': {unknown} | 1917 | 71..77 '{ () }': () |
1911 | 93..103 'try { () }': {unknown} | 1918 | 73..75 '()': () |
1912 | 97..103 '{ () }': () | 1919 | 95..96 'z': {unknown} |
1913 | 99..101 '()': () | 1920 | 99..109 'try { () }': {unknown} |
1914 | 113..114 't': i32 | 1921 | 103..109 '{ () }': () |
1915 | 121..127 '{ 92 }': i32 | 1922 | 105..107 '()': () |
1916 | 123..125 '92': i32 | 1923 | 119..120 't': i32 |
1924 | 127..133 '{ 92 }': i32 | ||
1925 | 129..131 '92': i32 | ||
1917 | "#]], | 1926 | "#]], |
1918 | ) | 1927 | ) |
1919 | } | 1928 | } |
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 1f1056962..41d097519 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs | |||
@@ -86,6 +86,46 @@ mod future { | |||
86 | } | 86 | } |
87 | 87 | ||
88 | #[test] | 88 | #[test] |
89 | fn infer_async_block() { | ||
90 | check_types( | ||
91 | r#" | ||
92 | //- /main.rs crate:main deps:core | ||
93 | async fn test() { | ||
94 | let a = async { 42 }; | ||
95 | a; | ||
96 | // ^ impl Future<Output = i32> | ||
97 | let x = a.await; | ||
98 | x; | ||
99 | // ^ i32 | ||
100 | let b = async {}.await; | ||
101 | b; | ||
102 | // ^ () | ||
103 | let c = async { | ||
104 | let y = Option::None; | ||
105 | y | ||
106 | // ^ Option<u64> | ||
107 | }; | ||
108 | let _: Option<u64> = c.await; | ||
109 | c; | ||
110 | // ^ impl Future<Output = Option<u64>> | ||
111 | } | ||
112 | |||
113 | enum Option<T> { None, Some(T) } | ||
114 | |||
115 | //- /core.rs crate:core | ||
116 | #[prelude_import] use future::*; | ||
117 | mod future { | ||
118 | #[lang = "future_trait"] | ||
119 | trait Future { | ||
120 | type Output; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | "#, | ||
125 | ); | ||
126 | } | ||
127 | |||
128 | #[test] | ||
89 | fn infer_try() { | 129 | fn infer_try() { |
90 | check_types( | 130 | check_types( |
91 | r#" | 131 | r#" |
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs index 01b5717a3..57d0a32df 100644 --- a/crates/hir_ty/src/traits/chalk.rs +++ b/crates/hir_ty/src/traits/chalk.rs | |||
@@ -11,6 +11,7 @@ use hir_def::{ | |||
11 | lang_item::{lang_attr, LangItemTarget}, | 11 | lang_item::{lang_attr, LangItemTarget}, |
12 | AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId, | 12 | AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId, |
13 | }; | 13 | }; |
14 | use hir_expand::name::name; | ||
14 | 15 | ||
15 | use super::ChalkContext; | 16 | use super::ChalkContext; |
16 | use crate::{ | 17 | use crate::{ |
@@ -18,7 +19,8 @@ use crate::{ | |||
18 | display::HirDisplay, | 19 | display::HirDisplay, |
19 | method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, | 20 | method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, |
20 | utils::generics, | 21 | utils::generics, |
21 | CallableDefId, DebruijnIndex, FnSig, GenericPredicate, Substs, Ty, TypeCtor, | 22 | BoundVar, CallableDefId, DebruijnIndex, FnSig, GenericPredicate, ProjectionPredicate, |
23 | ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | ||
22 | }; | 24 | }; |
23 | use mapping::{ | 25 | use mapping::{ |
24 | convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue, | 26 | convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue, |
@@ -166,27 +168,88 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
166 | fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> { | 168 | fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> { |
167 | let interned_id = crate::db::InternedOpaqueTyId::from(id); | 169 | let interned_id = crate::db::InternedOpaqueTyId::from(id); |
168 | let full_id = self.db.lookup_intern_impl_trait_id(interned_id); | 170 | let full_id = self.db.lookup_intern_impl_trait_id(interned_id); |
169 | let (func, idx) = match full_id { | 171 | let bound = match full_id { |
170 | crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => (func, idx), | 172 | crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => { |
171 | }; | 173 | let datas = self |
172 | let datas = | 174 | .db |
173 | self.db.return_type_impl_traits(func).expect("impl trait id without impl traits"); | 175 | .return_type_impl_traits(func) |
174 | let data = &datas.value.impl_traits[idx as usize]; | 176 | .expect("impl trait id without impl traits"); |
175 | let bound = OpaqueTyDatumBound { | 177 | let data = &datas.value.impl_traits[idx as usize]; |
176 | bounds: make_binders( | 178 | let bound = OpaqueTyDatumBound { |
177 | data.bounds | 179 | bounds: make_binders( |
178 | .value | 180 | data.bounds |
179 | .iter() | 181 | .value |
180 | .cloned() | 182 | .iter() |
181 | .filter(|b| !b.is_error()) | 183 | .cloned() |
182 | .map(|b| b.to_chalk(self.db)) | 184 | .filter(|b| !b.is_error()) |
183 | .collect(), | 185 | .map(|b| b.to_chalk(self.db)) |
184 | 1, | 186 | .collect(), |
185 | ), | 187 | 1, |
186 | where_clauses: make_binders(vec![], 0), | 188 | ), |
189 | where_clauses: make_binders(vec![], 0), | ||
190 | }; | ||
191 | let num_vars = datas.num_binders; | ||
192 | make_binders(bound, num_vars) | ||
193 | } | ||
194 | crate::OpaqueTyId::AsyncBlockTypeImplTrait(..) => { | ||
195 | if let Some((future_trait, future_output)) = self | ||
196 | .db | ||
197 | .lang_item(self.krate, "future_trait".into()) | ||
198 | .and_then(|item| item.as_trait()) | ||
199 | .and_then(|trait_| { | ||
200 | let alias = | ||
201 | self.db.trait_data(trait_).associated_type_by_name(&name![Output])?; | ||
202 | Some((trait_, alias)) | ||
203 | }) | ||
204 | { | ||
205 | // Making up `AsyncBlock<T>: Future<Output = T>` | ||
206 | // | ||
207 | // |--------------------OpaqueTyDatum-------------------| | ||
208 | // |-------------OpaqueTyDatumBound--------------| | ||
209 | // for<T> <Self> [Future<Self>, Future::Output<Self> = T] | ||
210 | // ^1 ^0 ^0 ^0 ^1 | ||
211 | let impl_bound = GenericPredicate::Implemented(TraitRef { | ||
212 | trait_: future_trait, | ||
213 | // Self type as the first parameter. | ||
214 | substs: Substs::single(Ty::Bound(BoundVar { | ||
215 | debruijn: DebruijnIndex::INNERMOST, | ||
216 | index: 0, | ||
217 | })), | ||
218 | }); | ||
219 | let proj_bound = GenericPredicate::Projection(ProjectionPredicate { | ||
220 | // The parameter of the opaque type. | ||
221 | ty: Ty::Bound(BoundVar { debruijn: DebruijnIndex::ONE, index: 0 }), | ||
222 | projection_ty: ProjectionTy { | ||
223 | associated_ty: future_output, | ||
224 | // Self type as the first parameter. | ||
225 | parameters: Substs::single(Ty::Bound(BoundVar::new( | ||
226 | DebruijnIndex::INNERMOST, | ||
227 | 0, | ||
228 | ))), | ||
229 | }, | ||
230 | }); | ||
231 | let bound = OpaqueTyDatumBound { | ||
232 | bounds: make_binders( | ||
233 | vec![impl_bound.to_chalk(self.db), proj_bound.to_chalk(self.db)], | ||
234 | 1, | ||
235 | ), | ||
236 | where_clauses: make_binders(vec![], 0), | ||
237 | }; | ||
238 | // The opaque type has 1 parameter. | ||
239 | make_binders(bound, 1) | ||
240 | } else { | ||
241 | // If failed to find `Future::Output`, return empty bounds as fallback. | ||
242 | let bound = OpaqueTyDatumBound { | ||
243 | bounds: make_binders(vec![], 0), | ||
244 | where_clauses: make_binders(vec![], 0), | ||
245 | }; | ||
246 | // The opaque type has 1 parameter. | ||
247 | make_binders(bound, 1) | ||
248 | } | ||
249 | } | ||
187 | }; | 250 | }; |
188 | let num_vars = datas.num_binders; | 251 | |
189 | Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound: make_binders(bound, num_vars) }) | 252 | Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound }) |
190 | } | 253 | } |
191 | 254 | ||
192 | fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> { | 255 | fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> { |
diff --git a/crates/hir_ty/src/traits/chalk/tls.rs b/crates/hir_ty/src/traits/chalk/tls.rs index db915625c..cb6b0fe81 100644 --- a/crates/hir_ty/src/traits/chalk/tls.rs +++ b/crates/hir_ty/src/traits/chalk/tls.rs | |||
@@ -73,6 +73,9 @@ impl DebugContext<'_> { | |||
73 | crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => { | 73 | crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => { |
74 | write!(f, "{{impl trait {} of {:?}}}", idx, func)?; | 74 | write!(f, "{{impl trait {} of {:?}}}", idx, func)?; |
75 | } | 75 | } |
76 | crate::OpaqueTyId::AsyncBlockTypeImplTrait(def, idx) => { | ||
77 | write!(f, "{{impl trait of async block {} of {:?}}}", idx.into_raw(), def)?; | ||
78 | } | ||
76 | }, | 79 | }, |
77 | TypeCtor::Closure { def, expr } => { | 80 | TypeCtor::Closure { def, expr } => { |
78 | write!(f, "{{closure {:?} in ", expr.into_raw())?; | 81 | write!(f, "{{closure {:?} in ", expr.into_raw())?; |
diff --git a/crates/ide/src/completion/complete_keyword.rs b/crates/ide/src/completion/complete_keyword.rs index 53ba76e0e..5645b41fa 100644 --- a/crates/ide/src/completion/complete_keyword.rs +++ b/crates/ide/src/completion/complete_keyword.rs | |||
@@ -510,6 +510,28 @@ pub mod future { | |||
510 | expect![[r#" | 510 | expect![[r#" |
511 | kw await expr.await | 511 | kw await expr.await |
512 | "#]], | 512 | "#]], |
513 | ); | ||
514 | |||
515 | check( | ||
516 | r#" | ||
517 | //- /main.rs | ||
518 | use std::future::*; | ||
519 | fn foo() { | ||
520 | let a = async {}; | ||
521 | a.<|> | ||
522 | } | ||
523 | |||
524 | //- /std/lib.rs | ||
525 | pub mod future { | ||
526 | #[lang = "future_trait"] | ||
527 | pub trait Future { | ||
528 | type Output; | ||
529 | } | ||
530 | } | ||
531 | "#, | ||
532 | expect![[r#" | ||
533 | kw await expr.await | ||
534 | "#]], | ||
513 | ) | 535 | ) |
514 | } | 536 | } |
515 | 537 | ||
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index efec0184e..37171cbef 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -2647,6 +2647,70 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {} | |||
2647 | } | 2647 | } |
2648 | 2648 | ||
2649 | #[test] | 2649 | #[test] |
2650 | fn test_hover_async_block_impl_trait_has_goto_type_action() { | ||
2651 | check_actions( | ||
2652 | r#" | ||
2653 | struct S; | ||
2654 | fn foo() { | ||
2655 | let fo<|>o = async { S }; | ||
2656 | } | ||
2657 | |||
2658 | #[prelude_import] use future::*; | ||
2659 | mod future { | ||
2660 | #[lang = "future_trait"] | ||
2661 | pub trait Future { type Output; } | ||
2662 | } | ||
2663 | "#, | ||
2664 | expect![[r#" | ||
2665 | [ | ||
2666 | GoToType( | ||
2667 | [ | ||
2668 | HoverGotoTypeData { | ||
2669 | mod_path: "test::future::Future", | ||
2670 | nav: NavigationTarget { | ||
2671 | file_id: FileId( | ||
2672 | 1, | ||
2673 | ), | ||
2674 | full_range: 101..163, | ||
2675 | focus_range: Some( | ||
2676 | 140..146, | ||
2677 | ), | ||
2678 | name: "Future", | ||
2679 | kind: TRAIT, | ||
2680 | container_name: None, | ||
2681 | description: Some( | ||
2682 | "pub trait Future", | ||
2683 | ), | ||
2684 | docs: None, | ||
2685 | }, | ||
2686 | }, | ||
2687 | HoverGotoTypeData { | ||
2688 | mod_path: "test::S", | ||
2689 | nav: NavigationTarget { | ||
2690 | file_id: FileId( | ||
2691 | 1, | ||
2692 | ), | ||
2693 | full_range: 0..9, | ||
2694 | focus_range: Some( | ||
2695 | 7..8, | ||
2696 | ), | ||
2697 | name: "S", | ||
2698 | kind: STRUCT, | ||
2699 | container_name: None, | ||
2700 | description: Some( | ||
2701 | "struct S", | ||
2702 | ), | ||
2703 | docs: None, | ||
2704 | }, | ||
2705 | }, | ||
2706 | ], | ||
2707 | ), | ||
2708 | ] | ||
2709 | "#]], | ||
2710 | ); | ||
2711 | } | ||
2712 | |||
2713 | #[test] | ||
2650 | fn test_hover_arg_generic_impl_trait_has_goto_type_action() { | 2714 | fn test_hover_arg_generic_impl_trait_has_goto_type_action() { |
2651 | check_actions( | 2715 | check_actions( |
2652 | r#" | 2716 | r#" |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index 570790384..3b97e087f 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -81,7 +81,9 @@ pub use crate::{ | |||
81 | }, | 81 | }, |
82 | }; | 82 | }; |
83 | 83 | ||
84 | pub use assists::{Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist}; | 84 | pub use assists::{ |
85 | utils::MergeBehaviour, Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist, | ||
86 | }; | ||
85 | pub use base_db::{ | 87 | pub use base_db::{ |
86 | Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot, | 88 | Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot, |
87 | SourceRootId, | 89 | SourceRootId, |
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs index 0d0affc27..f8c7aa491 100644 --- a/crates/ide_db/src/defs.rs +++ b/crates/ide_db/src/defs.rs | |||
@@ -157,9 +157,9 @@ pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option | |||
157 | ast::IdentPat(it) => { | 157 | ast::IdentPat(it) => { |
158 | let local = sema.to_def(&it)?; | 158 | let local = sema.to_def(&it)?; |
159 | 159 | ||
160 | if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordPatField::cast) { | 160 | if let Some(record_pat_field) = it.syntax().parent().and_then(ast::RecordPatField::cast) { |
161 | if record_field_pat.name_ref().is_none() { | 161 | if record_pat_field.name_ref().is_none() { |
162 | if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) { | 162 | if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) { |
163 | let field = Definition::Field(field); | 163 | let field = Definition::Field(field); |
164 | return Some(NameClass::FieldShorthand { local, field }); | 164 | return Some(NameClass::FieldShorthand { local, field }); |
165 | } | 165 | } |
@@ -275,8 +275,8 @@ pub fn classify_name_ref( | |||
275 | } | 275 | } |
276 | } | 276 | } |
277 | 277 | ||
278 | if let Some(record_field_pat) = ast::RecordPatField::cast(parent.clone()) { | 278 | if let Some(record_pat_field) = ast::RecordPatField::cast(parent.clone()) { |
279 | if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) { | 279 | if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) { |
280 | let field = Definition::Field(field); | 280 | let field = Definition::Field(field); |
281 | return Some(NameRefClass::Definition(field)); | 281 | return Some(NameRefClass::Definition(field)); |
282 | } | 282 | } |
diff --git a/crates/parser/src/grammar/patterns.rs b/crates/parser/src/grammar/patterns.rs index 796f206e1..7e7f73dee 100644 --- a/crates/parser/src/grammar/patterns.rs +++ b/crates/parser/src/grammar/patterns.rs | |||
@@ -188,7 +188,7 @@ fn tuple_pat_fields(p: &mut Parser) { | |||
188 | p.expect(T![')']); | 188 | p.expect(T![')']); |
189 | } | 189 | } |
190 | 190 | ||
191 | // test record_field_pat_list | 191 | // test record_pat_field_list |
192 | // fn foo() { | 192 | // fn foo() { |
193 | // let S {} = (); | 193 | // let S {} = (); |
194 | // let S { f, ref mut g } = (); | 194 | // let S { f, ref mut g } = (); |
@@ -208,7 +208,7 @@ fn record_pat_field_list(p: &mut Parser) { | |||
208 | c => { | 208 | c => { |
209 | let m = p.start(); | 209 | let m = p.start(); |
210 | match c { | 210 | match c { |
211 | // test record_field_pat | 211 | // test record_pat_field |
212 | // fn foo() { | 212 | // fn foo() { |
213 | // let S { 0: 1 } = (); | 213 | // let S { 0: 1 } = (); |
214 | // let S { x: 1 } = (); | 214 | // let S { x: 1 } = (); |
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs index 2d91939ce..288c39e49 100644 --- a/crates/project_model/src/lib.rs +++ b/crates/project_model/src/lib.rs | |||
@@ -33,7 +33,7 @@ pub enum ProjectWorkspace { | |||
33 | /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. | 33 | /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. |
34 | Cargo { cargo: CargoWorkspace, sysroot: Sysroot }, | 34 | Cargo { cargo: CargoWorkspace, sysroot: Sysroot }, |
35 | /// Project workspace was manually specified using a `rust-project.json` file. | 35 | /// Project workspace was manually specified using a `rust-project.json` file. |
36 | Json { project: ProjectJson }, | 36 | Json { project: ProjectJson, sysroot: Option<Sysroot> }, |
37 | } | 37 | } |
38 | 38 | ||
39 | impl fmt::Debug for ProjectWorkspace { | 39 | impl fmt::Debug for ProjectWorkspace { |
@@ -44,10 +44,10 @@ impl fmt::Debug for ProjectWorkspace { | |||
44 | .field("n_packages", &cargo.packages().len()) | 44 | .field("n_packages", &cargo.packages().len()) |
45 | .field("n_sysroot_crates", &sysroot.crates().len()) | 45 | .field("n_sysroot_crates", &sysroot.crates().len()) |
46 | .finish(), | 46 | .finish(), |
47 | ProjectWorkspace::Json { project } => { | 47 | ProjectWorkspace::Json { project, sysroot } => { |
48 | let mut debug_struct = f.debug_struct("Json"); | 48 | let mut debug_struct = f.debug_struct("Json"); |
49 | debug_struct.field("n_crates", &project.n_crates()); | 49 | debug_struct.field("n_crates", &project.n_crates()); |
50 | if let Some(sysroot) = &project.sysroot { | 50 | if let Some(sysroot) = sysroot { |
51 | debug_struct.field("n_sysroot_crates", &sysroot.crates().len()); | 51 | debug_struct.field("n_sysroot_crates", &sysroot.crates().len()); |
52 | } | 52 | } |
53 | debug_struct.finish() | 53 | debug_struct.finish() |
@@ -169,7 +169,11 @@ impl ProjectWorkspace { | |||
169 | })?; | 169 | })?; |
170 | let project_location = project_json.parent().unwrap().to_path_buf(); | 170 | let project_location = project_json.parent().unwrap().to_path_buf(); |
171 | let project = ProjectJson::new(&project_location, data); | 171 | let project = ProjectJson::new(&project_location, data); |
172 | ProjectWorkspace::Json { project } | 172 | let sysroot = match &project.sysroot_src { |
173 | Some(path) => Some(Sysroot::load(path)?), | ||
174 | None => None, | ||
175 | }; | ||
176 | ProjectWorkspace::Json { project, sysroot } | ||
173 | } | 177 | } |
174 | ProjectManifest::CargoToml(cargo_toml) => { | 178 | ProjectManifest::CargoToml(cargo_toml) => { |
175 | let cargo_version = utf8_stdout({ | 179 | let cargo_version = utf8_stdout({ |
@@ -203,12 +207,21 @@ impl ProjectWorkspace { | |||
203 | Ok(res) | 207 | Ok(res) |
204 | } | 208 | } |
205 | 209 | ||
210 | pub fn load_inline(project_json: ProjectJson) -> Result<ProjectWorkspace> { | ||
211 | let sysroot = match &project_json.sysroot_src { | ||
212 | Some(path) => Some(Sysroot::load(path)?), | ||
213 | None => None, | ||
214 | }; | ||
215 | |||
216 | Ok(ProjectWorkspace::Json { project: project_json, sysroot }) | ||
217 | } | ||
218 | |||
206 | /// Returns the roots for the current `ProjectWorkspace` | 219 | /// Returns the roots for the current `ProjectWorkspace` |
207 | /// The return type contains the path and whether or not | 220 | /// The return type contains the path and whether or not |
208 | /// the root is a member of the current workspace | 221 | /// the root is a member of the current workspace |
209 | pub fn to_roots(&self) -> Vec<PackageRoot> { | 222 | pub fn to_roots(&self) -> Vec<PackageRoot> { |
210 | match self { | 223 | match self { |
211 | ProjectWorkspace::Json { project } => project | 224 | ProjectWorkspace::Json { project, sysroot } => project |
212 | .crates() | 225 | .crates() |
213 | .map(|(_, krate)| PackageRoot { | 226 | .map(|(_, krate)| PackageRoot { |
214 | is_member: krate.is_workspace_member, | 227 | is_member: krate.is_workspace_member, |
@@ -217,7 +230,7 @@ impl ProjectWorkspace { | |||
217 | }) | 230 | }) |
218 | .collect::<FxHashSet<_>>() | 231 | .collect::<FxHashSet<_>>() |
219 | .into_iter() | 232 | .into_iter() |
220 | .chain(project.sysroot.as_ref().into_iter().flat_map(|sysroot| { | 233 | .chain(sysroot.as_ref().into_iter().flat_map(|sysroot| { |
221 | sysroot.crates().map(move |krate| PackageRoot { | 234 | sysroot.crates().map(move |krate| PackageRoot { |
222 | is_member: false, | 235 | is_member: false, |
223 | include: vec![sysroot[krate].root_dir().to_path_buf()], | 236 | include: vec![sysroot[krate].root_dir().to_path_buf()], |
@@ -255,7 +268,7 @@ impl ProjectWorkspace { | |||
255 | 268 | ||
256 | pub fn proc_macro_dylib_paths(&self) -> Vec<AbsPathBuf> { | 269 | pub fn proc_macro_dylib_paths(&self) -> Vec<AbsPathBuf> { |
257 | match self { | 270 | match self { |
258 | ProjectWorkspace::Json { project } => project | 271 | ProjectWorkspace::Json { project, sysroot: _ } => project |
259 | .crates() | 272 | .crates() |
260 | .filter_map(|(_, krate)| krate.proc_macro_dylib_path.as_ref()) | 273 | .filter_map(|(_, krate)| krate.proc_macro_dylib_path.as_ref()) |
261 | .cloned() | 274 | .cloned() |
@@ -285,9 +298,8 @@ impl ProjectWorkspace { | |||
285 | ) -> CrateGraph { | 298 | ) -> CrateGraph { |
286 | let mut crate_graph = CrateGraph::default(); | 299 | let mut crate_graph = CrateGraph::default(); |
287 | match self { | 300 | match self { |
288 | ProjectWorkspace::Json { project } => { | 301 | ProjectWorkspace::Json { project, sysroot } => { |
289 | let sysroot_dps = project | 302 | let sysroot_dps = sysroot |
290 | .sysroot | ||
291 | .as_ref() | 303 | .as_ref() |
292 | .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load)); | 304 | .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load)); |
293 | 305 | ||
diff --git a/crates/project_model/src/project_json.rs b/crates/project_model/src/project_json.rs index 5a0fe749a..979e90058 100644 --- a/crates/project_model/src/project_json.rs +++ b/crates/project_model/src/project_json.rs | |||
@@ -7,12 +7,12 @@ use paths::{AbsPath, AbsPathBuf}; | |||
7 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::FxHashMap; |
8 | use serde::{de, Deserialize}; | 8 | use serde::{de, Deserialize}; |
9 | 9 | ||
10 | use crate::{cfg_flag::CfgFlag, Sysroot}; | 10 | use crate::cfg_flag::CfgFlag; |
11 | 11 | ||
12 | /// Roots and crates that compose this Rust project. | 12 | /// Roots and crates that compose this Rust project. |
13 | #[derive(Clone, Debug, Eq, PartialEq)] | 13 | #[derive(Clone, Debug, Eq, PartialEq)] |
14 | pub struct ProjectJson { | 14 | pub struct ProjectJson { |
15 | pub(crate) sysroot: Option<Sysroot>, | 15 | pub(crate) sysroot_src: Option<AbsPathBuf>, |
16 | crates: Vec<Crate>, | 16 | crates: Vec<Crate>, |
17 | } | 17 | } |
18 | 18 | ||
@@ -35,7 +35,7 @@ pub struct Crate { | |||
35 | impl ProjectJson { | 35 | impl ProjectJson { |
36 | pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson { | 36 | pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson { |
37 | ProjectJson { | 37 | ProjectJson { |
38 | sysroot: data.sysroot_src.map(|it| base.join(it)).map(|it| Sysroot::load(&it)), | 38 | sysroot_src: data.sysroot_src.map(|it| base.join(it)), |
39 | crates: data | 39 | crates: data |
40 | .crates | 40 | .crates |
41 | .into_iter() | 41 | .into_iter() |
diff --git a/crates/project_model/src/sysroot.rs b/crates/project_model/src/sysroot.rs index 74c0eda9a..871808d89 100644 --- a/crates/project_model/src/sysroot.rs +++ b/crates/project_model/src/sysroot.rs | |||
@@ -51,11 +51,11 @@ impl Sysroot { | |||
51 | pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> { | 51 | pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> { |
52 | let current_dir = cargo_toml.parent().unwrap(); | 52 | let current_dir = cargo_toml.parent().unwrap(); |
53 | let sysroot_src_dir = discover_sysroot_src_dir(current_dir)?; | 53 | let sysroot_src_dir = discover_sysroot_src_dir(current_dir)?; |
54 | let res = Sysroot::load(&sysroot_src_dir); | 54 | let res = Sysroot::load(&sysroot_src_dir)?; |
55 | Ok(res) | 55 | Ok(res) |
56 | } | 56 | } |
57 | 57 | ||
58 | pub fn load(sysroot_src_dir: &AbsPath) -> Sysroot { | 58 | pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> { |
59 | let mut sysroot = Sysroot { crates: Arena::default() }; | 59 | let mut sysroot = Sysroot { crates: Arena::default() }; |
60 | 60 | ||
61 | for name in SYSROOT_CRATES.trim().lines() { | 61 | for name in SYSROOT_CRATES.trim().lines() { |
@@ -89,7 +89,14 @@ impl Sysroot { | |||
89 | } | 89 | } |
90 | } | 90 | } |
91 | 91 | ||
92 | sysroot | 92 | if sysroot.by_name("core").is_none() { |
93 | anyhow::bail!( | ||
94 | "could not find libcore in sysroot path `{}`", | ||
95 | sysroot_src_dir.as_ref().display() | ||
96 | ); | ||
97 | } | ||
98 | |||
99 | Ok(sysroot) | ||
93 | } | 100 | } |
94 | 101 | ||
95 | fn by_name(&self, name: &str) -> Option<SysrootCrate> { | 102 | fn by_name(&self, name: &str) -> Option<SysrootCrate> { |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 187273bbc..1a74286f5 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -10,7 +10,10 @@ | |||
10 | use std::{ffi::OsString, path::PathBuf}; | 10 | use std::{ffi::OsString, path::PathBuf}; |
11 | 11 | ||
12 | use flycheck::FlycheckConfig; | 12 | use flycheck::FlycheckConfig; |
13 | use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; | 13 | use ide::{ |
14 | AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig, | ||
15 | MergeBehaviour, | ||
16 | }; | ||
14 | use lsp_types::ClientCapabilities; | 17 | use lsp_types::ClientCapabilities; |
15 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; | 18 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; |
16 | use rustc_hash::FxHashSet; | 19 | use rustc_hash::FxHashSet; |
@@ -263,6 +266,12 @@ impl Config { | |||
263 | self.completion.add_call_parenthesis = data.completion_addCallParenthesis; | 266 | self.completion.add_call_parenthesis = data.completion_addCallParenthesis; |
264 | self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets; | 267 | self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets; |
265 | 268 | ||
269 | self.assist.insert_use.merge = match data.assist_importMergeBehaviour { | ||
270 | MergeBehaviourDef::None => None, | ||
271 | MergeBehaviourDef::Full => Some(MergeBehaviour::Full), | ||
272 | MergeBehaviourDef::Last => Some(MergeBehaviour::Last), | ||
273 | }; | ||
274 | |||
266 | self.call_info_full = data.callInfo_full; | 275 | self.call_info_full = data.callInfo_full; |
267 | 276 | ||
268 | self.lens = LensConfig { | 277 | self.lens = LensConfig { |
@@ -370,6 +379,14 @@ enum ManifestOrProjectJson { | |||
370 | ProjectJson(ProjectJsonData), | 379 | ProjectJson(ProjectJsonData), |
371 | } | 380 | } |
372 | 381 | ||
382 | #[derive(Deserialize)] | ||
383 | #[serde(rename_all = "lowercase")] | ||
384 | enum MergeBehaviourDef { | ||
385 | None, | ||
386 | Full, | ||
387 | Last, | ||
388 | } | ||
389 | |||
373 | macro_rules! config_data { | 390 | macro_rules! config_data { |
374 | (struct $name:ident { $($field:ident: $ty:ty = $default:expr,)*}) => { | 391 | (struct $name:ident { $($field:ident: $ty:ty = $default:expr,)*}) => { |
375 | #[allow(non_snake_case)] | 392 | #[allow(non_snake_case)] |
@@ -393,6 +410,8 @@ macro_rules! config_data { | |||
393 | 410 | ||
394 | config_data! { | 411 | config_data! { |
395 | struct ConfigData { | 412 | struct ConfigData { |
413 | assist_importMergeBehaviour: MergeBehaviourDef = MergeBehaviourDef::None, | ||
414 | |||
396 | callInfo_full: bool = true, | 415 | callInfo_full: bool = true, |
397 | 416 | ||
398 | cargo_autoreload: bool = true, | 417 | cargo_autoreload: bool = true, |
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index 20019b944..bab6f8a71 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs | |||
@@ -109,7 +109,7 @@ impl GlobalState { | |||
109 | ) | 109 | ) |
110 | } | 110 | } |
111 | LinkedProject::InlineJsonProject(it) => { | 111 | LinkedProject::InlineJsonProject(it) => { |
112 | Ok(project_model::ProjectWorkspace::Json { project: it.clone() }) | 112 | project_model::ProjectWorkspace::load_inline(it.clone()) |
113 | } | 113 | } |
114 | }) | 114 | }) |
115 | .collect::<Vec<_>>(); | 115 | .collect::<Vec<_>>(); |
diff --git a/crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast b/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rast index 866e60ed8..866e60ed8 100644 --- a/crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast +++ b/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rast | |||
diff --git a/crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rs b/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rs index da3412fa8..da3412fa8 100644 --- a/crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rs +++ b/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rs | |||
diff --git a/crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rast b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast index 925409bdf..925409bdf 100644 --- a/crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rast +++ b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast | |||
diff --git a/crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rs b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rs index 26b1d5f89..26b1d5f89 100644 --- a/crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rs +++ b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rs | |||
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index 63ba4bdf1..33d60d4dd 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json | |||
@@ -1761,9 +1761,9 @@ | |||
1761 | "dev": true | 1761 | "dev": true |
1762 | }, | 1762 | }, |
1763 | "node-fetch": { | 1763 | "node-fetch": { |
1764 | "version": "2.6.0", | 1764 | "version": "2.6.1", |
1765 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", | 1765 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", |
1766 | "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" | 1766 | "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" |
1767 | }, | 1767 | }, |
1768 | "normalize-path": { | 1768 | "normalize-path": { |
1769 | "version": "3.0.0", | 1769 | "version": "3.0.0", |
diff --git a/editors/code/package.json b/editors/code/package.json index 6fc4464df..86a70a89a 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -35,7 +35,7 @@ | |||
35 | "test": "node ./out/tests/runTests.js" | 35 | "test": "node ./out/tests/runTests.js" |
36 | }, | 36 | }, |
37 | "dependencies": { | 37 | "dependencies": { |
38 | "node-fetch": "^2.6.0", | 38 | "node-fetch": "^2.6.1", |
39 | "vscode-languageclient": "7.0.0-next.9" | 39 | "vscode-languageclient": "7.0.0-next.9" |
40 | }, | 40 | }, |
41 | "devDependencies": { | 41 | "devDependencies": { |
@@ -626,6 +626,21 @@ | |||
626 | }, | 626 | }, |
627 | "description": "List of warnings that should be displayed with hint severity.\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel.", | 627 | "description": "List of warnings that should be displayed with hint severity.\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel.", |
628 | "default": [] | 628 | "default": [] |
629 | }, | ||
630 | "rust-analyzer.assist.importMergeBehaviour": { | ||
631 | "type": "string", | ||
632 | "enum": [ | ||
633 | "none", | ||
634 | "full", | ||
635 | "last" | ||
636 | ], | ||
637 | "enumDescriptions": [ | ||
638 | "No merging", | ||
639 | "Merge all layers of the import trees", | ||
640 | "Only merge the last layer of the import trees" | ||
641 | ], | ||
642 | "default": "full", | ||
643 | "description": "The strategy to use when inserting new imports or merging imports." | ||
629 | } | 644 | } |
630 | } | 645 | } |
631 | }, | 646 | }, |