From e87063824c4db857ba60adfd0961e9f0a8f46d6e Mon Sep 17 00:00:00 2001 From: KtorZ Date: Thu, 16 May 2024 17:20:26 +0200 Subject: [PATCH] Fix pretty-printing of recursive type-alias causing stack overflow. Fixes #942. --- crates/aiken-lang/src/tipo/pretty.rs | 48 ++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/crates/aiken-lang/src/tipo/pretty.rs b/crates/aiken-lang/src/tipo/pretty.rs index 99313a2c..be27c767 100644 --- a/crates/aiken-lang/src/tipo/pretty.rs +++ b/crates/aiken-lang/src/tipo/pretty.rs @@ -54,7 +54,7 @@ impl Printer { }) = typ.alias().as_deref() { if let Some(resolved_parameters) = resolve_alias(parameters, annotation, typ) { - return self.type_alias_doc(alias.to_string(), resolved_parameters); + return self.type_alias_doc(typ, alias.to_string(), resolved_parameters); } } @@ -92,14 +92,27 @@ impl Printer { } } - fn type_alias_doc<'a>(&mut self, alias: String, parameters: Vec>) -> Document<'a> { + fn type_alias_doc<'a>( + &mut self, + typ: &Type, + alias: String, + parameters: Vec>, + ) -> Document<'a> { let doc = Document::String(alias); if !parameters.is_empty() { doc.append( break_("", "") .append(concat(Itertools::intersperse( - parameters.iter().map(|t| self.print(t)), + parameters.iter().map(|t| { + // Avoid infinite recursion for recursive types instantiated to + // themselves. For example: type Identity = t + if t.as_ref() == typ { + self.print(typ.clone().set_alias(None).as_ref()) + } else { + self.print(t) + } + }), break_(",", ", "), ))) .nest(INDENT) @@ -646,6 +659,35 @@ mod tests { }, "Fuzzer", ); + assert_string!( + Rc::new(Type::Fn { + args: vec![Rc::new(Type::App { + public: true, + contains_opaque: false, + module: "".to_string(), + name: "Bool".to_string(), + args: vec![], + alias: None, + })], + ret: Rc::new(Type::App { + public: true, + contains_opaque: false, + module: "".to_string(), + name: "Bool".to_string(), + args: vec![], + alias: None, + }), + alias: Some(Rc::new(TypeAliasAnnotation { + alias: "Identity".to_string(), + parameters: vec!["t".to_string()], + annotation: Annotation::Var { + location: Span::empty(), + name: "t".to_string(), + }, + })), + }), + "Identity Bool>", + ); } #[test]