Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 21 additions & 19 deletions crates/oxc_ecmascript/src/constant_evaluation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub trait ConstantEvaluation<'a>: MayHaveSideEffects {
// and there are only a very few cases where we can compute a number value, but there could
// also be side effects. e.g. `void doSomething()` has value NaN, regardless of the behavior
// of `doSomething()`
if value.is_some() && self.expression_may_have_side_efffects(expr) {
if value.is_some() && self.expression_may_have_side_effects(expr) {
None
} else {
value
Expand All @@ -41,23 +41,23 @@ pub trait ConstantEvaluation<'a>: MayHaveSideEffects {

fn get_side_free_string_value(&self, expr: &Expression<'a>) -> Option<Cow<'a, str>> {
let value = expr.to_js_string();
if value.is_some() && !self.expression_may_have_side_efffects(expr) {
if value.is_some() && !self.expression_may_have_side_effects(expr) {
return value;
}
None
}

fn get_side_free_boolean_value(&self, expr: &Expression<'a>) -> Option<bool> {
let value = self.get_boolean_value(expr);
if value.is_some() && !self.expression_may_have_side_efffects(expr) {
if value.is_some() && !self.expression_may_have_side_effects(expr) {
return value;
}
None
}

fn get_side_free_bigint_value(&self, expr: &Expression<'a>) -> Option<BigInt> {
let value = expr.to_big_int();
if value.is_some() && self.expression_may_have_side_efffects(expr) {
if value.is_some() && self.expression_may_have_side_effects(expr) {
None
} else {
value
Expand Down Expand Up @@ -201,8 +201,8 @@ pub trait ConstantEvaluation<'a>: MayHaveSideEffects {
) -> Option<ConstantValue<'a>> {
match operator {
BinaryOperator::Addition => {
if self.expression_may_have_side_efffects(left)
|| self.expression_may_have_side_efffects(right)
if self.expression_may_have_side_effects(left)
|| self.expression_may_have_side_effects(right)
{
return None;
}
Expand Down Expand Up @@ -319,7 +319,7 @@ pub trait ConstantEvaluation<'a>: MayHaveSideEffects {
None
}
BinaryOperator::Instanceof => {
if self.expression_may_have_side_efffects(left) {
if self.expression_may_have_side_effects(left) {
return None;
}
if let Expression::Identifier(right_ident) = right {
Expand Down Expand Up @@ -379,34 +379,36 @@ pub trait ConstantEvaluation<'a>: MayHaveSideEffects {
Some(ConstantValue::String(Cow::Borrowed(s)))
}
UnaryOperator::Void => (expr.argument.is_literal()
|| !self.expression_may_have_side_efffects(&expr.argument))
|| !self.expression_may_have_side_effects(&expr.argument))
.then_some(ConstantValue::Undefined),
UnaryOperator::LogicalNot => self
.get_side_free_boolean_value(&expr.argument)
.map(|b| !b)
.map(ConstantValue::Boolean),
UnaryOperator::UnaryPlus => {
self.eval_to_number(&expr.argument).map(ConstantValue::Number)
self.get_side_free_number_value(&expr.argument).map(ConstantValue::Number)
}
UnaryOperator::UnaryNegation => match ValueType::from(&expr.argument) {
ValueType::BigInt => {
self.eval_to_big_int(&expr.argument).map(|v| -v).map(ConstantValue::BigInt)
}
ValueType::BigInt => self
.get_side_free_bigint_value(&expr.argument)
.map(|v| -v)
.map(ConstantValue::BigInt),
ValueType::Number => self
.eval_to_number(&expr.argument)
.get_side_free_number_value(&expr.argument)
.map(|v| if v.is_nan() { v } else { -v })
.map(ConstantValue::Number),
ValueType::Undefined => Some(ConstantValue::Number(f64::NAN)),
ValueType::Null => Some(ConstantValue::Number(-0.0)),
_ => None,
},
UnaryOperator::BitwiseNot => match ValueType::from(&expr.argument) {
ValueType::BigInt => {
self.eval_to_big_int(&expr.argument).map(|v| !v).map(ConstantValue::BigInt)
}
ValueType::BigInt => self
.get_side_free_bigint_value(&expr.argument)
.map(|v| !v)
.map(ConstantValue::BigInt),
#[expect(clippy::cast_lossless)]
_ => self
.eval_to_number(&expr.argument)
.get_side_free_number_value(&expr.argument)
.map(|v| (!v.to_int_32()) as f64)
.map(ConstantValue::Number),
},
Expand All @@ -423,7 +425,7 @@ pub trait ConstantEvaluation<'a>: MayHaveSideEffects {
if let Some(ConstantValue::String(s)) = self.eval_expression(&expr.object) {
Some(ConstantValue::Number(s.encode_utf16().count().to_f64().unwrap()))
} else {
if self.expression_may_have_side_efffects(&expr.object) {
if self.expression_may_have_side_effects(&expr.object) {
return None;
}
if let Expression::ArrayExpression(arr) = &expr.object {
Expand All @@ -446,7 +448,7 @@ pub trait ConstantEvaluation<'a>: MayHaveSideEffects {
if let Some(ConstantValue::String(s)) = self.eval_expression(&expr.object) {
Some(ConstantValue::Number(s.encode_utf16().count().to_f64().unwrap()))
} else {
if self.expression_may_have_side_efffects(&expr.object) {
if self.expression_may_have_side_effects(&expr.object) {
return None;
}
if let Expression::ArrayExpression(arr) = &expr.object {
Expand Down
30 changes: 15 additions & 15 deletions crates/oxc_ecmascript/src/side_effects/may_have_side_effects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use oxc_ast::ast::*;
pub trait MayHaveSideEffects {
fn is_global_reference(&self, ident: &IdentifierReference<'_>) -> bool;

fn expression_may_have_side_efffects(&self, e: &Expression<'_>) -> bool {
fn expression_may_have_side_effects(&self, e: &Expression<'_>) -> bool {
match e {
// Reference read can have a side effect.
Expression::Identifier(ident) => match ident.name.as_str() {
Expand All @@ -24,19 +24,19 @@ pub trait MayHaveSideEffects {
| Expression::ArrowFunctionExpression(_)
| Expression::FunctionExpression(_) => false,
Expression::TemplateLiteral(template) => {
template.expressions.iter().any(|e| self.expression_may_have_side_efffects(e))
template.expressions.iter().any(|e| self.expression_may_have_side_effects(e))
}
Expression::UnaryExpression(e) => self.unary_expression_may_have_side_effects(e),
Expression::ParenthesizedExpression(e) => {
self.expression_may_have_side_efffects(&e.expression)
self.expression_may_have_side_effects(&e.expression)
}
Expression::ConditionalExpression(e) => {
self.expression_may_have_side_efffects(&e.test)
|| self.expression_may_have_side_efffects(&e.consequent)
|| self.expression_may_have_side_efffects(&e.alternate)
self.expression_may_have_side_effects(&e.test)
|| self.expression_may_have_side_effects(&e.consequent)
|| self.expression_may_have_side_effects(&e.alternate)
}
Expression::SequenceExpression(e) => {
e.expressions.iter().any(|e| self.expression_may_have_side_efffects(e))
e.expressions.iter().any(|e| self.expression_may_have_side_effects(e))
}
Expression::BinaryExpression(e) => self.binary_expression_may_have_side_effects(e),
Expression::ObjectExpression(object_expr) => object_expr
Expand All @@ -57,7 +57,7 @@ pub trait MayHaveSideEffects {
operator != UnaryOperator::Delete
}
if is_simple_unary_operator(e.operator) {
return self.expression_may_have_side_efffects(&e.argument);
return self.expression_may_have_side_effects(&e.argument);
}
true
}
Expand All @@ -67,8 +67,8 @@ pub trait MayHaveSideEffects {
if matches!(e.operator, BinaryOperator::In | BinaryOperator::Instanceof) {
return true;
}
self.expression_may_have_side_efffects(&e.left)
|| self.expression_may_have_side_efffects(&e.right)
self.expression_may_have_side_effects(&e.left)
|| self.expression_may_have_side_effects(&e.right)
}

fn array_expression_element_may_have_side_effects(
Expand All @@ -77,10 +77,10 @@ pub trait MayHaveSideEffects {
) -> bool {
match e {
ArrayExpressionElement::SpreadElement(e) => {
self.expression_may_have_side_efffects(&e.argument)
self.expression_may_have_side_effects(&e.argument)
}
match_expression!(ArrayExpressionElement) => {
self.expression_may_have_side_efffects(e.to_expression())
self.expression_may_have_side_effects(e.to_expression())
}
ArrayExpressionElement::Elision(_) => false,
}
Expand All @@ -90,21 +90,21 @@ pub trait MayHaveSideEffects {
match e {
ObjectPropertyKind::ObjectProperty(o) => self.object_property_may_have_side_effects(o),
ObjectPropertyKind::SpreadProperty(e) => {
self.expression_may_have_side_efffects(&e.argument)
self.expression_may_have_side_effects(&e.argument)
}
}
}

fn object_property_may_have_side_effects(&self, e: &ObjectProperty<'_>) -> bool {
self.property_key_may_have_side_effects(&e.key)
|| self.expression_may_have_side_efffects(&e.value)
|| self.expression_may_have_side_effects(&e.value)
}

fn property_key_may_have_side_effects(&self, key: &PropertyKey<'_>) -> bool {
match key {
PropertyKey::StaticIdentifier(_) | PropertyKey::PrivateIdentifier(_) => false,
match_expression!(PropertyKey) => {
self.expression_may_have_side_efffects(key.to_expression())
self.expression_may_have_side_effects(key.to_expression())
}
}
}
Expand Down
14 changes: 9 additions & 5 deletions crates/oxc_minifier/src/peephole/fold_constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl<'a, 'b> PeepholeOptimizations {
// (FALSE && x) => FALSE
if if lval { op == LogicalOperator::Or } else { op == LogicalOperator::And } {
return Some(ctx.ast.move_expression(&mut logical_expr.left));
} else if !ctx.expression_may_have_side_efffects(left) {
} else if !ctx.expression_may_have_side_effects(left) {
let parent = ctx.ancestry.parent();
// Bail `let o = { f() { assert.ok(this !== o); } }; (true && o.f)(); (true && o.f)``;`
if parent.is_tagged_template_expression()
Expand All @@ -145,7 +145,7 @@ impl<'a, 'b> PeepholeOptimizations {
let left_child_right_boolean = ctx.get_boolean_value(&left_child.right);
let left_child_op = left_child.operator;
if let Some(right_boolean) = left_child_right_boolean {
if !ctx.expression_may_have_side_efffects(&left_child.right) {
if !ctx.expression_may_have_side_effects(&left_child.right) {
// a || false || b => a || b
// a && true && b => a && b
if !right_boolean && left_child_op == LogicalOperator::Or
Expand Down Expand Up @@ -178,7 +178,7 @@ impl<'a, 'b> PeepholeOptimizations {
let left_val = ValueType::from(left);
match left_val {
ValueType::Null | ValueType::Undefined => {
Some(if ctx.expression_may_have_side_efffects(left) {
Some(if ctx.expression_may_have_side_effects(left) {
// e.g. `(a(), null) ?? 1` => `(a(), null, 1)`
let expressions = ctx.ast.vec_from_array([
ctx.ast.move_expression(&mut logical_expr.left),
Expand Down Expand Up @@ -381,8 +381,7 @@ impl<'a, 'b> PeepholeOptimizations {
let left = &e.left;
let right = &e.right;
let op = e.operator;
if ctx.expression_may_have_side_efffects(left)
|| ctx.expression_may_have_side_efffects(right)
if ctx.expression_may_have_side_effects(left) || ctx.expression_may_have_side_effects(right)
{
return None;
}
Expand Down Expand Up @@ -1828,6 +1827,11 @@ mod test {
fold("typeof foo === 'number'", "typeof foo == 'number'");
}

#[test]
fn test_issue_8782() {
fold("+(void unknown())", "+void unknown()");
}

// TODO: All big ints are rare and difficult to handle.
mod bigint {
use super::{
Expand Down
8 changes: 4 additions & 4 deletions crates/oxc_minifier/src/peephole/remove_dead_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ impl<'a, 'b> PeepholeOptimizations {
| ValueType::Boolean
| ValueType::Number
| ValueType::String
) && !ctx.expression_may_have_side_efffects(arg)
) && !ctx.expression_may_have_side_effects(arg)
}
_ => false,
},
Expand Down Expand Up @@ -526,7 +526,7 @@ impl<'a, 'b> PeepholeOptimizations {

match ctx.get_boolean_value(&expr.test) {
Some(v) => {
if ctx.expression_may_have_side_efffects(&expr.test) {
if ctx.expression_may_have_side_effects(&expr.test) {
let mut exprs = ctx.ast.vec_with_capacity(2);
exprs.push(ctx.ast.move_expression(&mut expr.test));
exprs.push(ctx.ast.move_expression(if v {
Expand Down Expand Up @@ -564,7 +564,7 @@ impl<'a, 'b> PeepholeOptimizations {
(false, 0),
|(mut should_fold, mut new_len), (i, expr)| {
if i == sequence_expr.expressions.len() - 1
|| ctx.expression_may_have_side_efffects(expr)
|| ctx.expression_may_have_side_effects(expr)
{
new_len += 1;
} else {
Expand All @@ -582,7 +582,7 @@ impl<'a, 'b> PeepholeOptimizations {
let mut new_exprs = ctx.ast.vec_with_capacity(new_len);
let len = sequence_expr.expressions.len();
for (i, expr) in sequence_expr.expressions.iter_mut().enumerate() {
if i == len - 1 || ctx.expression_may_have_side_efffects(expr) {
if i == len - 1 || ctx.expression_may_have_side_effects(expr) {
new_exprs.push(ctx.ast.move_expression(expr));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ impl<'a> PeepholeOptimizations {
if !match argument {
Expression::Identifier(ident) => ctx.is_identifier_undefined(ident),
Expression::UnaryExpression(e) => {
e.operator.is_void() && !ctx.expression_may_have_side_efffects(argument)
e.operator.is_void() && !ctx.expression_may_have_side_effects(argument)
}
_ => false,
} {
Expand Down
Loading