diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-05-04 11:49:24 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-05-04 11:49:24 +0100 |
commit | 57f285d0ebd5291e74cc52cd991ac7bdc3ec8630 (patch) | |
tree | 35752b33aa57155d43a39fa338603e29b70e8a49 | |
parent | b1a5dc8c8b8588ac61d1952ba3b4cf3b68d2a477 (diff) | |
parent | 5899c8eaa9f8868c5c3858e21f5b9b3bbde1de67 (diff) |
Merge #4283
4283: Support macro for trait items r=matklad a=edwin0cheng
Fixed #4039
r? @flodiebold
Co-authored-by: Edwin Cheng <[email protected]>
Co-authored-by: Edwin Cheng <[email protected]>
-rw-r--r-- | crates/ra_hir_def/src/data.rs | 146 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 38 |
2 files changed, 80 insertions, 104 deletions
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 7a2067e49..d4cba4d05 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -150,51 +150,31 @@ pub struct TraitData { | |||
150 | 150 | ||
151 | impl TraitData { | 151 | impl TraitData { |
152 | pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { | 152 | pub(crate) fn trait_data_query(db: &dyn DefDatabase, tr: TraitId) -> Arc<TraitData> { |
153 | let src = tr.lookup(db).source(db); | 153 | let tr_loc = tr.lookup(db); |
154 | let src = tr_loc.source(db); | ||
154 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); | 155 | let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); |
155 | let auto = src.value.auto_token().is_some(); | 156 | let auto = src.value.auto_token().is_some(); |
156 | let ast_id_map = db.ast_id_map(src.file_id); | 157 | let module_id = tr_loc.container.module(db); |
157 | 158 | ||
158 | let container = AssocContainerId::TraitId(tr); | 159 | let container = AssocContainerId::TraitId(tr); |
159 | let items = if let Some(item_list) = src.value.item_list() { | 160 | let mut items = Vec::new(); |
160 | item_list | 161 | |
161 | .impl_items() | 162 | if let Some(item_list) = src.value.item_list() { |
162 | .map(|item_node| match item_node { | 163 | let mut expander = Expander::new(db, tr_loc.ast_id.file_id, module_id); |
163 | ast::ImplItem::FnDef(it) => { | 164 | items.extend(collect_items( |
164 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | 165 | db, |
165 | let def = FunctionLoc { | 166 | &mut expander, |
166 | container, | 167 | item_list.impl_items(), |
167 | ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)), | 168 | src.file_id, |
168 | } | 169 | container, |
169 | .intern(db) | 170 | )); |
170 | .into(); | 171 | items.extend(collect_items_in_macros( |
171 | (name, def) | 172 | db, |
172 | } | 173 | &mut expander, |
173 | ast::ImplItem::ConstDef(it) => { | 174 | &src.with_value(item_list), |
174 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | 175 | container, |
175 | let def = ConstLoc { | 176 | )); |
176 | container, | 177 | } |
177 | ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)), | ||
178 | } | ||
179 | .intern(db) | ||
180 | .into(); | ||
181 | (name, def) | ||
182 | } | ||
183 | ast::ImplItem::TypeAliasDef(it) => { | ||
184 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | ||
185 | let def = TypeAliasLoc { | ||
186 | container, | ||
187 | ast_id: AstId::new(src.file_id, ast_id_map.ast_id(&it)), | ||
188 | } | ||
189 | .intern(db) | ||
190 | .into(); | ||
191 | (name, def) | ||
192 | } | ||
193 | }) | ||
194 | .collect() | ||
195 | } else { | ||
196 | Vec::new() | ||
197 | }; | ||
198 | Arc::new(TraitData { name, items, auto }) | 178 | Arc::new(TraitData { name, items, auto }) |
199 | } | 179 | } |
200 | 180 | ||
@@ -232,24 +212,22 @@ impl ImplData { | |||
232 | let target_type = TypeRef::from_ast_opt(&lower_ctx, src.value.target_type()); | 212 | let target_type = TypeRef::from_ast_opt(&lower_ctx, src.value.target_type()); |
233 | let is_negative = src.value.excl_token().is_some(); | 213 | let is_negative = src.value.excl_token().is_some(); |
234 | let module_id = impl_loc.container.module(db); | 214 | let module_id = impl_loc.container.module(db); |
215 | let container = AssocContainerId::ImplId(id); | ||
235 | 216 | ||
236 | let mut items = Vec::new(); | 217 | let mut items: Vec<AssocItemId> = Vec::new(); |
237 | 218 | ||
238 | if let Some(item_list) = src.value.item_list() { | 219 | if let Some(item_list) = src.value.item_list() { |
239 | let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id); | 220 | let mut expander = Expander::new(db, impl_loc.ast_id.file_id, module_id); |
240 | items.extend(collect_impl_items( | 221 | items.extend( |
241 | db, | 222 | collect_items(db, &mut expander, item_list.impl_items(), src.file_id, container) |
242 | &mut expander, | 223 | .into_iter() |
243 | item_list.impl_items(), | 224 | .map(|(_, item)| item), |
244 | src.file_id, | 225 | ); |
245 | id, | 226 | items.extend( |
246 | )); | 227 | collect_items_in_macros(db, &mut expander, &src.with_value(item_list), container) |
247 | items.extend(collect_impl_items_in_macros( | 228 | .into_iter() |
248 | db, | 229 | .map(|(_, item)| item), |
249 | &mut expander, | 230 | ); |
250 | &src.with_value(item_list), | ||
251 | id, | ||
252 | )); | ||
253 | } | 231 | } |
254 | 232 | ||
255 | let res = ImplData { target_trait, target_type, items, is_negative }; | 233 | let res = ImplData { target_trait, target_type, items, is_negative }; |
@@ -292,49 +270,50 @@ impl ConstData { | |||
292 | } | 270 | } |
293 | } | 271 | } |
294 | 272 | ||
295 | fn collect_impl_items_in_macros( | 273 | fn collect_items_in_macros( |
296 | db: &dyn DefDatabase, | 274 | db: &dyn DefDatabase, |
297 | expander: &mut Expander, | 275 | expander: &mut Expander, |
298 | impl_def: &InFile<ast::ItemList>, | 276 | impl_def: &InFile<ast::ItemList>, |
299 | id: ImplId, | 277 | container: AssocContainerId, |
300 | ) -> Vec<AssocItemId> { | 278 | ) -> Vec<(Name, AssocItemId)> { |
301 | let mut res = Vec::new(); | 279 | let mut res = Vec::new(); |
302 | 280 | ||
303 | // We set a limit to protect against infinite recursion | 281 | // We set a limit to protect against infinite recursion |
304 | let limit = 100; | 282 | let limit = 100; |
305 | 283 | ||
306 | for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) { | 284 | for m in impl_def.value.syntax().children().filter_map(ast::MacroCall::cast) { |
307 | res.extend(collect_impl_items_in_macro(db, expander, m, id, limit)) | 285 | res.extend(collect_items_in_macro(db, expander, m, container, limit)) |
308 | } | 286 | } |
309 | 287 | ||
310 | res | 288 | res |
311 | } | 289 | } |
312 | 290 | ||
313 | fn collect_impl_items_in_macro( | 291 | fn collect_items_in_macro( |
314 | db: &dyn DefDatabase, | 292 | db: &dyn DefDatabase, |
315 | expander: &mut Expander, | 293 | expander: &mut Expander, |
316 | m: ast::MacroCall, | 294 | m: ast::MacroCall, |
317 | id: ImplId, | 295 | container: AssocContainerId, |
318 | limit: usize, | 296 | limit: usize, |
319 | ) -> Vec<AssocItemId> { | 297 | ) -> Vec<(Name, AssocItemId)> { |
320 | if limit == 0 { | 298 | if limit == 0 { |
321 | return Vec::new(); | 299 | return Vec::new(); |
322 | } | 300 | } |
323 | 301 | ||
324 | if let Some((mark, items)) = expander.enter_expand(db, None, m) { | 302 | if let Some((mark, items)) = expander.enter_expand(db, None, m) { |
325 | let items: InFile<ast::MacroItems> = expander.to_source(items); | 303 | let items: InFile<ast::MacroItems> = expander.to_source(items); |
326 | let mut res = collect_impl_items( | 304 | let mut res = collect_items( |
327 | db, | 305 | db, |
328 | expander, | 306 | expander, |
329 | items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())), | 307 | items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())), |
330 | items.file_id, | 308 | items.file_id, |
331 | id, | 309 | container, |
332 | ); | 310 | ); |
311 | |||
333 | // Recursive collect macros | 312 | // Recursive collect macros |
334 | // Note that ast::ModuleItem do not include ast::MacroCall | 313 | // Note that ast::ModuleItem do not include ast::MacroCall |
335 | // We cannot use ModuleItemOwner::items here | 314 | // We cannot use ModuleItemOwner::items here |
336 | for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) { | 315 | for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) { |
337 | res.extend(collect_impl_items_in_macro(db, expander, it, id, limit - 1)) | 316 | res.extend(collect_items_in_macro(db, expander, it, container, limit - 1)) |
338 | } | 317 | } |
339 | expander.exit(db, mark); | 318 | expander.exit(db, mark); |
340 | res | 319 | res |
@@ -343,44 +322,39 @@ fn collect_impl_items_in_macro( | |||
343 | } | 322 | } |
344 | } | 323 | } |
345 | 324 | ||
346 | fn collect_impl_items( | 325 | fn collect_items( |
347 | db: &dyn DefDatabase, | 326 | db: &dyn DefDatabase, |
348 | expander: &mut Expander, | 327 | expander: &mut Expander, |
349 | impl_items: impl Iterator<Item = ImplItem>, | 328 | impl_items: impl Iterator<Item = ImplItem>, |
350 | file_id: crate::HirFileId, | 329 | file_id: crate::HirFileId, |
351 | id: ImplId, | 330 | container: AssocContainerId, |
352 | ) -> Vec<AssocItemId> { | 331 | ) -> Vec<(Name, AssocItemId)> { |
353 | let items = db.ast_id_map(file_id); | 332 | let items = db.ast_id_map(file_id); |
354 | 333 | ||
355 | impl_items | 334 | impl_items |
356 | .filter_map(|item_node| match item_node { | 335 | .filter_map(|item_node| match item_node { |
357 | ast::ImplItem::FnDef(it) => { | 336 | ast::ImplItem::FnDef(it) => { |
337 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); | ||
358 | let attrs = expander.parse_attrs(&it); | 338 | let attrs = expander.parse_attrs(&it); |
359 | if !expander.is_cfg_enabled(&attrs) { | 339 | if !expander.is_cfg_enabled(&attrs) { |
360 | return None; | 340 | return None; |
361 | } | 341 | } |
362 | let def = FunctionLoc { | 342 | let def = FunctionLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } |
363 | container: AssocContainerId::ImplId(id), | 343 | .intern(db); |
364 | ast_id: AstId::new(file_id, items.ast_id(&it)), | 344 | Some((name, def.into())) |
365 | } | ||
366 | .intern(db); | ||
367 | Some(def.into()) | ||
368 | } | 345 | } |
369 | ast::ImplItem::ConstDef(it) => { | 346 | ast::ImplItem::ConstDef(it) => { |
370 | let def = ConstLoc { | 347 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); |
371 | container: AssocContainerId::ImplId(id), | 348 | let def = ConstLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } |
372 | ast_id: AstId::new(file_id, items.ast_id(&it)), | 349 | .intern(db); |
373 | } | 350 | Some((name, def.into())) |
374 | .intern(db); | ||
375 | Some(def.into()) | ||
376 | } | 351 | } |
377 | ast::ImplItem::TypeAliasDef(it) => { | 352 | ast::ImplItem::TypeAliasDef(it) => { |
378 | let def = TypeAliasLoc { | 353 | let name = it.name().map_or_else(Name::missing, |it| it.as_name()); |
379 | container: AssocContainerId::ImplId(id), | 354 | let def = |
380 | ast_id: AstId::new(file_id, items.ast_id(&it)), | 355 | TypeAliasLoc { container, ast_id: AstId::new(file_id, items.ast_id(&it)) } |
381 | } | 356 | .intern(db); |
382 | .intern(db); | 357 | Some((name, def.into())) |
383 | Some(def.into()) | ||
384 | } | 358 | } |
385 | }) | 359 | }) |
386 | .collect() | 360 | .collect() |
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index e555c879a..9d32cbc7a 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -2055,7 +2055,7 @@ fn test<I: Iterator<Item: Iterator<Item = u32>>>() { | |||
2055 | #[test] | 2055 | #[test] |
2056 | fn proc_macro_server_types() { | 2056 | fn proc_macro_server_types() { |
2057 | assert_snapshot!( | 2057 | assert_snapshot!( |
2058 | infer_with_mismatches(r#" | 2058 | infer(r#" |
2059 | macro_rules! with_api { | 2059 | macro_rules! with_api { |
2060 | ($S:ident, $self:ident, $m:ident) => { | 2060 | ($S:ident, $self:ident, $m:ident) => { |
2061 | $m! { | 2061 | $m! { |
@@ -2069,9 +2069,9 @@ macro_rules! with_api { | |||
2069 | } | 2069 | } |
2070 | macro_rules! associated_item { | 2070 | macro_rules! associated_item { |
2071 | (type TokenStream) => | 2071 | (type TokenStream) => |
2072 | (type TokenStream: 'static + Clone;); | 2072 | (type TokenStream: 'static;); |
2073 | (type Group) => | 2073 | (type Group) => |
2074 | (type Group: 'static + Clone;); | 2074 | (type Group: 'static;); |
2075 | ($($item:tt)*) => ($($item)*;) | 2075 | ($($item:tt)*) => ($($item)*;) |
2076 | } | 2076 | } |
2077 | macro_rules! declare_server_traits { | 2077 | macro_rules! declare_server_traits { |
@@ -2083,21 +2083,23 @@ macro_rules! declare_server_traits { | |||
2083 | } | 2083 | } |
2084 | 2084 | ||
2085 | $(pub trait $name: Types { | 2085 | $(pub trait $name: Types { |
2086 | $(associated_item!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* | 2086 | $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)* |
2087 | })* | 2087 | })* |
2088 | 2088 | ||
2089 | pub trait Server: Types $(+ $name)* {} | 2089 | pub trait Server: Types $(+ $name)* {} |
2090 | impl<S: Types $(+ $name)*> Server for S {} | 2090 | impl<S: Types $(+ $name)*> Server for S {} |
2091 | } | 2091 | } |
2092 | } | 2092 | } |
2093 | |||
2093 | with_api!(Self, self_, declare_server_traits); | 2094 | with_api!(Self, self_, declare_server_traits); |
2094 | struct Group {} | 2095 | struct G {} |
2095 | struct TokenStream {} | 2096 | struct T {} |
2096 | struct Rustc; | 2097 | struct Rustc; |
2097 | impl Types for Rustc { | 2098 | impl Types for Rustc { |
2098 | type TokenStream = TokenStream; | 2099 | type TokenStream = T; |
2099 | type Group = Group; | 2100 | type Group = G; |
2100 | } | 2101 | } |
2102 | |||
2101 | fn make<T>() -> T { loop {} } | 2103 | fn make<T>() -> T { loop {} } |
2102 | impl TokenStream for Rustc { | 2104 | impl TokenStream for Rustc { |
2103 | fn new() -> Self::TokenStream { | 2105 | fn new() -> Self::TokenStream { |
@@ -2105,17 +2107,17 @@ impl TokenStream for Rustc { | |||
2105 | make() | 2107 | make() |
2106 | } | 2108 | } |
2107 | } | 2109 | } |
2108 | "#, true), | 2110 | "#), |
2109 | @r###" | 2111 | @r###" |
2110 | 1115..1126 '{ loop {} }': T | 2112 | 1062..1073 '{ loop {} }': T |
2111 | 1117..1124 'loop {}': ! | 2113 | 1064..1071 'loop {}': ! |
2112 | 1122..1124 '{}': () | 2114 | 1069..1071 '{}': () |
2113 | 1190..1253 '{ ... }': {unknown} | 2115 | 1137..1200 '{ ... }': T |
2114 | 1204..1209 'group': {unknown} | 2116 | 1151..1156 'group': G |
2115 | 1225..1229 'make': fn make<{unknown}>() -> {unknown} | 2117 | 1172..1176 'make': fn make<G>() -> G |
2116 | 1225..1231 'make()': {unknown} | 2118 | 1172..1178 'make()': G |
2117 | 1241..1245 'make': fn make<{unknown}>() -> {unknown} | 2119 | 1188..1192 'make': fn make<T>() -> T |
2118 | 1241..1247 'make()': {unknown} | 2120 | 1188..1194 'make()': T |
2119 | "### | 2121 | "### |
2120 | ); | 2122 | ); |
2121 | } | 2123 | } |