From 96a6e0a346c8e70230376ce3a713c76c33d10d9c Mon Sep 17 00:00:00 2001 From: raskad <32105367+raskad@users.noreply.github.com> Date: Mon, 23 Jan 2023 07:27:11 +0000 Subject: [PATCH] Return the correct value from a statement list (#2554) When compiling a statement list we need to make sure that the last expression that returns a value is compiled with the `use_expr` flag. Currently we set `use_expr` on the last statement of the statement list. This leads to incorrect returns when the last statement does not return a value. This PR fixes this by looking up the last value returning expression in a statement list and setting the `use_expr` appropriately. --- boa_engine/src/bytecompiler/mod.rs | 58 +++++++++++++++++++----------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/boa_engine/src/bytecompiler/mod.rs b/boa_engine/src/bytecompiler/mod.rs index e797a1293e..3c68265c79 100644 --- a/boa_engine/src/bytecompiler/mod.rs +++ b/boa_engine/src/bytecompiler/mod.rs @@ -660,17 +660,26 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { use_expr: bool, configurable_globals: bool, ) -> JsResult<()> { - let mut items = list - .statements() - .iter() - .filter(|item| item != &&StatementListItem::Statement(Statement::Empty)) - .peekable(); - - while let Some(item) = items.next() { - if items.peek().is_some() { + if use_expr { + let expr_index = list + .statements() + .iter() + .rev() + .skip_while(|item| { + matches!( + item, + &&StatementListItem::Statement(Statement::Empty | Statement::Var(_)) + | &&StatementListItem::Declaration(_) + ) + }) + .count(); + + for (i, item) in list.statements().iter().enumerate() { + self.compile_stmt_list_item(item, i + 1 == expr_index, configurable_globals)?; + } + } else { + for item in list.statements() { self.compile_stmt_list_item(item, false, configurable_globals)?; - } else { - self.compile_stmt_list_item(item, use_expr, configurable_globals)?; } } @@ -689,17 +698,26 @@ impl<'b, 'host> ByteCompiler<'b, 'host> { self.create_decls(list, true); - let mut items = list - .statements() - .iter() - .filter(|item| item != &&StatementListItem::Statement(Statement::Empty)) - .peekable(); - - while let Some(item) = items.next() { - if items.peek().is_some() { + if use_expr { + let expr_index = list + .statements() + .iter() + .rev() + .skip_while(|item| { + matches!( + item, + &&StatementListItem::Statement(Statement::Empty | Statement::Var(_)) + | &&StatementListItem::Declaration(_) + ) + }) + .count(); + + for (i, item) in list.statements().iter().enumerate() { + self.compile_stmt_list_item(item, i + 1 == expr_index, true)?; + } + } else { + for item in list.statements() { self.compile_stmt_list_item(item, false, true)?; - } else { - self.compile_stmt_list_item(item, use_expr, true)?; } }