1use super::prelude::*;
4use crate::ast::identifiers::global_id::view::{PathSegment, View};
5use std::cell::RefCell;
6
7mod renamings;
8
9#[setup_printer_struct]
11#[derive(Default, Clone)]
12pub struct RustPrinter {
13 current_namespace: RefCell<Option<Vec<String>>>,
14}
15
16impl Printer for RustPrinter {
17 const NAME: &str = "Rust";
18}
19
20impl RenderView for RustPrinter {
21 fn render_path_segment(&self, seg: &PathSegment) -> Vec<String> {
22 if let AnyKind::Constructor(constructor_kind) = seg.kind() {
23 match constructor_kind {
24 global_id::view::ConstructorKind::Constructor { ty } => {
25 if let global_id::view::TypeDefKind::Struct = ty.kind() {
26 return vec![
27 self.render_path_segment_payload(ty.lift().payload())
28 .to_string(),
29 ];
30 }
31 }
32 }
33 };
34 default::render_path_segment(self, seg)
35 }
36 fn render(&self, view: &View) -> Rendered {
37 let (module_path, relative_path) = view.split_at_module();
38 let path_segment = |seg| self.render_path_segment(seg);
39 let mut rendered = Rendered {
40 module: module_path.iter().flat_map(path_segment).collect(),
41 path: relative_path.iter().flat_map(path_segment).collect(),
42 };
43 renamings::rename_rendered(&mut rendered);
44 rendered
45 }
46}
47
48pub struct RustBackend;
50
51impl Backend for RustBackend {
52 type Printer = RustPrinter;
53
54 fn resugaring_phases() -> Vec<Box<dyn Resugaring>> {
55 vec![Box::new(FunctionsToConstants), Box::new(Tuples)]
56 }
57
58 fn module_path(&self, module: &Module) -> camino::Utf8PathBuf {
59 let printer = RustPrinter::default();
60 let path = <RustPrinter as RenderView>::module(&printer, &module.ident.view());
61 camino::Utf8PathBuf::from_iter(path).with_extension("rs")
62 }
63}
64
65const INDENT: isize = 4;
66
67#[prepend_associated_functions_with(install_pretty_helpers!(self: Self))]
68const _: () = {
71 macro_rules! todo {
72 ($($tt:tt)*) => {
73 disambiguated_todo!($($tt)*)
74 };
75 }
76 macro_rules! line {
77 ($($tt:tt)*) => {
78 disambiguated_line!($($tt)*)
79 };
80 }
81 macro_rules! concat {
82 ($($tt:tt)*) => {
83 disambiguated_concat!($($tt)*)
84 };
85 }
86
87 macro_rules! sep {
88 ($l:expr, $it:expr, $r:expr, $sep:expr$(,)?) => {
89 docs![
90 intersperse!($it, docs![$sep, line!()]),
91 docs![","].flat_alt(nil!())
92 ]
93 .enclose(line_!(), line_!())
94 .nest(INDENT)
95 .enclose($l, $r)
96 .group()
97 };
98 ($l:expr, $it:expr, $r:expr$(,)?) => {
99 sep!($l, $it, $r, ",")
100 };
101 }
102
103 macro_rules! print_tuple {
104 ($into_docs:ident) => {{
105 let mut docs: Vec<_> = $into_docs.iter().map(|typ| docs![typ]).collect();
106 if docs.len() == 1 {
107 docs.push(nil![])
108 }
109 sep!("(", docs, ")")
110 }};
111 }
112
113 macro_rules! sep_opt {
114 (@$l:expr, $it:expr, $($rest:tt)*) => {
115 {
116 let mut it = $it.into_iter().peekable();
117 if it.peek().is_some() {
118 sep!($l, it, $($rest)*)
119 } else {
120 nil!()
121 }
122 }
123 };
124 ($l:expr, $it:expr, $($rest:tt)*) => {
125 sep_opt!(@$l, $it, $($rest)*)
126 };
127 }
128
129 macro_rules! block {
130 ($body:expr) => {
131 docs![line!(), $body, line!()].group().nest(INDENT).braces()
132 };
133 }
134
135 impl<'a, 'b> RustPrinter {
136 fn generic_params<A: Clone>(&'a self, generic_params: &'b [GenericParam]) -> DocBuilder<A> {
137 let generic_params = generic_params
138 .iter()
139 .filter(|p| !matches!(&p.kind, GenericParamKind::Lifetime if p.ident.0.to_string() == "_"))
140 .collect::<Vec<_>>();
141 sep_opt!("<", generic_params, ">")
142 }
143 fn where_clause<A: Clone>(&'a self, constraints: &'b [GenericConstraint]) -> DocBuilder<A> {
144 if constraints.is_empty() {
145 return nil!();
146 }
147 docs![
148 line!(),
149 "where",
150 line!(),
151 intersperse!(constraints, docs![",", line!()])
152 .nest(INDENT)
153 .group(),
154 line!(),
155 ]
156 .nest(INDENT)
157 .group()
158 }
159 fn attributes<A: Clone>(&'a self, attrs: &'b [Attribute]) -> DocBuilder<A> {
160 concat!(
161 attrs
162 .iter()
163 .filter(|attr| match &attr.kind {
164 AttributeKind::Tool { .. } | AttributeKind::Hax(_) => false,
165 AttributeKind::DocComment { .. } => true,
166 })
167 .map(|attr| docs![attr, hardline!()])
168 )
169 }
170
171 fn id_name<A: Clone>(&'a self, id: GlobalId) -> DocBuilder<A> {
172 let view = id.view();
173 let path = <RustPrinter as RenderView>::render_strings(self, &view);
174 let name = path.last().unwrap().clone();
175 docs![if name == "_" {
176 "___empty_name".into()
177 } else {
178 name
179 }]
180 }
181 }
182
183 impl<A: Clone + 'static> PrettyAst<A> for RustPrinter {
184 const NAME: &'static str = "Rust";
185
186 fn module(&self, module: &Module) -> DocBuilder<A> {
187 let previous = self.current_namespace.borrow().clone();
188 let view = module.ident.view();
189 let module_path = <Self as RenderView>::module(self, &view);
190 *self.current_namespace.borrow_mut() = Some(module_path);
191 let doc = intersperse!(&module.items, docs![hardline!(), hardline!()]);
192 *self.current_namespace.borrow_mut() = previous;
193 doc
194 }
195
196 fn safety_kind(&self, safety_kind: &SafetyKind) -> DocBuilder<A> {
197 match safety_kind {
198 SafetyKind::Safe => nil!(),
199 SafetyKind::Unsafe => docs![text!("unsafe"), space!()],
200 }
201 }
202 fn param(&self, param: &Param) -> DocBuilder<A> {
203 docs![¶m.pat, ":", space!(), ¶m.ty]
204 }
205 fn binding_mode(&self, binding_mode: &BindingMode) -> DocBuilder<A> {
206 match binding_mode {
207 BindingMode::ByRef(BorrowKind::Mut) => docs!["ref mut", space!()],
208 BindingMode::ByRef(_) => docs!["ref", space!()],
209 _ => nil!(),
210 }
211 }
212 fn pat(&self, pat: &Pat) -> DocBuilder<A> {
213 match &*pat.kind {
214 PatKind::Wild => docs!["_"],
215 PatKind::Ascription { pat, ty } => docs![pat, ":", space!(), ty],
216 PatKind::Or { sub_pats } => {
217 intersperse!(sub_pats, docs![line!(), "|", line!()])
218 }
219 PatKind::Array { args } => sep!("[", args, "]", "|"),
220 PatKind::Deref { sub_pat } => docs!["&", sub_pat],
221 PatKind::Constant { lit } => docs![lit],
222 PatKind::Binding {
223 mutable,
224 var,
225 mode,
226 sub_pat,
227 } => {
228 docs![
229 if *mutable {
230 docs!["mut", space!()]
231 } else {
232 nil!()
233 },
234 mode,
235 var,
236 sub_pat.as_ref().map(|pat| docs!["@", docs![pat]]),
237 ]
238 }
239 PatKind::Construct { .. } => todo!("resugaring"),
240 PatKind::Resugared(resugared_pat_kind) => docs![resugared_pat_kind],
241 PatKind::Error(_) => todo!("resugaring"),
242 }
243 }
244 fn primitive_ty(&self, primitive_ty: &PrimitiveTy) -> DocBuilder<A> {
245 match primitive_ty {
246 PrimitiveTy::Bool => docs!["bool"],
247 PrimitiveTy::Int(int_kind) => docs![int_kind],
248 PrimitiveTy::Float(float_kind) => docs![float_kind],
249 PrimitiveTy::Char => docs!["char"],
250 PrimitiveTy::Str => docs!["str"],
251 }
252 }
253 fn int_kind(&self, int_kind: &IntKind) -> DocBuilder<A> {
254 docs![match (&int_kind.signedness, &int_kind.size) {
255 (Signedness::Signed, IntSize::S8) => "i8",
256 (Signedness::Signed, IntSize::S16) => "i16",
257 (Signedness::Signed, IntSize::S32) => "i32",
258 (Signedness::Signed, IntSize::S64) => "i64",
259 (Signedness::Signed, IntSize::S128) => "i128",
260 (Signedness::Signed, IntSize::SSize) => "isize",
261 (Signedness::Unsigned, IntSize::S8) => "u8",
262 (Signedness::Unsigned, IntSize::S16) => "u16",
263 (Signedness::Unsigned, IntSize::S32) => "u32",
264 (Signedness::Unsigned, IntSize::S64) => "u64",
265 (Signedness::Unsigned, IntSize::S128) => "u128",
266 (Signedness::Unsigned, IntSize::SSize) => "usize",
267 }]
268 }
269 fn generic_param(&self, generic_param: &GenericParam) -> DocBuilder<A> {
270 docs![
271 match &generic_param.kind {
272 GenericParamKind::Const { .. } => docs!["const", space!()],
273 _ => nil!(),
274 },
275 &generic_param.ident,
276 match &generic_param.kind {
277 GenericParamKind::Const { ty } => docs![":", space!(), ty],
278 _ => nil!(),
279 }
280 ]
281 }
282 fn generic_constraint(&self, generic_constraint: &GenericConstraint) -> DocBuilder<A> {
283 match generic_constraint {
284 GenericConstraint::Lifetime(s) => docs![s.clone()],
285 GenericConstraint::TypeClass(impl_ident) => docs![impl_ident],
286 GenericConstraint::Equality(projection_predicate) => docs![projection_predicate],
287 }
288 }
289 fn impl_ident(&self, impl_ident: &ImplIdent) -> DocBuilder<A> {
290 let trait_goal = &impl_ident.goal;
291 let [self_ty, args @ ..] = &trait_goal.args[..] else {
292 panic!()
293 };
294 docs![
295 self_ty,
296 space!(),
297 ":",
298 space!(),
299 &trait_goal.trait_,
300 sep_opt!("<", args, ">"),
301 ]
302 }
303
304 fn ty(&self, ty: &Ty) -> DocBuilder<A> {
305 match ty.kind() {
306 TyKind::Primitive(primitive_ty) => docs![primitive_ty],
307 TyKind::App { head, args } => docs![head, sep_opt!("<", args, ">")],
311 TyKind::Arrow { inputs, output } => {
312 docs!["fn", sep!("(", inputs, ")"), reflow!(" -> "), output]
313 }
314 TyKind::Ref {
315 inner,
316 mutable,
317 region: _,
318 } => docs![
319 "&",
320 if *mutable {
321 docs!["mut", space!()]
322 } else {
323 nil!()
324 },
325 inner
326 ],
327 TyKind::Param(local_id) => docs![local_id],
328 TyKind::Slice(ty) => docs![ty].brackets(),
329 TyKind::Array { ty, length } => {
330 docs![ty, ";", space!(), length.as_ref()].brackets()
331 }
332 TyKind::RawPointer => todo!(),
333 TyKind::AssociatedType { impl_, item } => docs![impl_, "::", item],
334 TyKind::Opaque(global_id) => docs![global_id],
335 TyKind::Dyn(dyn_trait_goals) => docs![
336 "dyn",
337 docs![
338 line!(),
339 intersperse!(dyn_trait_goals, docs![line!(), "+", space!()])
340 ]
341 .group()
342 .hang(0)
343 ],
344 TyKind::Resugared(resugared_ty_kind) => docs![resugared_ty_kind],
345 TyKind::Error(_) => todo!("resugaring"),
346 }
347 }
348 fn resugared_ty_kind(&self, resugared_ty_kind: &ResugaredTyKind) -> DocBuilder<A> {
349 match resugared_ty_kind {
350 ResugaredTyKind::Tuple(types) => print_tuple!(types),
351 }
352 }
353 fn literal(&self, literal: &Literal) -> DocBuilder<A> {
354 match literal {
355 Literal::String(symbol) => docs![symbol],
356 Literal::Char(ch) => text!(format!("{}", ch)),
357 Literal::Bool(b) => text!(format!("{}", b)),
358 Literal::Int {
359 value,
360 negative,
361 kind,
362 } => docs![if *negative { docs!["-"] } else { nil!() }, value, kind],
363 Literal::Float {
364 value,
365 negative,
366 kind,
367 } => docs![if *negative { docs!["-"] } else { nil!() }, value, kind],
368 }
369 }
370 fn trait_goal(&self, trait_goal: &TraitGoal) -> DocBuilder<A> {
371 let [self_ty, args @ ..] = &trait_goal.args[..] else {
372 panic!()
373 };
374 docs![
375 self_ty,
376 space!(),
377 "as",
378 space!(),
379 &trait_goal.trait_,
380 sep_opt!("<", args, ">"),
381 ]
382 .enclose("<", ">")
383 }
384 fn generic_value(&self, generic_value: &GenericValue) -> DocBuilder<A> {
385 match generic_value {
386 GenericValue::Ty(ty) => docs![ty],
387 GenericValue::Expr(expr) => docs![expr],
388 GenericValue::Lifetime => docs!["'_"],
389 }
390 }
391 fn arm(&self, arm: &Arm) -> DocBuilder<A> {
392 docs![
393 &arm.pat,
394 arm.guard.as_ref().map(|guard| docs!["if", space!(), guard]),
395 reflow!(" => "),
396 block![&arm.body],
397 ]
398 }
399 fn expr(&self, expr: &Expr) -> DocBuilder<A> {
400 match &*expr.kind {
401 ExprKind::If {
402 condition,
403 then,
404 else_,
405 } => docs![
406 "if",
407 space!(),
408 docs![condition].parens(),
409 space!(),
410 block![then],
411 else_
412 .as_ref()
413 .map(|doc| docs![reflow!(" else "), block![doc]])
414 .unwrap_or(nil!())
415 ],
416 ExprKind::App {
417 head,
418 args,
419 generic_args,
420 bounds_impls: _, trait_,
422 } => {
423 mod names {
424 pub use crate::names::rust_primitives::hax::{
425 cast_op, deref_op, logical_op_and, logical_op_or,
426 };
427 }
428 use ExprKind::GlobalId;
429 match (&*head.kind, &args[..]) {
430 (GlobalId(names::deref_op), [reference]) => {
431 Some(docs!["*", docs![reference].parens()])
432 }
433 (GlobalId(names::cast_op), [value]) => {
434 Some(docs![docs![value].parens(), reflow!(" as "), &expr.ty])
435 }
436 (GlobalId(names::logical_op_and), [lhs, rhs]) => Some(docs![
437 docs![lhs].parens(),
438 reflow!(" && "),
439 docs![rhs].parens()
440 ]),
441 (GlobalId(names::logical_op_or), [lhs, rhs]) => Some(docs![
442 docs![lhs].parens(),
443 reflow!(" || "),
444 docs![rhs].parens()
445 ]),
446 _ => None,
447 }
448 .unwrap_or_else(|| match (trait_, &*head.kind) {
449 (Some((trait_impl_expr, _trait_args)), GlobalId(head)) => {
450 docs![
451 &trait_impl_expr.goal,
452 "::",
453 self.id_name(*head),
454 sep_opt!("::<", generic_args, ">"),
455 sep!("(", args, ")")
456 ]
457 }
458 _ => docs![
459 head,
460 sep_opt!("::<", generic_args, ">"),
461 sep!("(", args, ")")
462 ],
463 })
464 }
465 ExprKind::Literal(literal) => docs![literal],
466 ExprKind::Array(exprs) => sep!("[", exprs, "]"),
467 ExprKind::Construct {
468 constructor,
469 is_record,
470 fields,
471 ..
473 } => {
474 let payload = fields.iter().map(|(id, value)| {
475 docs![
476 if *is_record {
477 docs![id, ":", space!()]
478 } else {
479 nil!()
480 },
481 value
482 ]
483 });
484 docs![
485 constructor,
486 if *is_record {
487 sep!("{", payload, "}")
488 } else {
489 sep!("(", payload, ")")
490 }
491 ]
492 }
493 ExprKind::Match { scrutinee, arms } => {
494 docs![
495 "match",
496 space!(),
497 scrutinee,
498 space!(),
499 block!(intersperse!(arms, hardline!())),
500 ]
501 }
502 ExprKind::Borrow { mutable, inner } => {
503 docs!["&", if *mutable { reflow!["mut "] } else { nil!() }, inner]
504 }
505 ExprKind::AddressOf { mutable, inner } => docs![
506 inner,
507 reflow!(" as *"),
508 if *mutable { reflow!["mut "] } else { nil!() },
509 docs![&expr.ty]
510 ]
511 .parens(),
512 ExprKind::Let { lhs, rhs, body } => docs![
513 "let",
514 space!(),
515 lhs,
516 space!(),
517 "=",
518 docs![line!(), rhs].group().nest(INDENT),
519 ";",
520 hardline!(),
521 body
522 ],
523 ExprKind::GlobalId(global_id) => docs![global_id],
524 ExprKind::LocalId(local_id) => docs![local_id],
525 ExprKind::Ascription { e, ty } => docs![e, ":", space!(), ty].parens(),
526 ExprKind::Assign { lhs, value } => docs![lhs, space!(), "=", space!(), value],
527 ExprKind::Loop {
528 body,
529 kind,
530 state: None,
531 control_flow: None,
532 label: None,
533 } => match &**kind {
534 LoopKind::UnconditionalLoop => docs!["loop", space!(), block![body]],
535 LoopKind::WhileLoop { condition } => {
536 docs!["while", space!(), condition, space!(), block![body]]
537 }
538 LoopKind::ForLoop { pat, iterator } => {
539 docs![
540 "for",
541 space!(),
542 pat,
543 reflow!(" in "),
544 iterator,
545 space!(),
546 block![body]
547 ]
548 }
549 LoopKind::ForIndexLoop {
550 start,
551 end,
552 var,
553 var_ty: _,
554 } => docs![
555 "for",
556 space!(),
557 var,
558 reflow!(" in "),
559 start,
560 "..",
561 end,
562 space!(),
563 block![body]
564 ],
565 },
566 ExprKind::Loop { .. } => {
567 todo!("loop with explicit state or with a label")
568 }
569 ExprKind::Break {
570 value, label: None, ..
571 } => docs!["break", space!(), value],
572 ExprKind::Break { .. } => todo!("break with a label"),
573 ExprKind::Return { value } => docs!["return", space!(), value],
574 ExprKind::Continue { label: None, .. } => docs!["continue"],
575 ExprKind::Continue { .. } => todo!("continue with a label"),
576 ExprKind::Closure {
577 params,
578 body,
579 captures: _,
580 } => docs![
581 intersperse!(params, docs![",", space!()]).enclose("|", "|"),
582 body
583 ],
584 ExprKind::Block { body, safety_mode } => {
585 docs![safety_mode, block![body]]
586 }
587 ExprKind::Quote { contents } => docs![contents],
588 ExprKind::Resugared(resugared_expr_kind) => docs![resugared_expr_kind],
589 ExprKind::Error { .. } => todo!("resugaring"),
590 }
591 }
592 fn resugared_expr_kind(&self, resugared_expr_kind: &ResugaredExprKind) -> DocBuilder<A> {
593 match resugared_expr_kind {
594 ResugaredExprKind::Tuple(values) => print_tuple!(values),
595 ResugaredExprKind::LetPure { .. } => unreachable!("LetPure resugaring not active"),
596 }
597 }
598
599 fn lhs(&self, lhs: &Lhs) -> DocBuilder<A> {
600 match lhs {
601 Lhs::LocalVar { var, ty: _ } => docs![var],
602 Lhs::VecRef { e, .. } => docs![e],
603 Lhs::ArbitraryExpr(expr) => docs![std::ops::Deref::deref(expr)],
604 Lhs::FieldAccessor { e, ty: _, field } => {
605 docs![std::ops::Deref::deref(e), ".", field]
606 }
607 Lhs::ArrayAccessor { e, ty: _, index } => {
608 docs![std::ops::Deref::deref(e), docs!(index).brackets()]
609 }
610 }
611 }
612 fn global_id(&self, global_id: &GlobalId) -> DocBuilder<A> {
613 let view = global_id.view();
614 let module = <Self as RenderView>::module(self, &view);
615 if Some(module) == *self.current_namespace.borrow() {
616 let rendered = self.render(&view);
617 docs![rendered.path.join("::")]
618 } else {
619 docs![self.render_string(&view)]
620 }
621 }
622 fn variant(&self, variant: &Variant) -> DocBuilder<A> {
623 let payload = variant.arguments.iter().map(|(id, ty, attrs)| {
624 docs![
625 self.attributes(attrs),
626 if variant.is_record {
627 docs![id, ":", space!()]
628 } else {
629 nil!()
630 },
631 ty
632 ]
633 });
634
635 if variant.is_record {
636 sep!("{", payload, "}")
637 } else {
638 sep!("(", payload, ")")
639 }
640 }
641 fn item(&self, item: &Item) -> DocBuilder<A> {
642 docs![&item.meta, item.kind()]
643 }
644 fn resugared_item_kind(&self, resugared_item_kind: &ResugaredItemKind) -> DocBuilder<A> {
645 match resugared_item_kind {
646 ResugaredItemKind::Constant { name, body, .. } => {
647 docs![
648 "const",
649 space!(),
650 self.id_name(*name),
651 ":",
652 space!(),
653 &body.ty,
654 reflow!(" = "),
655 docs![body].braces(),
656 ";"
657 ]
658 }
659 ResugaredItemKind::RecursiveFn { .. } => {
660 unreachable!("The Rust backend does not use the RecursiveFn resugaring")
661 }
662 }
663 }
664 fn item_kind(&self, item_kind: &ItemKind) -> DocBuilder<A> {
665 match item_kind {
666 ItemKind::Fn {
667 name,
668 generics,
669 body,
670 params,
671 safety,
672 } => {
673 docs![
674 safety,
675 text!("fn"),
676 space!(),
677 self.id_name(*name),
678 self.generic_params(&generics.params),
679 sep!("(", params, ")"),
680 reflow!(" -> "),
681 &body.ty,
682 space!(),
683 self.where_clause(&generics.constraints),
684 block![body]
685 ]
686 }
687 ItemKind::TyAlias {
688 name,
689 generics: _,
690 ty,
691 } => docs!["type", space!(), name, space!(), "=", space!(), ty, ";"],
692 ItemKind::Type {
693 name,
694 generics,
695 variants,
696 is_struct,
697 } => match &variants[..] {
698 [variant] if *is_struct => {
699 docs![
700 "struct",
701 space!(),
702 self.id_name(*name),
703 self.generic_params(&generics.params),
704 variant,
705 if variant.is_record {
706 nil!()
707 } else {
708 docs![";"]
709 }
710 ]
711 }
712 _ => {
713 docs![
714 "enum",
715 space!(),
716 self.id_name(*name),
717 self.generic_params(&generics.params),
718 sep!(
719 "{",
720 variants.iter().map(|variant| docs![
721 &variant.name,
722 space!(),
723 variant
724 ]),
725 "}",
726 ),
727 self.where_clause(&generics.constraints),
728 ]
729 }
730 },
731 ItemKind::Trait {
732 name,
733 generics,
734 items,
735 safety: _,
736 } => docs![
737 "trait",
738 space!(),
739 self.id_name(*name),
740 self.generic_params(&generics.params),
741 self.where_clause(&generics.constraints),
742 sep!("{", items, "}", nil!()),
743 ],
744 ItemKind::Impl {
745 generics,
746 self_ty,
747 of_trait: (trait_, trait_args),
748 items,
749 parent_bounds: _,
750 } => docs![
751 "impl",
752 self.generic_params(&generics.params),
753 space!(),
754 trait_,
755 sep_opt!("<", trait_args[1..], ">"),
756 space!(),
757 "for",
758 space!(),
759 self_ty,
760 self.where_clause(&generics.constraints),
761 sep!("{", items, "}", nil!()),
762 ],
763 ItemKind::Alias { name, item } => {
764 docs!["type", self.id_name(*name), reflow!(" = "), item, ";"]
765 }
766 ItemKind::RustModule | ItemKind::Use { .. } => nil!(),
767 ItemKind::Quote { quote, .. } => docs![quote],
768 ItemKind::Error { .. } => todo!("resugaring"),
769 ItemKind::Resugared(resugared_item_kind) => docs![resugared_item_kind],
770 ItemKind::NotImplementedYet => docs!["/* `NotImplementedYet` item */"],
771 }
772 }
773 fn impl_item(&self, impl_item: &ImplItem) -> DocBuilder<A> {
774 match &impl_item.kind {
775 ImplItemKind::Type {
776 ty,
777 parent_bounds: _,
778 } => docs![
779 &impl_item.meta,
780 reflow!("type "),
781 self.id_name(impl_item.ident),
782 reflow!(" = "),
783 ty,
784 ";"
785 ],
786 ImplItemKind::Fn { body, params } => docs![
787 &impl_item.meta,
788 text!("fn"),
789 space!(),
790 self.id_name(impl_item.ident),
791 self.generic_params(&impl_item.generics.params),
792 sep!("(", params, ")"),
793 reflow!(" -> "),
794 &body.ty,
795 space!(),
796 self.where_clause(&impl_item.generics.constraints),
797 docs![line_!(), body, line_!(),].nest(INDENT).braces()
798 ],
799 ImplItemKind::Resugared(_resugared_impl_item_kind) => todo!(),
800 ImplItemKind::Error(_) => todo!(),
801 }
802 }
803 fn metadata(&self, metadata: &Metadata) -> DocBuilder<A> {
804 self.attributes(&metadata.attributes)
805 }
806 fn attribute(&self, attribute: &Attribute) -> DocBuilder<A> {
807 match &attribute.kind {
808 AttributeKind::Tool { .. } | AttributeKind::Hax(_) => nil!(),
809 AttributeKind::DocComment { kind, body } => match kind {
810 DocCommentKind::Line => {
811 intersperse!(
812 body.lines().map(|line| docs![format!("/// {line}")]),
813 hardline!()
814 )
815 }
816 DocCommentKind::Block => {
817 docs![
818 "/**",
819 intersperse!(body.lines().map(|line| line.to_string()), hardline!()),
820 "*/"
821 ]
822 }
823 },
824 }
825 }
826 }
827};