From cbcdaa60d29825af1444591d5700edb72af13fd7 Mon Sep 17 00:00:00 2001 From: Tibor Djurica Potpara Date: Sun, 29 Sep 2024 11:32:28 +0100 Subject: [PATCH] fix: Fix the order of evaluation when unpacking tuples --- src/alumina-boot/src/ir/mono/mod.rs | 35 ++++++++++++++++++----------- tests/lang/lang.alu | 20 +++++++++++++++++ 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/alumina-boot/src/ir/mono/mod.rs b/src/alumina-boot/src/ir/mono/mod.rs index 92eadc2a..b798c971 100644 --- a/src/alumina-boot/src/ir/mono/mod.rs +++ b/src/alumina-boot/src/ir/mono/mod.rs @@ -4284,6 +4284,7 @@ impl<'a, 'ast, 'ir> Mono<'a, 'ast, 'ir> { let mut lowered = Vec::with_capacity(exprs.len()); for expr in exprs { + let _guard = self.diag.push_span(expr.span); match expr.kind { ast::ExprKind::EtCetera(inner) => { // type hint is None since we do not know the length beforehand. If @@ -4331,22 +4332,30 @@ impl<'a, 'ast, 'ir> Mono<'a, 'ast, 'ir> { let element_types: Vec<_> = lowered.iter().map(|e| e.ty).collect(); let tuple_type = self.types.tuple(element_types); - let ret = self + // Unpacking produced an empty tuple, but there may have been side effects + // in the process, so we need to wrap the tuple in a block. This is slightly + // involved because we care about evaluating the expressions in order. + let ret = if stmts.is_empty() { + self .exprs .tuple(lowered.into_iter().enumerate(), tuple_type, ast_span) - .alloc_on(self.ctx.ir); - - if !stmts.is_empty() { - // Unpacking produced an empty tuple, but there may have been side effects - // in the process, so we need to wrap the tuple in a block - - let (tuple, assign) = self.ensure_local(ret); - stmts.extend(assign); - - Ok(self.exprs.block(stmts, tuple, ast_span)) + .alloc_on(self.ctx.ir) + } else if let Some(last) = lowered.last_mut() { + // Attach the remaining statements after the last tuple element + let (expr, stmt) = self.ensure_local(last); + stmts.extend(stmt); + + *last = self.exprs.block(stmts, expr, ast_span); + self + .exprs + .tuple(lowered.into_iter().enumerate(), tuple_type, ast_span) + .alloc_on(self.ctx.ir) } else { - Ok(ret) - } + let ret = self.exprs.void(tuple_type, ir::ValueType::RValue, ast_span); + self.exprs.block(stmts, ret, ast_span) + }; + + Ok(ret) } fn lower_cast( diff --git a/tests/lang/lang.alu b/tests/lang/lang.alu index ded5a111..ba4ea24f 100644 --- a/tests/lang/lang.alu +++ b/tests/lang/lang.alu @@ -927,4 +927,24 @@ fn test_tuple_slicing_types() { #[test] fn test_tuple_unpack() { assert_eq!((1, (2, 3)..., 4, 5), (1, 2, 3, 4, 5)); + assert_eq!((()...,), ()); + + // Test side effects & order of evaluation + let counter = 0; + + let a = (1, { + assert_eq!(counter, 0); + counter += 1; + (2, 3) + }..., { + assert_eq!(counter, 1); + counter += 1; + (4, 5) + }..., { + assert_eq!(counter, 2); + counter += 1; + () + }...); + + assert_eq!(a, (1, 2, 3, 4, 5)); }