diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs index c91f21bbb15..d00de2f73c8 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 @@ fn print_mod_item(&mut self, item: ModItem) { let Function { name, visibility, - generic_params: _, // FIXME print these somehow + generic_params, abi, params, ret_type, @@ -188,7 +190,9 @@ fn print_mod_item(&mut self, item: ModItem) { 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 @@ fn print_mod_item(&mut self, item: ModItem) { 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 @@ fn print_mod_item(&mut self, item: ModItem) { } } 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 @@ fn print_mod_item(&mut self, item: ModItem) { } } 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 @@ fn print_mod_item(&mut self, item: ModItem) { is_unsafe, bounds, items, - generic_params: _, + generic_params, ast_id: _, } = &self.tree[it]; self.print_visibility(*visibility); @@ -296,7 +301,9 @@ fn print_mod_item(&mut self, item: ModItem) { 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 @@ fn print_mod_item(&mut self, item: ModItem) { 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 @@ fn print_mod_item(&mut self, item: ModItem) { 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 @@ fn print_generic_arg(&mut self, arg: &GenericArg) { 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 91c44362e16..e0847dc7512 100644 --- a/crates/hir_def/src/item_tree/tests.rs +++ b/crates/hir_def/src/item_tree/tests.rs @@ -288,3 +288,36 @@ pub(self) 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> { + } + "#]], + ) +}