aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock20
-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
-rw-r--r--editors/code/package-lock.json6
-rw-r--r--editors/code/package.json17
40 files changed, 713 insertions, 240 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9ebb15a96..f5b1a4747 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -720,9 +720,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
720 720
721[[package]] 721[[package]]
722name = "libc" 722name = "libc"
723version = "0.2.76" 723version = "0.2.77"
724source = "registry+https://github.com/rust-lang/crates.io-index" 724source = "registry+https://github.com/rust-lang/crates.io-index"
725checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" 725checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
726 726
727[[package]] 727[[package]]
728name = "libloading" 728name = "libloading"
@@ -1071,9 +1071,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
1071 1071
1072[[package]] 1072[[package]]
1073name = "proc-macro2" 1073name = "proc-macro2"
1074version = "1.0.20" 1074version = "1.0.21"
1075source = "registry+https://github.com/rust-lang/crates.io-index" 1075source = "registry+https://github.com/rust-lang/crates.io-index"
1076checksum = "175c513d55719db99da20232b06cda8bab6b83ec2d04e3283edf0213c37c1a29" 1076checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c"
1077dependencies = [ 1077dependencies = [
1078 "unicode-xid", 1078 "unicode-xid",
1079] 1079]
@@ -1401,18 +1401,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
1401 1401
1402[[package]] 1402[[package]]
1403name = "serde" 1403name = "serde"
1404version = "1.0.115" 1404version = "1.0.116"
1405source = "registry+https://github.com/rust-lang/crates.io-index" 1405source = "registry+https://github.com/rust-lang/crates.io-index"
1406checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" 1406checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5"
1407dependencies = [ 1407dependencies = [
1408 "serde_derive", 1408 "serde_derive",
1409] 1409]
1410 1410
1411[[package]] 1411[[package]]
1412name = "serde_derive" 1412name = "serde_derive"
1413version = "1.0.115" 1413version = "1.0.116"
1414source = "registry+https://github.com/rust-lang/crates.io-index" 1414source = "registry+https://github.com/rust-lang/crates.io-index"
1415checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" 1415checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8"
1416dependencies = [ 1416dependencies = [
1417 "proc-macro2", 1417 "proc-macro2",
1418 "quote", 1418 "quote",
@@ -1639,9 +1639,9 @@ dependencies = [
1639 1639
1640[[package]] 1640[[package]]
1641name = "tracing-core" 1641name = "tracing-core"
1642version = "0.1.15" 1642version = "0.1.16"
1643source = "registry+https://github.com/rust-lang/crates.io-index" 1643source = "registry+https://github.com/rust-lang/crates.io-index"
1644checksum = "4f0e00789804e99b20f12bc7003ca416309d28a6f495d6af58d1e2c2842461b5" 1644checksum = "5bcf46c1f1f06aeea2d6b81f3c863d0930a596c86ad1920d4e5bad6dd1d7119a"
1645dependencies = [ 1645dependencies = [
1646 "lazy_static", 1646 "lazy_static",
1647] 1647]
diff --git a/crates/assists/src/assist_config.rs b/crates/assists/src/assist_config.rs
index cda2abfb9..adf02edab 100644
--- a/crates/assists/src/assist_config.rs
+++ b/crates/assists/src/assist_config.rs
@@ -4,12 +4,13 @@
4//! module, and we use to statically check that we only produce snippet 4//! module, and we use to statically check that we only produce snippet
5//! assists if we are allowed to. 5//! assists if we are allowed to.
6 6
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
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 63ba4bdf1..33d60d4dd 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -1761,9 +1761,9 @@
1761 "dev": true 1761 "dev": true
1762 }, 1762 },
1763 "node-fetch": { 1763 "node-fetch": {
1764 "version": "2.6.0", 1764 "version": "2.6.1",
1765 "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", 1765 "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
1766 "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" 1766 "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
1767 }, 1767 },
1768 "normalize-path": { 1768 "normalize-path": {
1769 "version": "3.0.0", 1769 "version": "3.0.0",
diff --git a/editors/code/package.json b/editors/code/package.json
index 6fc4464df..86a70a89a 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -35,7 +35,7 @@
35 "test": "node ./out/tests/runTests.js" 35 "test": "node ./out/tests/runTests.js"
36 }, 36 },
37 "dependencies": { 37 "dependencies": {
38 "node-fetch": "^2.6.0", 38 "node-fetch": "^2.6.1",
39 "vscode-languageclient": "7.0.0-next.9" 39 "vscode-languageclient": "7.0.0-next.9"
40 }, 40 },
41 "devDependencies": { 41 "devDependencies": {
@@ -626,6 +626,21 @@
626 }, 626 },
627 "description": "List of warnings that should be displayed with hint severity.\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel.", 627 "description": "List of warnings that should be displayed with hint severity.\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel.",
628 "default": [] 628 "default": []
629 },
630 "rust-analyzer.assist.importMergeBehaviour": {
631 "type": "string",
632 "enum": [
633 "none",
634 "full",
635 "last"
636 ],
637 "enumDescriptions": [
638 "No merging",
639 "Merge all layers of the import trees",
640 "Only merge the last layer of the import trees"
641 ],
642 "default": "full",
643 "description": "The strategy to use when inserting new imports or merging imports."
629 } 644 }
630 } 645 }
631 }, 646 },