diff options
Diffstat (limited to 'crates')
37 files changed, 684 insertions, 226 deletions
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 | |||