aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/src/assist_config.rs20
-rw-r--r--crates/assists/src/handlers/auto_import.rs7
-rw-r--r--crates/assists/src/handlers/extract_struct_from_enum_variant.rs6
-rw-r--r--crates/assists/src/handlers/merge_imports.rs161
-rw-r--r--crates/assists/src/handlers/remove_dbg.rs144
-rw-r--r--crates/assists/src/handlers/replace_qualified_name_with_use.rs4
-rw-r--r--crates/assists/src/utils.rs3
-rw-r--r--crates/assists/src/utils/insert_use.rs37
-rw-r--r--crates/hir/src/code_model.rs7
-rw-r--r--crates/hir/src/semantics.rs8
-rw-r--r--crates/hir/src/source_analyzer.rs4
-rw-r--r--crates/hir_def/src/body/lower.rs11
-rw-r--r--crates/hir_def/src/expr.rs7
-rw-r--r--crates/hir_ty/src/display.rs28
-rw-r--r--crates/hir_ty/src/infer.rs6
-rw-r--r--crates/hir_ty/src/infer/expr.rs11
-rw-r--r--crates/hir_ty/src/infer/pat.rs16
-rw-r--r--crates/hir_ty/src/lib.rs34
-rw-r--r--crates/hir_ty/src/tests/patterns.rs25
-rw-r--r--crates/hir_ty/src/tests/simple.rs45
-rw-r--r--crates/hir_ty/src/tests/traits.rs40
-rw-r--r--crates/hir_ty/src/traits/chalk.rs105
-rw-r--r--crates/hir_ty/src/traits/chalk/tls.rs3
-rw-r--r--crates/ide/src/completion/complete_keyword.rs22
-rw-r--r--crates/ide/src/hover.rs64
-rw-r--r--crates/ide/src/lib.rs4
-rw-r--r--crates/ide_db/src/defs.rs10
-rw-r--r--crates/parser/src/grammar/patterns.rs4
-rw-r--r--crates/project_model/src/lib.rs32
-rw-r--r--crates/project_model/src/project_json.rs6
-rw-r--r--crates/project_model/src/sysroot.rs13
-rw-r--r--crates/rust-analyzer/src/config.rs21
-rw-r--r--crates/rust-analyzer/src/reload.rs2
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rast (renamed from crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast)0
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rs (renamed from crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rs)0
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast (renamed from crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rast)0
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rs (renamed from crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rs)0
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
7use crate::AssistKind; 7use crate::{utils::MergeBehaviour, AssistKind};
8 8
9#[derive(Clone, Debug, PartialEq, Eq)] 9#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct AssistConfig { 10pub 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
15impl AssistConfig { 16impl AssistConfig {
@@ -25,6 +26,21 @@ pub struct SnippetCap {
25 26
26impl Default for AssistConfig { 27impl 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)]
38pub struct InsertUseConfig {
39 pub merge: Option<MergeBehaviour>,
40}
41
42impl 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
17use crate::{ 17use 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
12use crate::{ 12use 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};
17use ast::make; 15use ast::make;
18use insert_use::ImportScope; 16use 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 @@
1use std::iter::successors;
2
3use syntax::{ 1use 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
9use crate::{ 6use 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
70fn 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
103fn 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
126fn 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)]
131mod tests { 70mod 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"
135pub use std::fmt<|>::Debug;
136use std::fmt::Display;
137",
138 );
139 }
140
141 #[test]
142 fn skip_pub_last() {
143 check_assist_not_applicable(
144 merge_imports,
145 r"
146use std::fmt<|>::Debug;
147pub 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"
157pub(crate) use std::fmt<|>::Debug;
158pub 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"
168pub use std::fmt<|>::Debug;
169pub(crate) use std::fmt::Display;
170",
171 );
172 }
173
174 #[test]
175 fn merge_pub() {
176 check_assist(
177 merge_imports,
178 r"
179pub use std::fmt<|>::Debug;
180pub use std::fmt::Display;
181",
182 r"
183pub use std::fmt::{Debug, Display};
184",
185 )
186 }
187
188 #[test]
189 fn merge_pub_crate() {
190 check_assist(
191 merge_imports,
192 r"
193pub(crate) use std::fmt<|>::Debug;
194pub(crate) use std::fmt::Display;
195",
196 r"
197pub(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 @@
1use syntax::{ 1use syntax::{
2 ast::{self, AstNode}, 2 ast::{self, AstNode},
3 TextRange, TextSize, T, 3 SyntaxElement, TextRange, TextSize, T,
4}; 4};
5 5
6use crate::{AssistContext, AssistId, AssistKind, Assists}; 6use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -22,62 +22,108 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
22// ``` 22// ```
23pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 23pub(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(&macro_call)?;
25 26
26 if !is_valid_macrocall(&macro_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(); 44fn 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(&macro_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
62fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<bool> { 62fn 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()) { 92fn 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 "
210fn main() {
211 let mut a = 1;
212 while dbg!<|>(a) < 10000 {
213 a += 1;
214 }
215}
216",
217 "
218fn 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
2use test_utils::mark; 2use test_utils::mark;
3 3
4use crate::{ 4use crate::{
5 utils::{insert_use, ImportScope, MergeBehaviour}, 5 utils::{insert_use, ImportScope},
6 AssistContext, AssistId, AssistKind, Assists, 6 AssistContext, AssistId, AssistKind, Assists,
7}; 7};
8use ast::make; 8use 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
17use crate::assist_config::SnippetCap; 17use crate::assist_config::SnippetCap;
18 18
19pub(crate) use insert_use::{insert_use, ImportScope, MergeBehaviour}; 19pub use insert_use::MergeBehaviour;
20pub(crate) use insert_use::{insert_use, ImportScope};
20 21
21pub(crate) fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { 22pub(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
141fn try_merge_imports( 141fn 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
151pub(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
164pub fn try_merge_trees( 174pub(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)]
230pub enum MergeBehaviour { 240pub 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
280fn segment_iter(path: &ast::Path) -> impl Iterator<Item = ast::PathSegment> + Clone { 290fn 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;
688use foo::bar;", 699use 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;
709use 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
400impl Pat { 404impl 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
24use super::{ 24use 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)]
1066pub enum OpaqueTyId { 1095pub 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]
659fn 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() {
1889fn effects_smoke_test() { 1889fn 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]
89fn infer_async_block() {
90 check_types(
91 r#"
92//- /main.rs crate:main deps:core
93async 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
113enum Option<T> { None, Some(T) }
114
115//- /core.rs crate:core
116#[prelude_import] use future::*;
117mod future {
118 #[lang = "future_trait"]
119 trait Future {
120 type Output;
121 }
122}
123
124"#,
125 );
126}
127
128#[test]
89fn infer_try() { 129fn 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};
14use hir_expand::name::name;
14 15
15use super::ChalkContext; 16use super::ChalkContext;
16use crate::{ 17use 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};
23use mapping::{ 25use 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
518use std::future::*;
519fn foo() {
520 let a = async {};
521 a.<|>
522}
523
524//- /std/lib.rs
525pub 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#"
2653struct S;
2654fn foo() {
2655 let fo<|>o = async { S };
2656}
2657
2658#[prelude_import] use future::*;
2659mod 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
84pub use assists::{Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist}; 84pub use assists::{
85 utils::MergeBehaviour, Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist,
86};
85pub use base_db::{ 87pub 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
39impl fmt::Debug for ProjectWorkspace { 39impl 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};
7use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
8use serde::{de, Deserialize}; 8use serde::{de, Deserialize};
9 9
10use crate::{cfg_flag::CfgFlag, Sysroot}; 10use 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)]
14pub struct ProjectJson { 14pub 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 {
35impl ProjectJson { 35impl 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 @@
10use std::{ffi::OsString, path::PathBuf}; 10use std::{ffi::OsString, path::PathBuf};
11 11
12use flycheck::FlycheckConfig; 12use flycheck::FlycheckConfig;
13use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; 13use ide::{
14 AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig,
15 MergeBehaviour,
16};
14use lsp_types::ClientCapabilities; 17use lsp_types::ClientCapabilities;
15use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; 18use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest};
16use rustc_hash::FxHashSet; 19use 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")]
384enum MergeBehaviourDef {
385 None,
386 Full,
387 Last,
388}
389
373macro_rules! config_data { 390macro_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
394config_data! { 411config_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