diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-05-23 02:00:33 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-05-23 02:00:33 +0100 |
commit | e4722b6492c3a3b9636f7da6cee34b5879100de3 (patch) | |
tree | 40647077f6cfbd6481b00c5b9f6ecc14e67bd749 /crates/hir_def/src | |
parent | bc1ba1549d97e7d5ddceb16b7238ae8aab5794d0 (diff) | |
parent | 15ff7faf3dd7979cce2fb76106add30bb771c503 (diff) |
Merge #8932
8932: internal: even prettier itemtrees r=jonas-schievink a=jonas-schievink
Extends the ItemTree pretty printer to handle all `Path`s, and to print generic parameters and where-clauses.
bors r+
Co-authored-by: Jonas Schievink <[email protected]>
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r-- | crates/hir_def/src/item_tree/pretty.rs | 254 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree/tests.rs | 122 |
2 files changed, 342 insertions, 34 deletions
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs index 5ec02d1be..4bc87a0e2 100644 --- a/crates/hir_def/src/item_tree/pretty.rs +++ b/crates/hir_def/src/item_tree/pretty.rs | |||
@@ -2,7 +2,12 @@ | |||
2 | 2 | ||
3 | use std::fmt::{self, Write}; | 3 | use std::fmt::{self, Write}; |
4 | 4 | ||
5 | use crate::{attr::RawAttrs, visibility::RawVisibility}; | 5 | use crate::{ |
6 | attr::RawAttrs, | ||
7 | generics::{WherePredicate, WherePredicateTypeTarget}, | ||
8 | path::GenericArg, | ||
9 | visibility::RawVisibility, | ||
10 | }; | ||
6 | 11 | ||
7 | use super::*; | 12 | use super::*; |
8 | 13 | ||
@@ -70,6 +75,13 @@ impl<'a> Printer<'a> { | |||
70 | } | 75 | } |
71 | } | 76 | } |
72 | 77 | ||
78 | fn whitespace(&mut self) { | ||
79 | match self.buf.chars().next_back() { | ||
80 | None | Some('\n') | Some(' ') => {} | ||
81 | _ => self.buf.push(' '), | ||
82 | } | ||
83 | } | ||
84 | |||
73 | fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool) { | 85 | fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool) { |
74 | let inner = if inner { "!" } else { "" }; | 86 | let inner = if inner { "!" } else { "" }; |
75 | for attr in &**attrs { | 87 | for attr in &**attrs { |
@@ -100,7 +112,8 @@ impl<'a> Printer<'a> { | |||
100 | fn print_fields(&mut self, fields: &Fields) { | 112 | fn print_fields(&mut self, fields: &Fields) { |
101 | match fields { | 113 | match fields { |
102 | Fields::Record(fields) => { | 114 | Fields::Record(fields) => { |
103 | w!(self, " {{"); | 115 | self.whitespace(); |
116 | w!(self, "{{"); | ||
104 | self.indented(|this| { | 117 | self.indented(|this| { |
105 | for field in fields.clone() { | 118 | for field in fields.clone() { |
106 | let Field { visibility, name, type_ref } = &this.tree[field]; | 119 | let Field { visibility, name, type_ref } = &this.tree[field]; |
@@ -131,6 +144,25 @@ impl<'a> Printer<'a> { | |||
131 | } | 144 | } |
132 | } | 145 | } |
133 | 146 | ||
147 | fn print_fields_and_where_clause(&mut self, fields: &Fields, params: &GenericParams) { | ||
148 | match fields { | ||
149 | Fields::Record(_) => { | ||
150 | if self.print_where_clause(params) { | ||
151 | wln!(self); | ||
152 | } | ||
153 | self.print_fields(fields); | ||
154 | } | ||
155 | Fields::Unit => { | ||
156 | self.print_where_clause(params); | ||
157 | self.print_fields(fields); | ||
158 | } | ||
159 | Fields::Tuple(_) => { | ||
160 | self.print_fields(fields); | ||
161 | self.print_where_clause(params); | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | |||
134 | fn print_mod_item(&mut self, item: ModItem) { | 166 | fn print_mod_item(&mut self, item: ModItem) { |
135 | self.print_attrs_of(item); | 167 | self.print_attrs_of(item); |
136 | 168 | ||
@@ -174,7 +206,7 @@ impl<'a> Printer<'a> { | |||
174 | let Function { | 206 | let Function { |
175 | name, | 207 | name, |
176 | visibility, | 208 | visibility, |
177 | generic_params: _, // FIXME print these somehow | 209 | generic_params, |
178 | abi, | 210 | abi, |
179 | params, | 211 | params, |
180 | ret_type, | 212 | ret_type, |
@@ -188,7 +220,9 @@ impl<'a> Printer<'a> { | |||
188 | if let Some(abi) = abi { | 220 | if let Some(abi) = abi { |
189 | w!(self, "extern \"{}\" ", abi); | 221 | w!(self, "extern \"{}\" ", abi); |
190 | } | 222 | } |
191 | w!(self, "fn {}(", name); | 223 | w!(self, "fn {}", name); |
224 | self.print_generic_params(generic_params); | ||
225 | w!(self, "("); | ||
192 | if !params.is_empty() { | 226 | if !params.is_empty() { |
193 | self.indented(|this| { | 227 | self.indented(|this| { |
194 | for param in params.clone() { | 228 | for param in params.clone() { |
@@ -208,14 +242,15 @@ impl<'a> Printer<'a> { | |||
208 | } | 242 | } |
209 | w!(self, ") -> "); | 243 | w!(self, ") -> "); |
210 | self.print_type_ref(ret_type); | 244 | self.print_type_ref(ret_type); |
245 | self.print_where_clause(generic_params); | ||
211 | wln!(self, ";"); | 246 | wln!(self, ";"); |
212 | } | 247 | } |
213 | ModItem::Struct(it) => { | 248 | ModItem::Struct(it) => { |
214 | let Struct { visibility, name, fields, generic_params: _, ast_id: _ } = | 249 | let Struct { visibility, name, fields, generic_params, ast_id: _ } = &self.tree[it]; |
215 | &self.tree[it]; | ||
216 | self.print_visibility(*visibility); | 250 | self.print_visibility(*visibility); |
217 | w!(self, "struct {}", name); | 251 | w!(self, "struct {}", name); |
218 | self.print_fields(fields); | 252 | self.print_generic_params(generic_params); |
253 | self.print_fields_and_where_clause(fields, generic_params); | ||
219 | if matches!(fields, Fields::Record(_)) { | 254 | if matches!(fields, Fields::Record(_)) { |
220 | wln!(self); | 255 | wln!(self); |
221 | } else { | 256 | } else { |
@@ -223,11 +258,11 @@ impl<'a> Printer<'a> { | |||
223 | } | 258 | } |
224 | } | 259 | } |
225 | ModItem::Union(it) => { | 260 | ModItem::Union(it) => { |
226 | let Union { name, visibility, fields, generic_params: _, ast_id: _ } = | 261 | let Union { name, visibility, fields, generic_params, ast_id: _ } = &self.tree[it]; |
227 | &self.tree[it]; | ||
228 | self.print_visibility(*visibility); | 262 | self.print_visibility(*visibility); |
229 | w!(self, "union {}", name); | 263 | w!(self, "union {}", name); |
230 | self.print_fields(fields); | 264 | self.print_generic_params(generic_params); |
265 | self.print_fields_and_where_clause(fields, generic_params); | ||
231 | if matches!(fields, Fields::Record(_)) { | 266 | if matches!(fields, Fields::Record(_)) { |
232 | wln!(self); | 267 | wln!(self); |
233 | } else { | 268 | } else { |
@@ -235,10 +270,11 @@ impl<'a> Printer<'a> { | |||
235 | } | 270 | } |
236 | } | 271 | } |
237 | ModItem::Enum(it) => { | 272 | ModItem::Enum(it) => { |
238 | let Enum { name, visibility, variants, generic_params: _, ast_id: _ } = | 273 | let Enum { name, visibility, variants, generic_params, ast_id: _ } = &self.tree[it]; |
239 | &self.tree[it]; | ||
240 | self.print_visibility(*visibility); | 274 | self.print_visibility(*visibility); |
241 | w!(self, "enum {} {{", name); | 275 | w!(self, "enum {}", name); |
276 | self.print_generic_params(generic_params); | ||
277 | self.print_where_clause_and_opening_brace(generic_params); | ||
242 | self.indented(|this| { | 278 | self.indented(|this| { |
243 | for variant in variants.clone() { | 279 | for variant in variants.clone() { |
244 | let Variant { name, fields } = &this.tree[variant]; | 280 | let Variant { name, fields } = &this.tree[variant]; |
@@ -286,7 +322,7 @@ impl<'a> Printer<'a> { | |||
286 | is_unsafe, | 322 | is_unsafe, |
287 | bounds, | 323 | bounds, |
288 | items, | 324 | items, |
289 | generic_params: _, | 325 | generic_params, |
290 | ast_id: _, | 326 | ast_id: _, |
291 | } = &self.tree[it]; | 327 | } = &self.tree[it]; |
292 | self.print_visibility(*visibility); | 328 | self.print_visibility(*visibility); |
@@ -297,11 +333,12 @@ impl<'a> Printer<'a> { | |||
297 | w!(self, "auto "); | 333 | w!(self, "auto "); |
298 | } | 334 | } |
299 | w!(self, "trait {}", name); | 335 | w!(self, "trait {}", name); |
336 | self.print_generic_params(generic_params); | ||
300 | if !bounds.is_empty() { | 337 | if !bounds.is_empty() { |
301 | w!(self, ": "); | 338 | w!(self, ": "); |
302 | self.print_type_bounds(bounds); | 339 | self.print_type_bounds(bounds); |
303 | } | 340 | } |
304 | w!(self, " {{"); | 341 | self.print_where_clause_and_opening_brace(generic_params); |
305 | self.indented(|this| { | 342 | self.indented(|this| { |
306 | for item in &**items { | 343 | for item in &**items { |
307 | this.print_mod_item((*item).into()); | 344 | this.print_mod_item((*item).into()); |
@@ -310,15 +347,11 @@ impl<'a> Printer<'a> { | |||
310 | wln!(self, "}}"); | 347 | wln!(self, "}}"); |
311 | } | 348 | } |
312 | ModItem::Impl(it) => { | 349 | ModItem::Impl(it) => { |
313 | let Impl { | 350 | let Impl { target_trait, self_ty, is_negative, items, generic_params, ast_id: _ } = |
314 | target_trait, | 351 | &self.tree[it]; |
315 | self_ty, | 352 | w!(self, "impl"); |
316 | is_negative, | 353 | self.print_generic_params(generic_params); |
317 | items, | 354 | w!(self, " "); |
318 | generic_params: _, | ||
319 | ast_id: _, | ||
320 | } = &self.tree[it]; | ||
321 | w!(self, "impl "); | ||
322 | if *is_negative { | 355 | if *is_negative { |
323 | w!(self, "!"); | 356 | w!(self, "!"); |
324 | } | 357 | } |
@@ -327,7 +360,7 @@ impl<'a> Printer<'a> { | |||
327 | w!(self, " for "); | 360 | w!(self, " for "); |
328 | } | 361 | } |
329 | self.print_type_ref(self_ty); | 362 | self.print_type_ref(self_ty); |
330 | w!(self, " {{"); | 363 | self.print_where_clause_and_opening_brace(generic_params); |
331 | self.indented(|this| { | 364 | self.indented(|this| { |
332 | for item in &**items { | 365 | for item in &**items { |
333 | this.print_mod_item((*item).into()); | 366 | this.print_mod_item((*item).into()); |
@@ -342,11 +375,12 @@ impl<'a> Printer<'a> { | |||
342 | bounds, | 375 | bounds, |
343 | type_ref, | 376 | type_ref, |
344 | is_extern, | 377 | is_extern, |
345 | generic_params: _, | 378 | generic_params, |
346 | ast_id: _, | 379 | ast_id: _, |
347 | } = &self.tree[it]; | 380 | } = &self.tree[it]; |
348 | self.print_visibility(*visibility); | 381 | self.print_visibility(*visibility); |
349 | w!(self, "type {}", name); | 382 | w!(self, "type {}", name); |
383 | self.print_generic_params(generic_params); | ||
350 | if !bounds.is_empty() { | 384 | if !bounds.is_empty() { |
351 | w!(self, ": "); | 385 | w!(self, ": "); |
352 | self.print_type_bounds(bounds); | 386 | self.print_type_bounds(bounds); |
@@ -355,6 +389,7 @@ impl<'a> Printer<'a> { | |||
355 | w!(self, " = "); | 389 | w!(self, " = "); |
356 | self.print_type_ref(ty); | 390 | self.print_type_ref(ty); |
357 | } | 391 | } |
392 | self.print_where_clause(generic_params); | ||
358 | w!(self, ";"); | 393 | w!(self, ";"); |
359 | if *is_extern { | 394 | if *is_extern { |
360 | w!(self, " // extern"); | 395 | w!(self, " // extern"); |
@@ -466,7 +501,7 @@ impl<'a> Printer<'a> { | |||
466 | TypeRef::Macro(_ast_id) => { | 501 | TypeRef::Macro(_ast_id) => { |
467 | w!(self, "<macro>"); | 502 | w!(self, "<macro>"); |
468 | } | 503 | } |
469 | TypeRef::Error => drop(write!(self, "{{unknown}}")), | 504 | TypeRef::Error => w!(self, "{{unknown}}"), |
470 | TypeRef::ImplTrait(bounds) => { | 505 | TypeRef::ImplTrait(bounds) => { |
471 | w!(self, "impl "); | 506 | w!(self, "impl "); |
472 | self.print_type_bounds(bounds); | 507 | self.print_type_bounds(bounds); |
@@ -493,15 +528,168 @@ impl<'a> Printer<'a> { | |||
493 | } | 528 | } |
494 | 529 | ||
495 | fn print_path(&mut self, path: &Path) { | 530 | fn print_path(&mut self, path: &Path) { |
496 | if path.type_anchor().is_none() | 531 | match path.type_anchor() { |
497 | && path.segments().iter().all(|seg| seg.args_and_bindings.is_none()) | 532 | Some(anchor) => { |
498 | { | 533 | w!(self, "<"); |
499 | w!(self, "{}", path.mod_path()); | 534 | self.print_type_ref(anchor); |
535 | w!(self, ">::"); | ||
536 | } | ||
537 | None => match path.kind() { | ||
538 | PathKind::Plain => {} | ||
539 | PathKind::Super(0) => w!(self, "self::"), | ||
540 | PathKind::Super(n) => { | ||
541 | for _ in 0..*n { | ||
542 | w!(self, "super::"); | ||
543 | } | ||
544 | } | ||
545 | PathKind::Crate => w!(self, "crate::"), | ||
546 | PathKind::Abs => w!(self, "::"), | ||
547 | PathKind::DollarCrate(_) => w!(self, "$crate::"), | ||
548 | }, | ||
549 | } | ||
550 | |||
551 | for (i, segment) in path.segments().iter().enumerate() { | ||
552 | if i != 0 { | ||
553 | w!(self, "::"); | ||
554 | } | ||
555 | |||
556 | w!(self, "{}", segment.name); | ||
557 | if let Some(generics) = segment.args_and_bindings { | ||
558 | // NB: these are all in type position, so `::<` turbofish syntax is not necessary | ||
559 | w!(self, "<"); | ||
560 | let mut first = true; | ||
561 | let args = if generics.has_self_type { | ||
562 | let (self_ty, args) = generics.args.split_first().unwrap(); | ||
563 | w!(self, "Self="); | ||
564 | self.print_generic_arg(self_ty); | ||
565 | first = false; | ||
566 | args | ||
567 | } else { | ||
568 | &generics.args | ||
569 | }; | ||
570 | for arg in args { | ||
571 | if !first { | ||
572 | w!(self, ", "); | ||
573 | } | ||
574 | first = false; | ||
575 | self.print_generic_arg(arg); | ||
576 | } | ||
577 | for binding in &generics.bindings { | ||
578 | if !first { | ||
579 | w!(self, ", "); | ||
580 | } | ||
581 | first = false; | ||
582 | w!(self, "{}", binding.name); | ||
583 | if !binding.bounds.is_empty() { | ||
584 | w!(self, ": "); | ||
585 | self.print_type_bounds(&binding.bounds); | ||
586 | } | ||
587 | if let Some(ty) = &binding.type_ref { | ||
588 | w!(self, " = "); | ||
589 | self.print_type_ref(ty); | ||
590 | } | ||
591 | } | ||
592 | |||
593 | w!(self, ">"); | ||
594 | } | ||
595 | } | ||
596 | } | ||
597 | |||
598 | fn print_generic_arg(&mut self, arg: &GenericArg) { | ||
599 | match arg { | ||
600 | GenericArg::Type(ty) => self.print_type_ref(ty), | ||
601 | GenericArg::Lifetime(lt) => w!(self, "{}", lt.name), | ||
602 | } | ||
603 | } | ||
604 | |||
605 | fn print_generic_params(&mut self, params: &GenericParams) { | ||
606 | if params.types.is_empty() && params.lifetimes.is_empty() && params.consts.is_empty() { | ||
607 | return; | ||
608 | } | ||
609 | |||
610 | w!(self, "<"); | ||
611 | let mut first = true; | ||
612 | for (_, lt) in params.lifetimes.iter() { | ||
613 | if !first { | ||
614 | w!(self, ", "); | ||
615 | } | ||
616 | first = false; | ||
617 | w!(self, "{}", lt.name); | ||
618 | } | ||
619 | for (idx, ty) in params.types.iter() { | ||
620 | if !first { | ||
621 | w!(self, ", "); | ||
622 | } | ||
623 | first = false; | ||
624 | match &ty.name { | ||
625 | Some(name) => w!(self, "{}", name), | ||
626 | None => w!(self, "_anon_{}", idx.into_raw()), | ||
627 | } | ||
628 | } | ||
629 | for (_, konst) in params.consts.iter() { | ||
630 | if !first { | ||
631 | w!(self, ", "); | ||
632 | } | ||
633 | first = false; | ||
634 | w!(self, "const {}: ", konst.name); | ||
635 | self.print_type_ref(&konst.ty); | ||
636 | } | ||
637 | w!(self, ">"); | ||
638 | } | ||
639 | |||
640 | fn print_where_clause_and_opening_brace(&mut self, params: &GenericParams) { | ||
641 | if self.print_where_clause(params) { | ||
642 | w!(self, "\n{{"); | ||
500 | } else { | 643 | } else { |
501 | // too complicated, just use `Debug` | 644 | self.whitespace(); |
502 | w!(self, "{:?}", path); | 645 | w!(self, "{{"); |
503 | } | 646 | } |
504 | } | 647 | } |
648 | |||
649 | fn print_where_clause(&mut self, params: &GenericParams) -> bool { | ||
650 | if params.where_predicates.is_empty() { | ||
651 | return false; | ||
652 | } | ||
653 | |||
654 | w!(self, "\nwhere"); | ||
655 | self.indented(|this| { | ||
656 | for (i, pred) in params.where_predicates.iter().enumerate() { | ||
657 | if i != 0 { | ||
658 | wln!(this, ","); | ||
659 | } | ||
660 | |||
661 | let (target, bound) = match pred { | ||
662 | WherePredicate::TypeBound { target, bound } => (target, bound), | ||
663 | WherePredicate::Lifetime { target, bound } => { | ||
664 | wln!(this, "{}: {},", target.name, bound.name); | ||
665 | continue; | ||
666 | } | ||
667 | WherePredicate::ForLifetime { lifetimes, target, bound } => { | ||
668 | w!(this, "for<"); | ||
669 | for (i, lt) in lifetimes.iter().enumerate() { | ||
670 | if i != 0 { | ||
671 | w!(this, ", "); | ||
672 | } | ||
673 | w!(this, "{}", lt); | ||
674 | } | ||
675 | w!(this, "> "); | ||
676 | (target, bound) | ||
677 | } | ||
678 | }; | ||
679 | |||
680 | match target { | ||
681 | WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty), | ||
682 | WherePredicateTypeTarget::TypeParam(id) => match ¶ms.types[*id].name { | ||
683 | Some(name) => w!(this, "{}", name), | ||
684 | None => w!(this, "_anon_{}", id.into_raw()), | ||
685 | }, | ||
686 | } | ||
687 | w!(this, ": "); | ||
688 | this.print_type_bounds(std::slice::from_ref(bound)); | ||
689 | } | ||
690 | }); | ||
691 | true | ||
692 | } | ||
505 | } | 693 | } |
506 | 694 | ||
507 | impl<'a> Write for Printer<'a> { | 695 | impl<'a> Write for Printer<'a> { |
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs index 100ae9b97..6407871b5 100644 --- a/crates/hir_def/src/item_tree/tests.rs +++ b/crates/hir_def/src/item_tree/tests.rs | |||
@@ -183,7 +183,11 @@ trait Tr: SuperTrait + 'lifetime { | |||
183 | _: (), | 183 | _: (), |
184 | ) -> (); | 184 | ) -> (); |
185 | 185 | ||
186 | pub(self) trait Tr: SuperTrait + 'lifetime { | 186 | pub(self) trait Tr<Self>: SuperTrait + 'lifetime |
187 | where | ||
188 | Self: SuperTrait, | ||
189 | Self: 'lifetime | ||
190 | { | ||
187 | pub(self) type Assoc: AssocBound = Default; | 191 | pub(self) type Assoc: AssocBound = Default; |
188 | 192 | ||
189 | // flags = 0x1 | 193 | // flags = 0x1 |
@@ -207,6 +211,8 @@ mod inline { | |||
207 | 211 | ||
208 | fn fn_in_module() {} | 212 | fn fn_in_module() {} |
209 | } | 213 | } |
214 | |||
215 | mod outline; | ||
210 | "#, | 216 | "#, |
211 | expect![[r##" | 217 | expect![[r##" |
212 | #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 } | 218 | #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 } |
@@ -217,6 +223,8 @@ mod inline { | |||
217 | // flags = 0x2 | 223 | // flags = 0x2 |
218 | pub(self) fn fn_in_module() -> (); | 224 | pub(self) fn fn_in_module() -> (); |
219 | } | 225 | } |
226 | |||
227 | pub(self) mod outline; | ||
220 | "##]], | 228 | "##]], |
221 | ); | 229 | ); |
222 | } | 230 | } |
@@ -242,3 +250,115 @@ m!(); | |||
242 | "#]], | 250 | "#]], |
243 | ); | 251 | ); |
244 | } | 252 | } |
253 | |||
254 | #[test] | ||
255 | fn mod_paths() { | ||
256 | check( | ||
257 | r#" | ||
258 | struct S { | ||
259 | a: self::Ty, | ||
260 | b: super::SuperTy, | ||
261 | c: super::super::SuperSuperTy, | ||
262 | d: ::abs::Path, | ||
263 | e: crate::Crate, | ||
264 | f: plain::path::Ty, | ||
265 | } | ||
266 | "#, | ||
267 | expect![[r#" | ||
268 | pub(self) struct S { | ||
269 | pub(self) a: self::Ty, | ||
270 | pub(self) b: super::SuperTy, | ||
271 | pub(self) c: super::super::SuperSuperTy, | ||
272 | pub(self) d: ::abs::Path, | ||
273 | pub(self) e: crate::Crate, | ||
274 | pub(self) f: plain::path::Ty, | ||
275 | } | ||
276 | "#]], | ||
277 | ) | ||
278 | } | ||
279 | |||
280 | #[test] | ||
281 | fn types() { | ||
282 | check( | ||
283 | r#" | ||
284 | struct S { | ||
285 | a: Mixed<'a, T, Item=(), OtherItem=u8>, | ||
286 | b: <Fully as Qualified>::Syntax, | ||
287 | c: <TypeAnchored>::Path::<'a>, | ||
288 | } | ||
289 | "#, | ||
290 | expect![[r#" | ||
291 | pub(self) struct S { | ||
292 | pub(self) a: Mixed<'a, T, Item = (), OtherItem = u8>, | ||
293 | pub(self) b: Qualified<Self=Fully>::Syntax, | ||
294 | pub(self) c: <TypeAnchored>::Path<'a>, | ||
295 | } | ||
296 | "#]], | ||
297 | ) | ||
298 | } | ||
299 | |||
300 | #[test] | ||
301 | fn generics() { | ||
302 | check( | ||
303 | r#" | ||
304 | struct S<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> { | ||
305 | field: &'a &'b T, | ||
306 | } | ||
307 | |||
308 | struct Tuple<T: Copy>(T); | ||
309 | |||
310 | impl<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> S<'a, 'b, T, K> { | ||
311 | fn f<G: 'a>(arg: impl Copy) -> impl Copy {} | ||
312 | } | ||
313 | |||
314 | enum Enum<'a, T, const U: u8> {} | ||
315 | union Union<'a, T, const U: u8> {} | ||
316 | |||
317 | trait Tr<'a, T: 'a>: Super {} | ||
318 | "#, | ||
319 | expect![[r#" | ||
320 | pub(self) struct S<'a, 'b, T, const K: u8> | ||
321 | where | ||
322 | T: Copy, | ||
323 | T: 'a, | ||
324 | T: 'b | ||
325 | { | ||
326 | pub(self) field: &'a &'b T, | ||
327 | } | ||
328 | |||
329 | pub(self) struct Tuple<T>( | ||
330 | pub(self) 0: T, | ||
331 | ) | ||
332 | where | ||
333 | T: Copy; | ||
334 | |||
335 | impl<'a, 'b, T, const K: u8> S<'a, 'b, T, K> | ||
336 | where | ||
337 | T: Copy, | ||
338 | T: 'a, | ||
339 | T: 'b | ||
340 | { | ||
341 | // flags = 0x2 | ||
342 | pub(self) fn f<G, _anon_1>( | ||
343 | _: impl Copy, | ||
344 | ) -> impl Copy | ||
345 | where | ||
346 | G: 'a, | ||
347 | _anon_1: Copy; | ||
348 | } | ||
349 | |||
350 | pub(self) enum Enum<'a, T, const U: u8> { | ||
351 | } | ||
352 | |||
353 | pub(self) union Union<'a, T, const U: u8> { | ||
354 | } | ||
355 | |||
356 | pub(self) trait Tr<'a, Self, T>: Super | ||
357 | where | ||
358 | Self: Super, | ||
359 | T: 'a | ||
360 | { | ||
361 | } | ||
362 | "#]], | ||
363 | ) | ||
364 | } | ||