diff --git a/compiler/gen/tests/gen_list.rs b/compiler/gen/tests/gen_list.rs index 39cc706a77..71f9895f54 100644 --- a/compiler/gen/tests/gen_list.rs +++ b/compiler/gen/tests/gen_list.rs @@ -307,10 +307,16 @@ mod gen_list { assert_concat_worked(2, 3); assert_concat_worked(3, 3); assert_concat_worked(4, 4); - // TODO TCE seems to be broken for large concats - // assert_concat_worked(150, 150); - // assert_concat_worked(129, 350); - // assert_concat_worked(350, 129); + } + + #[test] + fn list_concat_large() { + // these values produce mono ASTs so large that + // it can cause a stack overflow. This has been solved + // for current code, but may become a problem again in the future. + assert_concat_worked(150, 150); + assert_concat_worked(129, 350); + assert_concat_worked(350, 129); } #[test] diff --git a/compiler/mono/src/inc_dec.rs b/compiler/mono/src/inc_dec.rs index b5f7dd3e17..9e90e80b7c 100644 --- a/compiler/mono/src/inc_dec.rs +++ b/compiler/mono/src/inc_dec.rs @@ -568,9 +568,43 @@ impl<'a> Context<'a> { } // TODO should not be pub - pub fn visit_stmt(&self, stmt: &'a Stmt<'a>) -> (&'a Stmt<'a>, LiveVarSet) { + fn visit_stmt(&self, stmt: &'a Stmt<'a>) -> (&'a Stmt<'a>, LiveVarSet) { use Stmt::*; + // let-chains can be very long, especially for large (list) literals + // in (rust) debug mode, this function can overflow the stack for such values + // so we have to write an explicit loop. + { + let mut cont = stmt; + let mut triples = Vec::new_in(self.arena); + while let Stmt::Let(symbol, expr, layout, new_cont) = cont { + triples.push((symbol, expr, layout)); + cont = new_cont; + } + + if !triples.is_empty() { + let mut ctx = self.clone(); + for (symbol, expr, layout) in triples.iter() { + ctx = ctx.update_var_info(**symbol, layout, expr); + } + let (mut b, mut b_live_vars) = ctx.visit_stmt(cont); + for (symbol, expr, layout) in triples.into_iter().rev() { + let pair = ctx.visit_variable_declaration( + *symbol, + (*expr).clone(), + (*layout).clone(), + b, + &b_live_vars, + ); + + b = pair.0; + b_live_vars = pair.1; + } + + return (b, b_live_vars); + } + } + match stmt { Let(symbol, expr, layout, cont) => { let ctx = self.update_var_info(*symbol, layout, expr);