From 7cc81ef5ef13d5cc84afc1fc719cbd373a217432 Mon Sep 17 00:00:00 2001 From: camc314 <18101008+camc314@users.noreply.github.com> Date: Thu, 16 Jan 2025 14:26:35 +0000 Subject: [PATCH] feat(minifier): fold invalid typeof comparisons (#8550) --- .../src/ast_passes/peephole_fold_constants.rs | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs b/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs index ad3faf8295aff..563dc002e60ab 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs @@ -607,12 +607,12 @@ impl<'a, 'b> PeepholeFoldConstants { )) } - // `typeof a === typeof b` -> `typeof a == typeof b`, `typeof a != typeof b` -> `typeof a != typeof b`, - // `typeof a == typeof a` -> `true`, `typeof a != typeof a` -> `false` fn try_fold_binary_typeof_comparison( bin_expr: &mut BinaryExpression<'a>, ctx: Ctx<'a, 'b>, ) -> Option> { + // `typeof a === typeof b` -> `typeof a == typeof b`, `typeof a != typeof b` -> `typeof a != typeof b`, + // `typeof a == typeof a` -> `true`, `typeof a != typeof a` -> `false` if bin_expr.operator.is_equality() { if let (Expression::UnaryExpression(left), Expression::UnaryExpression(right)) = (&bin_expr.left, &bin_expr.right) @@ -653,6 +653,41 @@ impl<'a, 'b> PeepholeFoldConstants { } } + // `typeof a === 'asd` -> `false`` + // `typeof a !== 'b'` -> `true`` + if let Expression::UnaryExpression(left) = &bin_expr.left { + if left.operator.is_typeof() && bin_expr.operator.is_equality() { + let right_ty = ValueType::from(&bin_expr.right); + + if !right_ty.is_undetermined() && right_ty != ValueType::String { + return Some(ctx.ast.expression_boolean_literal( + bin_expr.span, + bin_expr.operator == BinaryOperator::Inequality + || bin_expr.operator == BinaryOperator::StrictInequality, + )); + } + if let Expression::StringLiteral(string_lit) = &bin_expr.right { + if !matches!( + string_lit.value.as_str(), + "string" + | "number" + | "bigint" + | "boolean" + | "symbol" + | "undefined" + | "object" + | "function" + ) { + return Some(ctx.ast.expression_boolean_literal( + bin_expr.span, + bin_expr.operator == BinaryOperator::Inequality + || bin_expr.operator == BinaryOperator::StrictInequality, + )); + } + } + } + } + None } @@ -1736,6 +1771,20 @@ mod test { test("typeof foo.bar !== typeof foo.bar", "typeof foo.bar != typeof foo.bar"); } + #[test] + fn test_fold_invalid_typeof_comparison() { + test("typeof foo == 123", "false"); + test("typeof foo == '123'", "false"); + test("typeof foo === null", "false"); + test("typeof foo === undefined", "false"); + test("typeof foo !== 123", "true"); + test("typeof foo !== '123'", "true"); + test("typeof foo != null", "true"); + test("typeof foo != undefined", "true"); + test_same("typeof foo === 'string'"); + test_same("typeof foo === 'number'"); + } + // TODO: All big ints are rare and difficult to handle. mod bigint { use super::{