From c22ccd07fecb964b11cba283d5ab184967c2669b Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 23 May 2021 00:37:15 +0200 Subject: ItemTree: pretty-print all paths --- crates/hir_def/src/item_tree/pretty.rs | 82 ++++++++++++++++++++++++++++++---- crates/hir_def/src/item_tree/tests.rs | 46 +++++++++++++++++++ 2 files changed, 119 insertions(+), 9 deletions(-) (limited to 'crates/hir_def/src') diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs index 5ec02d1be..c91f21bbb 100644 --- a/crates/hir_def/src/item_tree/pretty.rs +++ b/crates/hir_def/src/item_tree/pretty.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Write}; -use crate::{attr::RawAttrs, visibility::RawVisibility}; +use crate::{attr::RawAttrs, path::GenericArg, visibility::RawVisibility}; use super::*; @@ -466,7 +466,7 @@ impl<'a> Printer<'a> { TypeRef::Macro(_ast_id) => { w!(self, ""); } - TypeRef::Error => drop(write!(self, "{{unknown}}")), + TypeRef::Error => w!(self, "{{unknown}}"), TypeRef::ImplTrait(bounds) => { w!(self, "impl "); self.print_type_bounds(bounds); @@ -493,13 +493,77 @@ impl<'a> Printer<'a> { } fn print_path(&mut self, path: &Path) { - if path.type_anchor().is_none() - && path.segments().iter().all(|seg| seg.args_and_bindings.is_none()) - { - w!(self, "{}", path.mod_path()); - } else { - // too complicated, just use `Debug` - w!(self, "{:?}", path); + match path.type_anchor() { + Some(anchor) => { + w!(self, "<"); + self.print_type_ref(anchor); + w!(self, ">::"); + } + None => match path.kind() { + PathKind::Plain => {} + PathKind::Super(0) => w!(self, "self::"), + PathKind::Super(n) => { + for _ in 0..*n { + w!(self, "super::"); + } + } + PathKind::Crate => w!(self, "crate::"), + PathKind::Abs => w!(self, "::"), + PathKind::DollarCrate(_) => w!(self, "$crate::"), + }, + } + + for (i, segment) in path.segments().iter().enumerate() { + if i != 0 { + w!(self, "::"); + } + + w!(self, "{}", segment.name); + if let Some(generics) = segment.args_and_bindings { + // NB: these are all in type position, so `::<` turbofish syntax is not necessary + w!(self, "<"); + let mut first = true; + let args = if generics.has_self_type { + let (self_ty, args) = generics.args.split_first().unwrap(); + w!(self, "Self="); + self.print_generic_arg(self_ty); + first = false; + args + } else { + &generics.args + }; + for arg in args { + if !first { + w!(self, ", "); + } + first = false; + self.print_generic_arg(arg); + } + for binding in &generics.bindings { + if !first { + w!(self, ", "); + } + first = false; + w!(self, "{}", binding.name); + if !binding.bounds.is_empty() { + w!(self, ": "); + self.print_type_bounds(&binding.bounds); + } + if let Some(ty) = &binding.type_ref { + w!(self, " = "); + self.print_type_ref(ty); + } + } + + w!(self, ">"); + } + } + } + + fn print_generic_arg(&mut self, arg: &GenericArg) { + match arg { + GenericArg::Type(ty) => self.print_type_ref(ty), + GenericArg::Lifetime(lt) => w!(self, "{}", lt.name), } } } diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs index 100ae9b97..91c44362e 100644 --- a/crates/hir_def/src/item_tree/tests.rs +++ b/crates/hir_def/src/item_tree/tests.rs @@ -242,3 +242,49 @@ m!(); "#]], ); } + +#[test] +fn mod_paths() { + check( + r#" +struct S { + a: self::Ty, + b: super::SuperTy, + c: super::super::SuperSuperTy, + d: ::abs::Path, + e: crate::Crate, + f: plain::path::Ty, +} + "#, + expect![[r#" + pub(self) struct S { + pub(self) a: self::Ty, + pub(self) b: super::SuperTy, + pub(self) c: super::super::SuperSuperTy, + pub(self) d: ::abs::Path, + pub(self) e: crate::Crate, + pub(self) f: plain::path::Ty, + } + "#]], + ) +} + +#[test] +fn types() { + check( + r#" +struct S { + a: Mixed<'a, T, Item=(), OtherItem=u8>, + b: ::Syntax, + c: ::Path::<'a>, +} + "#, + expect![[r#" + pub(self) struct S { + pub(self) a: Mixed<'a, T, Item = (), OtherItem = u8>, + pub(self) b: Qualified::Syntax, + pub(self) c: ::Path<'a>, + } + "#]], + ) +} -- cgit v1.2.3 From 380293d6c2ead91a0988183ca634d9eb4f4fa9d7 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 23 May 2021 01:00:17 +0200 Subject: Pretty-print generic parameters --- crates/hir_def/src/item_tree/pretty.rs | 88 +++++++++++++++++++++++++--------- crates/hir_def/src/item_tree/tests.rs | 33 +++++++++++++ 2 files changed, 99 insertions(+), 22 deletions(-) (limited to 'crates/hir_def/src') diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs index c91f21bbb..d00de2f73 100644 --- a/crates/hir_def/src/item_tree/pretty.rs +++ b/crates/hir_def/src/item_tree/pretty.rs @@ -2,7 +2,9 @@ use std::fmt::{self, Write}; -use crate::{attr::RawAttrs, path::GenericArg, visibility::RawVisibility}; +use crate::{ + attr::RawAttrs, generics::TypeParamProvenance, path::GenericArg, visibility::RawVisibility, +}; use super::*; @@ -174,7 +176,7 @@ impl<'a> Printer<'a> { let Function { name, visibility, - generic_params: _, // FIXME print these somehow + generic_params, abi, params, ret_type, @@ -188,7 +190,9 @@ impl<'a> Printer<'a> { if let Some(abi) = abi { w!(self, "extern \"{}\" ", abi); } - w!(self, "fn {}(", name); + w!(self, "fn {}", name); + self.print_generic_params(generic_params); + w!(self, "("); if !params.is_empty() { self.indented(|this| { for param in params.clone() { @@ -211,10 +215,10 @@ impl<'a> Printer<'a> { wln!(self, ";"); } ModItem::Struct(it) => { - let Struct { visibility, name, fields, generic_params: _, ast_id: _ } = - &self.tree[it]; + let Struct { visibility, name, fields, generic_params, ast_id: _ } = &self.tree[it]; self.print_visibility(*visibility); w!(self, "struct {}", name); + self.print_generic_params(generic_params); self.print_fields(fields); if matches!(fields, Fields::Record(_)) { wln!(self); @@ -223,10 +227,10 @@ impl<'a> Printer<'a> { } } ModItem::Union(it) => { - let Union { name, visibility, fields, generic_params: _, ast_id: _ } = - &self.tree[it]; + let Union { name, visibility, fields, generic_params, ast_id: _ } = &self.tree[it]; self.print_visibility(*visibility); w!(self, "union {}", name); + self.print_generic_params(generic_params); self.print_fields(fields); if matches!(fields, Fields::Record(_)) { wln!(self); @@ -235,10 +239,11 @@ impl<'a> Printer<'a> { } } ModItem::Enum(it) => { - let Enum { name, visibility, variants, generic_params: _, ast_id: _ } = - &self.tree[it]; + let Enum { name, visibility, variants, generic_params, ast_id: _ } = &self.tree[it]; self.print_visibility(*visibility); - w!(self, "enum {} {{", name); + w!(self, "enum {}", name); + self.print_generic_params(generic_params); + w!(self, " {{"); self.indented(|this| { for variant in variants.clone() { let Variant { name, fields } = &this.tree[variant]; @@ -286,7 +291,7 @@ impl<'a> Printer<'a> { is_unsafe, bounds, items, - generic_params: _, + generic_params, ast_id: _, } = &self.tree[it]; self.print_visibility(*visibility); @@ -296,7 +301,9 @@ impl<'a> Printer<'a> { if *is_auto { w!(self, "auto "); } - w!(self, "trait {}", name); + w!(self, "trait"); + self.print_generic_params(generic_params); + w!(self, " {}", name); if !bounds.is_empty() { w!(self, ": "); self.print_type_bounds(bounds); @@ -310,15 +317,11 @@ impl<'a> Printer<'a> { wln!(self, "}}"); } ModItem::Impl(it) => { - let Impl { - target_trait, - self_ty, - is_negative, - items, - generic_params: _, - ast_id: _, - } = &self.tree[it]; - w!(self, "impl "); + let Impl { target_trait, self_ty, is_negative, items, generic_params, ast_id: _ } = + &self.tree[it]; + w!(self, "impl"); + self.print_generic_params(generic_params); + w!(self, " "); if *is_negative { w!(self, "!"); } @@ -342,11 +345,12 @@ impl<'a> Printer<'a> { bounds, type_ref, is_extern, - generic_params: _, + generic_params, ast_id: _, } = &self.tree[it]; self.print_visibility(*visibility); w!(self, "type {}", name); + self.print_generic_params(generic_params); if !bounds.is_empty() { w!(self, ": "); self.print_type_bounds(bounds); @@ -566,6 +570,46 @@ impl<'a> Printer<'a> { GenericArg::Lifetime(lt) => w!(self, "{}", lt.name), } } + + fn print_generic_params(&mut self, params: &GenericParams) { + let mut first = true; + for (_, lt) in params.lifetimes.iter() { + if first { + w!(self, "<"); + } else { + w!(self, ", "); + } + first = false; + w!(self, "{}", lt.name); + } + for (_, ty) in params.types.iter() { + if ty.provenance != TypeParamProvenance::TypeParamList { + continue; + } + if let Some(name) = &ty.name { + if first { + w!(self, "<"); + } else { + w!(self, ", "); + } + first = false; + w!(self, "{}", name); + } + } + for (_, konst) in params.consts.iter() { + if first { + w!(self, "<"); + } else { + w!(self, ", "); + } + first = false; + w!(self, "const {}: ", konst.name); + self.print_type_ref(&konst.ty); + } + if !first { + w!(self, ">"); + } + } } 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 91c44362e..e0847dc75 100644 --- a/crates/hir_def/src/item_tree/tests.rs +++ b/crates/hir_def/src/item_tree/tests.rs @@ -288,3 +288,36 @@ struct S { "#]], ) } + +#[test] +fn generics() { + check( + r#" +struct S<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> {} + +impl<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> S<'a, 'b, T, K> { + fn f(arg: impl Copy) -> impl Copy {} +} + +enum Enum<'a, T, const U: u8> {} +union Union<'a, T, const U: u8> {} + "#, + expect![[r#" + pub(self) struct S<'a, 'b, T, const K: u8> { + } + + impl<'a, 'b, T, const K: u8> S<'a, 'b, T, K> { + // flags = 0x2 + pub(self) fn f( + _: impl Copy, + ) -> impl Copy; + } + + pub(self) enum Enum<'a, T, const U: u8> { + } + + pub(self) union Union<'a, T, const U: u8> { + } + "#]], + ) +} -- cgit v1.2.3 From 15ff7faf3dd7979cce2fb76106add30bb771c503 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Sun, 23 May 2021 02:51:58 +0200 Subject: Render where clauses and more generic params --- crates/hir_def/src/item_tree/pretty.rs | 136 ++++++++++++++++++++++++++------- crates/hir_def/src/item_tree/tests.rs | 53 +++++++++++-- 2 files changed, 155 insertions(+), 34 deletions(-) (limited to 'crates/hir_def/src') diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs index d00de2f73..4bc87a0e2 100644 --- a/crates/hir_def/src/item_tree/pretty.rs +++ b/crates/hir_def/src/item_tree/pretty.rs @@ -3,7 +3,10 @@ use std::fmt::{self, Write}; use crate::{ - attr::RawAttrs, generics::TypeParamProvenance, path::GenericArg, visibility::RawVisibility, + attr::RawAttrs, + generics::{WherePredicate, WherePredicateTypeTarget}, + path::GenericArg, + visibility::RawVisibility, }; use super::*; @@ -72,6 +75,13 @@ impl<'a> Printer<'a> { } } + fn whitespace(&mut self) { + match self.buf.chars().next_back() { + None | Some('\n') | Some(' ') => {} + _ => self.buf.push(' '), + } + } + fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool) { let inner = if inner { "!" } else { "" }; for attr in &**attrs { @@ -102,7 +112,8 @@ impl<'a> Printer<'a> { fn print_fields(&mut self, fields: &Fields) { match fields { Fields::Record(fields) => { - w!(self, " {{"); + self.whitespace(); + w!(self, "{{"); self.indented(|this| { for field in fields.clone() { let Field { visibility, name, type_ref } = &this.tree[field]; @@ -133,6 +144,25 @@ impl<'a> Printer<'a> { } } + fn print_fields_and_where_clause(&mut self, fields: &Fields, params: &GenericParams) { + match fields { + Fields::Record(_) => { + if self.print_where_clause(params) { + wln!(self); + } + self.print_fields(fields); + } + Fields::Unit => { + self.print_where_clause(params); + self.print_fields(fields); + } + Fields::Tuple(_) => { + self.print_fields(fields); + self.print_where_clause(params); + } + } + } + fn print_mod_item(&mut self, item: ModItem) { self.print_attrs_of(item); @@ -212,6 +242,7 @@ impl<'a> Printer<'a> { } w!(self, ") -> "); self.print_type_ref(ret_type); + self.print_where_clause(generic_params); wln!(self, ";"); } ModItem::Struct(it) => { @@ -219,7 +250,7 @@ impl<'a> Printer<'a> { self.print_visibility(*visibility); w!(self, "struct {}", name); self.print_generic_params(generic_params); - self.print_fields(fields); + self.print_fields_and_where_clause(fields, generic_params); if matches!(fields, Fields::Record(_)) { wln!(self); } else { @@ -231,7 +262,7 @@ impl<'a> Printer<'a> { self.print_visibility(*visibility); w!(self, "union {}", name); self.print_generic_params(generic_params); - self.print_fields(fields); + self.print_fields_and_where_clause(fields, generic_params); if matches!(fields, Fields::Record(_)) { wln!(self); } else { @@ -243,7 +274,7 @@ impl<'a> Printer<'a> { self.print_visibility(*visibility); w!(self, "enum {}", name); self.print_generic_params(generic_params); - w!(self, " {{"); + self.print_where_clause_and_opening_brace(generic_params); self.indented(|this| { for variant in variants.clone() { let Variant { name, fields } = &this.tree[variant]; @@ -301,14 +332,13 @@ impl<'a> Printer<'a> { if *is_auto { w!(self, "auto "); } - w!(self, "trait"); + w!(self, "trait {}", name); self.print_generic_params(generic_params); - w!(self, " {}", name); if !bounds.is_empty() { w!(self, ": "); self.print_type_bounds(bounds); } - w!(self, " {{"); + self.print_where_clause_and_opening_brace(generic_params); self.indented(|this| { for item in &**items { this.print_mod_item((*item).into()); @@ -330,7 +360,7 @@ impl<'a> Printer<'a> { w!(self, " for "); } self.print_type_ref(self_ty); - w!(self, " {{"); + self.print_where_clause_and_opening_brace(generic_params); self.indented(|this| { for item in &**items { this.print_mod_item((*item).into()); @@ -359,6 +389,7 @@ impl<'a> Printer<'a> { w!(self, " = "); self.print_type_ref(ty); } + self.print_where_clause(generic_params); w!(self, ";"); if *is_extern { w!(self, " // extern"); @@ -572,44 +603,93 @@ impl<'a> Printer<'a> { } fn print_generic_params(&mut self, params: &GenericParams) { + if params.types.is_empty() && params.lifetimes.is_empty() && params.consts.is_empty() { + return; + } + + w!(self, "<"); let mut first = true; for (_, lt) in params.lifetimes.iter() { - if first { - w!(self, "<"); - } else { + if !first { w!(self, ", "); } first = false; w!(self, "{}", lt.name); } - for (_, ty) in params.types.iter() { - if ty.provenance != TypeParamProvenance::TypeParamList { - continue; + for (idx, ty) in params.types.iter() { + if !first { + w!(self, ", "); } - if let Some(name) = &ty.name { - if first { - w!(self, "<"); - } else { - w!(self, ", "); - } - first = false; - w!(self, "{}", name); + first = false; + match &ty.name { + Some(name) => w!(self, "{}", name), + None => w!(self, "_anon_{}", idx.into_raw()), } } for (_, konst) in params.consts.iter() { - if first { - w!(self, "<"); - } else { + if !first { w!(self, ", "); } first = false; w!(self, "const {}: ", konst.name); self.print_type_ref(&konst.ty); } - if !first { - w!(self, ">"); + w!(self, ">"); + } + + fn print_where_clause_and_opening_brace(&mut self, params: &GenericParams) { + if self.print_where_clause(params) { + w!(self, "\n{{"); + } else { + self.whitespace(); + w!(self, "{{"); } } + + fn print_where_clause(&mut self, params: &GenericParams) -> bool { + if params.where_predicates.is_empty() { + return false; + } + + w!(self, "\nwhere"); + self.indented(|this| { + for (i, pred) in params.where_predicates.iter().enumerate() { + if i != 0 { + wln!(this, ","); + } + + let (target, bound) = match pred { + WherePredicate::TypeBound { target, bound } => (target, bound), + WherePredicate::Lifetime { target, bound } => { + wln!(this, "{}: {},", target.name, bound.name); + continue; + } + WherePredicate::ForLifetime { lifetimes, target, bound } => { + w!(this, "for<"); + for (i, lt) in lifetimes.iter().enumerate() { + if i != 0 { + w!(this, ", "); + } + w!(this, "{}", lt); + } + w!(this, "> "); + (target, bound) + } + }; + + match target { + WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty), + WherePredicateTypeTarget::TypeParam(id) => match ¶ms.types[*id].name { + Some(name) => w!(this, "{}", name), + None => w!(this, "_anon_{}", id.into_raw()), + }, + } + w!(this, ": "); + this.print_type_bounds(std::slice::from_ref(bound)); + } + }); + true + } } 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 e0847dc75..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 { _: (), ) -> (); - pub(self) trait Tr: SuperTrait + 'lifetime { + pub(self) trait Tr: SuperTrait + 'lifetime + where + Self: SuperTrait, + Self: 'lifetime + { pub(self) type Assoc: AssocBound = Default; // flags = 0x1 @@ -207,6 +211,8 @@ mod inline { fn fn_in_module() {} } + +mod outline; "#, expect![[r##" #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 } @@ -217,6 +223,8 @@ mod inline { // flags = 0x2 pub(self) fn fn_in_module() -> (); } + + pub(self) mod outline; "##]], ); } @@ -293,7 +301,11 @@ struct S { fn generics() { check( r#" -struct S<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> {} +struct S<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> { + field: &'a &'b T, +} + +struct Tuple(T); impl<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> S<'a, 'b, T, K> { fn f(arg: impl Copy) -> impl Copy {} @@ -301,16 +313,38 @@ impl<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> S<'a, 'b, T, K> { enum Enum<'a, T, const U: u8> {} union Union<'a, T, const U: u8> {} + +trait Tr<'a, T: 'a>: Super {} "#, expect![[r#" - pub(self) struct S<'a, 'b, T, const K: u8> { + pub(self) struct S<'a, 'b, T, const K: u8> + where + T: Copy, + T: 'a, + T: 'b + { + pub(self) field: &'a &'b T, } - impl<'a, 'b, T, const K: u8> S<'a, 'b, T, K> { + pub(self) struct Tuple( + pub(self) 0: T, + ) + where + T: Copy; + + impl<'a, 'b, T, const K: u8> S<'a, 'b, T, K> + where + T: Copy, + T: 'a, + T: 'b + { // flags = 0x2 - pub(self) fn f( + pub(self) fn f( _: impl Copy, - ) -> impl Copy; + ) -> impl Copy + where + G: 'a, + _anon_1: Copy; } pub(self) enum Enum<'a, T, const U: u8> { @@ -318,6 +352,13 @@ union Union<'a, T, const U: u8> {} pub(self) union Union<'a, T, const U: u8> { } + + pub(self) trait Tr<'a, Self, T>: Super + where + Self: Super, + T: 'a + { + } "#]], ) } -- cgit v1.2.3