diff options
-rw-r--r-- | Cargo.lock | 18 | ||||
-rw-r--r-- | crates/ra_assists/src/assist_ctx.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/assists/add_missing_impl_members.rs | 131 | ||||
-rw-r--r-- | crates/ra_assists/src/doc_tests/generated.rs | 22 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir_def/src/data.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir_def/src/path.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer.rs | 23 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 57 | ||||
-rw-r--r-- | crates/ra_project_model/src/cargo_workspace.rs | 2 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 4 | ||||
-rw-r--r-- | docs/user/assists.md | 22 | ||||
-rw-r--r-- | xtask/src/main.rs | 2 |
13 files changed, 272 insertions, 51 deletions
diff --git a/Cargo.lock b/Cargo.lock index 9f44599fd..792e30494 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -625,7 +625,7 @@ dependencies = [ | |||
625 | 625 | ||
626 | [[package]] | 626 | [[package]] |
627 | name = "lsp-types" | 627 | name = "lsp-types" |
628 | version = "0.67.0" | 628 | version = "0.67.1" |
629 | source = "registry+https://github.com/rust-lang/crates.io-index" | 629 | source = "registry+https://github.com/rust-lang/crates.io-index" |
630 | dependencies = [ | 630 | dependencies = [ |
631 | "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", | 631 | "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", |
@@ -1040,7 +1040,7 @@ dependencies = [ | |||
1040 | "ra_syntax 0.1.0", | 1040 | "ra_syntax 0.1.0", |
1041 | "ra_text_edit 0.1.0", | 1041 | "ra_text_edit 0.1.0", |
1042 | "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", | 1042 | "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", |
1043 | "rayon 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1043 | "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", |
1044 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1044 | "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", |
1045 | "superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", | 1045 | "superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", |
1046 | "test_utils 0.1.0", | 1046 | "test_utils 0.1.0", |
@@ -1056,7 +1056,7 @@ dependencies = [ | |||
1056 | "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", | 1056 | "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", |
1057 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", | 1057 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", |
1058 | "lsp-server 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | 1058 | "lsp-server 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", |
1059 | "lsp-types 0.67.0 (registry+https://github.com/rust-lang/crates.io-index)", | 1059 | "lsp-types 0.67.1 (registry+https://github.com/rust-lang/crates.io-index)", |
1060 | "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", | 1060 | "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", |
1061 | "ra_ide 0.1.0", | 1061 | "ra_ide 0.1.0", |
1062 | "ra_prof 0.1.0", | 1062 | "ra_prof 0.1.0", |
@@ -1320,17 +1320,17 @@ dependencies = [ | |||
1320 | 1320 | ||
1321 | [[package]] | 1321 | [[package]] |
1322 | name = "rayon" | 1322 | name = "rayon" |
1323 | version = "1.2.1" | 1323 | version = "1.3.0" |
1324 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1324 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1325 | dependencies = [ | 1325 | dependencies = [ |
1326 | "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", | 1326 | "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", |
1327 | "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", | 1327 | "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", |
1328 | "rayon-core 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1328 | "rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", |
1329 | ] | 1329 | ] |
1330 | 1330 | ||
1331 | [[package]] | 1331 | [[package]] |
1332 | name = "rayon-core" | 1332 | name = "rayon-core" |
1333 | version = "1.6.1" | 1333 | version = "1.7.0" |
1334 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1334 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1335 | dependencies = [ | 1335 | dependencies = [ |
1336 | "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", | 1336 | "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", |
@@ -1849,7 +1849,7 @@ dependencies = [ | |||
1849 | "checksum lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e57b3997725d2b60dbec1297f6c2e2957cc383db1cebd6be812163f969c7d586" | 1849 | "checksum lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e57b3997725d2b60dbec1297f6c2e2957cc383db1cebd6be812163f969c7d586" |
1850 | "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" | 1850 | "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" |
1851 | "checksum lsp-server 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ba36405bd742139ab79c246ca5adb7fde2fe1a0f495e2c8e2f607b607dedb12" | 1851 | "checksum lsp-server 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ba36405bd742139ab79c246ca5adb7fde2fe1a0f495e2c8e2f607b607dedb12" |
1852 | "checksum lsp-types 0.67.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7728b2c5a0e15fbb530bbd8b56520d19d56d89491a2a5e8b875f104e745b76" | 1852 | "checksum lsp-types 0.67.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aea9639ebf210bd5de66931cbdb2d4a8bcc1fa1e5b2dece7daa6b387ab42e803" |
1853 | "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" | 1853 | "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" |
1854 | "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" | 1854 | "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" |
1855 | "checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" | 1855 | "checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" |
@@ -1891,8 +1891,8 @@ dependencies = [ | |||
1891 | "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" | 1891 | "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" |
1892 | "checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" | 1892 | "checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" |
1893 | "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" | 1893 | "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" |
1894 | "checksum rayon 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43739f8831493b276363637423d3622d4bd6394ab6f0a9c4a552e208aeb7fddd" | 1894 | "checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098" |
1895 | "checksum rayon-core 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8bf17de6f23b05473c437eb958b9c850bfc8af0961fe17b4cc92d5a627b4791" | 1895 | "checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9" |
1896 | "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" | 1896 | "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" |
1897 | "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" | 1897 | "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" |
1898 | "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" | 1898 | "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" |
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index 993aebc47..28152f724 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -46,7 +46,7 @@ pub(crate) enum Assist { | |||
46 | /// | 46 | /// |
47 | /// Note, however, that we don't actually use such two-phase logic at the | 47 | /// Note, however, that we don't actually use such two-phase logic at the |
48 | /// moment, because the LSP API is pretty awkward in this place, and it's much | 48 | /// moment, because the LSP API is pretty awkward in this place, and it's much |
49 | /// easier to just compute the edit eagerly :-)#[derive(Debug, Clone)] | 49 | /// easier to just compute the edit eagerly :-) |
50 | #[derive(Debug)] | 50 | #[derive(Debug)] |
51 | pub(crate) struct AssistCtx<'a, DB> { | 51 | pub(crate) struct AssistCtx<'a, DB> { |
52 | pub(crate) db: &'a DB, | 52 | pub(crate) db: &'a DB, |
diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs index cef669cb5..bc49e71fe 100644 --- a/crates/ra_assists/src/assists/add_missing_impl_members.rs +++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | use std::collections::HashMap; | ||
2 | |||
1 | use hir::{db::HirDatabase, HasSource}; | 3 | use hir::{db::HirDatabase, HasSource}; |
2 | use ra_syntax::{ | 4 | use ra_syntax::{ |
3 | ast::{self, edit, make, AstNode, NameOwner}, | 5 | ast::{self, edit, make, AstNode, NameOwner}, |
@@ -17,26 +19,26 @@ enum AddMissingImplMembersMode { | |||
17 | // Adds scaffold for required impl members. | 19 | // Adds scaffold for required impl members. |
18 | // | 20 | // |
19 | // ``` | 21 | // ``` |
20 | // trait T { | 22 | // trait Trait<T> { |
21 | // Type X; | 23 | // Type X; |
22 | // fn foo(&self); | 24 | // fn foo(&self) -> T; |
23 | // fn bar(&self) {} | 25 | // fn bar(&self) {} |
24 | // } | 26 | // } |
25 | // | 27 | // |
26 | // impl T for () {<|> | 28 | // impl Trait<u32> for () {<|> |
27 | // | 29 | // |
28 | // } | 30 | // } |
29 | // ``` | 31 | // ``` |
30 | // -> | 32 | // -> |
31 | // ``` | 33 | // ``` |
32 | // trait T { | 34 | // trait Trait<T> { |
33 | // Type X; | 35 | // Type X; |
34 | // fn foo(&self); | 36 | // fn foo(&self) -> T; |
35 | // fn bar(&self) {} | 37 | // fn bar(&self) {} |
36 | // } | 38 | // } |
37 | // | 39 | // |
38 | // impl T for () { | 40 | // impl Trait<u32> for () { |
39 | // fn foo(&self) { unimplemented!() } | 41 | // fn foo(&self) -> u32 { unimplemented!() } |
40 | // | 42 | // |
41 | // } | 43 | // } |
42 | // ``` | 44 | // ``` |
@@ -54,13 +56,13 @@ pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Opti | |||
54 | // Adds scaffold for overriding default impl members. | 56 | // Adds scaffold for overriding default impl members. |
55 | // | 57 | // |
56 | // ``` | 58 | // ``` |
57 | // trait T { | 59 | // trait Trait { |
58 | // Type X; | 60 | // Type X; |
59 | // fn foo(&self); | 61 | // fn foo(&self); |
60 | // fn bar(&self) {} | 62 | // fn bar(&self) {} |
61 | // } | 63 | // } |
62 | // | 64 | // |
63 | // impl T for () { | 65 | // impl Trait for () { |
64 | // Type X = (); | 66 | // Type X = (); |
65 | // fn foo(&self) {}<|> | 67 | // fn foo(&self) {}<|> |
66 | // | 68 | // |
@@ -68,13 +70,13 @@ pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Opti | |||
68 | // ``` | 70 | // ``` |
69 | // -> | 71 | // -> |
70 | // ``` | 72 | // ``` |
71 | // trait T { | 73 | // trait Trait { |
72 | // Type X; | 74 | // Type X; |
73 | // fn foo(&self); | 75 | // fn foo(&self); |
74 | // fn bar(&self) {} | 76 | // fn bar(&self) {} |
75 | // } | 77 | // } |
76 | // | 78 | // |
77 | // impl T for () { | 79 | // impl Trait for () { |
78 | // Type X = (); | 80 | // Type X = (); |
79 | // fn foo(&self) {} | 81 | // fn foo(&self) {} |
80 | // fn bar(&self) {} | 82 | // fn bar(&self) {} |
@@ -99,7 +101,7 @@ fn add_missing_impl_members_inner( | |||
99 | let impl_node = ctx.find_node_at_offset::<ast::ImplBlock>()?; | 101 | let impl_node = ctx.find_node_at_offset::<ast::ImplBlock>()?; |
100 | let impl_item_list = impl_node.item_list()?; | 102 | let impl_item_list = impl_node.item_list()?; |
101 | 103 | ||
102 | let trait_def = { | 104 | let (trait_, trait_def) = { |
103 | let analyzer = ctx.source_analyzer(impl_node.syntax(), None); | 105 | let analyzer = ctx.source_analyzer(impl_node.syntax(), None); |
104 | 106 | ||
105 | resolve_target_trait_def(ctx.db, &analyzer, &impl_node)? | 107 | resolve_target_trait_def(ctx.db, &analyzer, &impl_node)? |
@@ -132,10 +134,25 @@ fn add_missing_impl_members_inner( | |||
132 | return None; | 134 | return None; |
133 | } | 135 | } |
134 | 136 | ||
137 | let file_id = ctx.frange.file_id; | ||
138 | let db = ctx.db; | ||
139 | |||
135 | ctx.add_assist(AssistId(assist_id), label, |edit| { | 140 | ctx.add_assist(AssistId(assist_id), label, |edit| { |
136 | let n_existing_items = impl_item_list.impl_items().count(); | 141 | let n_existing_items = impl_item_list.impl_items().count(); |
142 | let substs = get_syntactic_substs(impl_node).unwrap_or_default(); | ||
143 | let generic_def: hir::GenericDef = trait_.into(); | ||
144 | let substs_by_param: HashMap<_, _> = generic_def | ||
145 | .params(db) | ||
146 | .into_iter() | ||
147 | // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky | ||
148 | .skip(1) | ||
149 | .zip(substs.into_iter()) | ||
150 | .collect(); | ||
137 | let items = missing_items | 151 | let items = missing_items |
138 | .into_iter() | 152 | .into_iter() |
153 | .map(|it| { | ||
154 | substitute_type_params(db, hir::InFile::new(file_id.into(), it), &substs_by_param) | ||
155 | }) | ||
139 | .map(|it| match it { | 156 | .map(|it| match it { |
140 | ast::ImplItem::FnDef(def) => ast::ImplItem::FnDef(add_body(def)), | 157 | ast::ImplItem::FnDef(def) => ast::ImplItem::FnDef(add_body(def)), |
141 | _ => it, | 158 | _ => it, |
@@ -160,13 +177,63 @@ fn add_body(fn_def: ast::FnDef) -> ast::FnDef { | |||
160 | } | 177 | } |
161 | } | 178 | } |
162 | 179 | ||
180 | // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the | ||
181 | // trait ref, and then go from the types in the substs back to the syntax) | ||
182 | // FIXME: This should be a general utility (not even just for assists) | ||
183 | fn get_syntactic_substs(impl_block: ast::ImplBlock) -> Option<Vec<ast::TypeRef>> { | ||
184 | let target_trait = impl_block.target_trait()?; | ||
185 | let path_type = match target_trait { | ||
186 | ast::TypeRef::PathType(path) => path, | ||
187 | _ => return None, | ||
188 | }; | ||
189 | let type_arg_list = path_type.path()?.segment()?.type_arg_list()?; | ||
190 | let mut result = Vec::new(); | ||
191 | for type_arg in type_arg_list.type_args() { | ||
192 | let type_arg: ast::TypeArg = type_arg; | ||
193 | result.push(type_arg.type_ref()?); | ||
194 | } | ||
195 | Some(result) | ||
196 | } | ||
197 | |||
198 | // FIXME: This should be a general utility (not even just for assists) | ||
199 | fn substitute_type_params<N: AstNode>( | ||
200 | db: &impl HirDatabase, | ||
201 | node: hir::InFile<N>, | ||
202 | substs: &HashMap<hir::TypeParam, ast::TypeRef>, | ||
203 | ) -> N { | ||
204 | let type_param_replacements = node | ||
205 | .value | ||
206 | .syntax() | ||
207 | .descendants() | ||
208 | .filter_map(ast::TypeRef::cast) | ||
209 | .filter_map(|n| { | ||
210 | let path = match &n { | ||
211 | ast::TypeRef::PathType(path_type) => path_type.path()?, | ||
212 | _ => return None, | ||
213 | }; | ||
214 | let analyzer = hir::SourceAnalyzer::new(db, node.with_value(n.syntax()), None); | ||
215 | let resolution = analyzer.resolve_path(db, &path)?; | ||
216 | match resolution { | ||
217 | hir::PathResolution::TypeParam(tp) => Some((n, substs.get(&tp)?.clone())), | ||
218 | _ => None, | ||
219 | } | ||
220 | }) | ||
221 | .collect::<Vec<_>>(); | ||
222 | |||
223 | if type_param_replacements.is_empty() { | ||
224 | node.value | ||
225 | } else { | ||
226 | edit::replace_descendants(&node.value, type_param_replacements.into_iter()) | ||
227 | } | ||
228 | } | ||
229 | |||
163 | /// Given an `ast::ImplBlock`, resolves the target trait (the one being | 230 | /// Given an `ast::ImplBlock`, resolves the target trait (the one being |
164 | /// implemented) to a `ast::TraitDef`. | 231 | /// implemented) to a `ast::TraitDef`. |
165 | fn resolve_target_trait_def( | 232 | fn resolve_target_trait_def( |
166 | db: &impl HirDatabase, | 233 | db: &impl HirDatabase, |
167 | analyzer: &hir::SourceAnalyzer, | 234 | analyzer: &hir::SourceAnalyzer, |
168 | impl_block: &ast::ImplBlock, | 235 | impl_block: &ast::ImplBlock, |
169 | ) -> Option<ast::TraitDef> { | 236 | ) -> Option<(hir::Trait, ast::TraitDef)> { |
170 | let ast_path = impl_block | 237 | let ast_path = impl_block |
171 | .target_trait() | 238 | .target_trait() |
172 | .map(|it| it.syntax().clone()) | 239 | .map(|it| it.syntax().clone()) |
@@ -174,7 +241,9 @@ fn resolve_target_trait_def( | |||
174 | .path()?; | 241 | .path()?; |
175 | 242 | ||
176 | match analyzer.resolve_path(db, &ast_path) { | 243 | match analyzer.resolve_path(db, &ast_path) { |
177 | Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => Some(def.source(db).value), | 244 | Some(hir::PathResolution::Def(hir::ModuleDef::Trait(def))) => { |
245 | Some((def, def.source(db).value)) | ||
246 | } | ||
178 | _ => None, | 247 | _ => None, |
179 | } | 248 | } |
180 | } | 249 | } |
@@ -281,6 +350,40 @@ impl Foo for S { | |||
281 | } | 350 | } |
282 | 351 | ||
283 | #[test] | 352 | #[test] |
353 | fn fill_in_type_params_1() { | ||
354 | check_assist( | ||
355 | add_missing_impl_members, | ||
356 | " | ||
357 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | ||
358 | struct S; | ||
359 | impl Foo<u32> for S { <|> }", | ||
360 | " | ||
361 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | ||
362 | struct S; | ||
363 | impl Foo<u32> for S { | ||
364 | <|>fn foo(&self, t: u32) -> &u32 { unimplemented!() } | ||
365 | }", | ||
366 | ); | ||
367 | } | ||
368 | |||
369 | #[test] | ||
370 | fn fill_in_type_params_2() { | ||
371 | check_assist( | ||
372 | add_missing_impl_members, | ||
373 | " | ||
374 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | ||
375 | struct S; | ||
376 | impl<U> Foo<U> for S { <|> }", | ||
377 | " | ||
378 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | ||
379 | struct S; | ||
380 | impl<U> Foo<U> for S { | ||
381 | <|>fn foo(&self, t: U) -> &U { unimplemented!() } | ||
382 | }", | ||
383 | ); | ||
384 | } | ||
385 | |||
386 | #[test] | ||
284 | fn test_cursor_after_empty_impl_block() { | 387 | fn test_cursor_after_empty_impl_block() { |
285 | check_assist( | 388 | check_assist( |
286 | add_missing_impl_members, | 389 | add_missing_impl_members, |
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index 4586eeb59..7d84dc8fb 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs | |||
@@ -101,26 +101,26 @@ fn doctest_add_impl_default_members() { | |||
101 | check( | 101 | check( |
102 | "add_impl_default_members", | 102 | "add_impl_default_members", |
103 | r#####" | 103 | r#####" |
104 | trait T { | 104 | trait Trait { |
105 | Type X; | 105 | Type X; |
106 | fn foo(&self); | 106 | fn foo(&self); |
107 | fn bar(&self) {} | 107 | fn bar(&self) {} |
108 | } | 108 | } |
109 | 109 | ||
110 | impl T for () { | 110 | impl Trait for () { |
111 | Type X = (); | 111 | Type X = (); |
112 | fn foo(&self) {}<|> | 112 | fn foo(&self) {}<|> |
113 | 113 | ||
114 | } | 114 | } |
115 | "#####, | 115 | "#####, |
116 | r#####" | 116 | r#####" |
117 | trait T { | 117 | trait Trait { |
118 | Type X; | 118 | Type X; |
119 | fn foo(&self); | 119 | fn foo(&self); |
120 | fn bar(&self) {} | 120 | fn bar(&self) {} |
121 | } | 121 | } |
122 | 122 | ||
123 | impl T for () { | 123 | impl Trait for () { |
124 | Type X = (); | 124 | Type X = (); |
125 | fn foo(&self) {} | 125 | fn foo(&self) {} |
126 | fn bar(&self) {} | 126 | fn bar(&self) {} |
@@ -135,25 +135,25 @@ fn doctest_add_impl_missing_members() { | |||
135 | check( | 135 | check( |
136 | "add_impl_missing_members", | 136 | "add_impl_missing_members", |
137 | r#####" | 137 | r#####" |
138 | trait T { | 138 | trait Trait<T> { |
139 | Type X; | 139 | Type X; |
140 | fn foo(&self); | 140 | fn foo(&self) -> T; |
141 | fn bar(&self) {} | 141 | fn bar(&self) {} |
142 | } | 142 | } |
143 | 143 | ||
144 | impl T for () {<|> | 144 | impl Trait<u32> for () {<|> |
145 | 145 | ||
146 | } | 146 | } |
147 | "#####, | 147 | "#####, |
148 | r#####" | 148 | r#####" |
149 | trait T { | 149 | trait Trait<T> { |
150 | Type X; | 150 | Type X; |
151 | fn foo(&self); | 151 | fn foo(&self) -> T; |
152 | fn bar(&self) {} | 152 | fn bar(&self) {} |
153 | } | 153 | } |
154 | 154 | ||
155 | impl T for () { | 155 | impl Trait<u32> for () { |
156 | fn foo(&self) { unimplemented!() } | 156 | fn foo(&self) -> u32 { unimplemented!() } |
157 | 157 | ||
158 | } | 158 | } |
159 | "#####, | 159 | "#####, |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index bcfc0d03e..76d8f85f1 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -644,6 +644,17 @@ impl_froms!( | |||
644 | Const | 644 | Const |
645 | ); | 645 | ); |
646 | 646 | ||
647 | impl GenericDef { | ||
648 | pub fn params(self, db: &impl HirDatabase) -> Vec<TypeParam> { | ||
649 | let generics: Arc<hir_def::generics::GenericParams> = db.generic_params(self.into()); | ||
650 | generics | ||
651 | .types | ||
652 | .iter() | ||
653 | .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } }) | ||
654 | .collect() | ||
655 | } | ||
656 | } | ||
657 | |||
647 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 658 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
648 | pub struct Local { | 659 | pub struct Local { |
649 | pub(crate) parent: DefWithBody, | 660 | pub(crate) parent: DefWithBody, |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 1aa9a9b7d..c900a6a18 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -10,8 +10,9 @@ use ra_syntax::ast::{self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAs | |||
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | db::DefDatabase, | 12 | db::DefDatabase, |
13 | path::{path, GenericArgs, Path}, | ||
13 | src::HasSource, | 14 | src::HasSource, |
14 | type_ref::{Mutability, TypeRef}, | 15 | type_ref::{Mutability, TypeBound, TypeRef}, |
15 | AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, | 16 | AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule, |
16 | ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, | 17 | ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, |
17 | }; | 18 | }; |
@@ -62,11 +63,29 @@ impl FunctionData { | |||
62 | TypeRef::unit() | 63 | TypeRef::unit() |
63 | }; | 64 | }; |
64 | 65 | ||
66 | let ret_type = if src.value.is_async() { | ||
67 | let future_impl = desugar_future_path(ret_type); | ||
68 | let ty_bound = TypeBound::Path(future_impl); | ||
69 | TypeRef::ImplTrait(vec![ty_bound]) | ||
70 | } else { | ||
71 | ret_type | ||
72 | }; | ||
73 | |||
65 | let sig = FunctionData { name, params, ret_type, has_self_param }; | 74 | let sig = FunctionData { name, params, ret_type, has_self_param }; |
66 | Arc::new(sig) | 75 | Arc::new(sig) |
67 | } | 76 | } |
68 | } | 77 | } |
69 | 78 | ||
79 | fn desugar_future_path(orig: TypeRef) -> Path { | ||
80 | let path = path![std::future::Future]; | ||
81 | let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); | ||
82 | let mut last = GenericArgs::empty(); | ||
83 | last.bindings.push((name![Output], orig)); | ||
84 | generic_args.push(Some(Arc::new(last))); | ||
85 | |||
86 | Path::from_known_path(path, generic_args) | ||
87 | } | ||
88 | |||
70 | #[derive(Debug, Clone, PartialEq, Eq)] | 89 | #[derive(Debug, Clone, PartialEq, Eq)] |
71 | pub struct TypeAliasData { | 90 | pub struct TypeAliasData { |
72 | pub name: Name, | 91 | pub name: Name, |
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 8e1294201..107d2d799 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -130,6 +130,14 @@ impl Path { | |||
130 | Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] } | 130 | Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] } |
131 | } | 131 | } |
132 | 132 | ||
133 | /// Converts a known mod path to `Path`. | ||
134 | pub(crate) fn from_known_path( | ||
135 | path: ModPath, | ||
136 | generic_args: Vec<Option<Arc<GenericArgs>>>, | ||
137 | ) -> Path { | ||
138 | Path { type_anchor: None, mod_path: path, generic_args } | ||
139 | } | ||
140 | |||
133 | pub fn kind(&self) -> &PathKind { | 141 | pub fn kind(&self) -> &PathKind { |
134 | &self.mod_path.kind | 142 | &self.mod_path.kind |
135 | } | 143 | } |
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index e97b81473..32c0d07a5 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -37,8 +37,8 @@ use test_utils::tested_by; | |||
37 | use super::{ | 37 | use super::{ |
38 | primitive::{FloatTy, IntTy}, | 38 | primitive::{FloatTy, IntTy}, |
39 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, | 39 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, |
40 | ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, | 40 | ApplicationTy, GenericPredicate, InEnvironment, ProjectionTy, Substs, TraitEnvironment, |
41 | TypeWalk, Uncertain, | 41 | TraitRef, Ty, TypeCtor, TypeWalk, Uncertain, |
42 | }; | 42 | }; |
43 | use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; | 43 | use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; |
44 | 44 | ||
@@ -379,6 +379,25 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
379 | ) -> Ty { | 379 | ) -> Ty { |
380 | match assoc_ty { | 380 | match assoc_ty { |
381 | Some(res_assoc_ty) => { | 381 | Some(res_assoc_ty) => { |
382 | // FIXME: | ||
383 | // Check if inner_ty is is `impl Trait` and contained input TypeAlias id | ||
384 | // this is a workaround while Chalk assoc type projection doesn't always work yet, | ||
385 | // but once that is fixed I don't think we should keep this | ||
386 | // (we'll probably change how associated types are resolved anyway) | ||
387 | if let Ty::Opaque(ref predicates) = inner_ty { | ||
388 | for p in predicates.iter() { | ||
389 | if let GenericPredicate::Projection(projection) = p { | ||
390 | if projection.projection_ty.associated_ty == res_assoc_ty { | ||
391 | if let ty_app!(_, params) = &projection.ty { | ||
392 | if params.len() == 0 { | ||
393 | return projection.ty.clone(); | ||
394 | } | ||
395 | } | ||
396 | } | ||
397 | } | ||
398 | } | ||
399 | } | ||
400 | |||
382 | let ty = self.table.new_type_var(); | 401 | let ty = self.table.new_type_var(); |
383 | let builder = Substs::build_for_def(self.db, res_assoc_ty) | 402 | let builder = Substs::build_for_def(self.db, res_assoc_ty) |
384 | .push(inner_ty) | 403 | .push(inner_ty) |
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index ae316922b..0bc72644a 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -38,6 +38,63 @@ mod future { | |||
38 | } | 38 | } |
39 | 39 | ||
40 | #[test] | 40 | #[test] |
41 | fn infer_async() { | ||
42 | let (db, pos) = TestDB::with_position( | ||
43 | r#" | ||
44 | //- /main.rs crate:main deps:std | ||
45 | |||
46 | async fn foo() -> u64 { | ||
47 | 128 | ||
48 | } | ||
49 | |||
50 | fn test() { | ||
51 | let r = foo(); | ||
52 | let v = r.await; | ||
53 | v<|>; | ||
54 | } | ||
55 | |||
56 | //- /std.rs crate:std | ||
57 | #[prelude_import] use future::*; | ||
58 | mod future { | ||
59 | trait Future { | ||
60 | type Output; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | "#, | ||
65 | ); | ||
66 | assert_eq!("u64", type_at_pos(&db, pos)); | ||
67 | } | ||
68 | |||
69 | #[test] | ||
70 | fn infer_desugar_async() { | ||
71 | let (db, pos) = TestDB::with_position( | ||
72 | r#" | ||
73 | //- /main.rs crate:main deps:std | ||
74 | |||
75 | async fn foo() -> u64 { | ||
76 | 128 | ||
77 | } | ||
78 | |||
79 | fn test() { | ||
80 | let r = foo(); | ||
81 | r<|>; | ||
82 | } | ||
83 | |||
84 | //- /std.rs crate:std | ||
85 | #[prelude_import] use future::*; | ||
86 | mod future { | ||
87 | trait Future { | ||
88 | type Output; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | "#, | ||
93 | ); | ||
94 | assert_eq!("impl Future<Output = u64>", type_at_pos(&db, pos)); | ||
95 | } | ||
96 | |||
97 | #[test] | ||
41 | fn infer_try() { | 98 | fn infer_try() { |
42 | let (db, pos) = TestDB::with_position( | 99 | let (db, pos) = TestDB::with_position( |
43 | r#" | 100 | r#" |
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index c862d3912..1b3c246c7 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs | |||
@@ -165,7 +165,7 @@ impl CargoWorkspace { | |||
165 | // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` | 165 | // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` |
166 | // https://github.com/oli-obk/cargo_metadata/issues/79 | 166 | // https://github.com/oli-obk/cargo_metadata/issues/79 |
167 | meta.features(CargoOpt::NoDefaultFeatures); | 167 | meta.features(CargoOpt::NoDefaultFeatures); |
168 | } else { | 168 | } else if cargo_features.features.len() > 0 { |
169 | meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone())); | 169 | meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone())); |
170 | } | 170 | } |
171 | if let Some(parent) = cargo_toml.parent() { | 171 | if let Some(parent) = cargo_toml.parent() { |
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index a8f625176..baaef3023 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -221,6 +221,10 @@ impl ast::FnDef { | |||
221 | .and_then(|it| it.into_token()) | 221 | .and_then(|it| it.into_token()) |
222 | .filter(|it| it.kind() == T![;]) | 222 | .filter(|it| it.kind() == T![;]) |
223 | } | 223 | } |
224 | |||
225 | pub fn is_async(&self) -> bool { | ||
226 | self.syntax().children_with_tokens().any(|it| it.kind() == T![async]) | ||
227 | } | ||
224 | } | 228 | } |
225 | 229 | ||
226 | impl ast::LetStmt { | 230 | impl ast::LetStmt { |
diff --git a/docs/user/assists.md b/docs/user/assists.md index 334ba450f..ecf206f71 100644 --- a/docs/user/assists.md +++ b/docs/user/assists.md | |||
@@ -98,26 +98,26 @@ Adds scaffold for overriding default impl members. | |||
98 | 98 | ||
99 | ```rust | 99 | ```rust |
100 | // BEFORE | 100 | // BEFORE |
101 | trait T { | 101 | trait Trait { |
102 | Type X; | 102 | Type X; |
103 | fn foo(&self); | 103 | fn foo(&self); |
104 | fn bar(&self) {} | 104 | fn bar(&self) {} |
105 | } | 105 | } |
106 | 106 | ||
107 | impl T for () { | 107 | impl Trait for () { |
108 | Type X = (); | 108 | Type X = (); |
109 | fn foo(&self) {}┃ | 109 | fn foo(&self) {}┃ |
110 | 110 | ||
111 | } | 111 | } |
112 | 112 | ||
113 | // AFTER | 113 | // AFTER |
114 | trait T { | 114 | trait Trait { |
115 | Type X; | 115 | Type X; |
116 | fn foo(&self); | 116 | fn foo(&self); |
117 | fn bar(&self) {} | 117 | fn bar(&self) {} |
118 | } | 118 | } |
119 | 119 | ||
120 | impl T for () { | 120 | impl Trait for () { |
121 | Type X = (); | 121 | Type X = (); |
122 | fn foo(&self) {} | 122 | fn foo(&self) {} |
123 | fn bar(&self) {} | 123 | fn bar(&self) {} |
@@ -131,25 +131,25 @@ Adds scaffold for required impl members. | |||
131 | 131 | ||
132 | ```rust | 132 | ```rust |
133 | // BEFORE | 133 | // BEFORE |
134 | trait T { | 134 | trait Trait<T> { |
135 | Type X; | 135 | Type X; |
136 | fn foo(&self); | 136 | fn foo(&self) -> T; |
137 | fn bar(&self) {} | 137 | fn bar(&self) {} |
138 | } | 138 | } |
139 | 139 | ||
140 | impl T for () {┃ | 140 | impl Trait<u32> for () {┃ |
141 | 141 | ||
142 | } | 142 | } |
143 | 143 | ||
144 | // AFTER | 144 | // AFTER |
145 | trait T { | 145 | trait Trait<T> { |
146 | Type X; | 146 | Type X; |
147 | fn foo(&self); | 147 | fn foo(&self) -> T; |
148 | fn bar(&self) {} | 148 | fn bar(&self) {} |
149 | } | 149 | } |
150 | 150 | ||
151 | impl T for () { | 151 | impl Trait<u32> for () { |
152 | fn foo(&self) { unimplemented!() } | 152 | fn foo(&self) -> u32 { unimplemented!() } |
153 | 153 | ||
154 | } | 154 | } |
155 | ``` | 155 | ``` |
diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 4201c6a6a..9cefad925 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs | |||
@@ -226,7 +226,7 @@ fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> { | |||
226 | if !str::from_utf8(&output.stdout)?.contains("ra-lsp") { | 226 | if !str::from_utf8(&output.stdout)?.contains("ra-lsp") { |
227 | anyhow::bail!( | 227 | anyhow::bail!( |
228 | "Could not install the Visual Studio Code extension. \ | 228 | "Could not install the Visual Studio Code extension. \ |
229 | Please make sure you have at least NodeJS 10.x installed and try again." | 229 | Please make sure you have at least NodeJS 10.x together with the latest version of VS Code installed and try again." |
230 | ); | 230 | ); |
231 | } | 231 | } |
232 | 232 | ||