diff --git a/crates/oxc_ecmascript/src/constant_evaluation/mod.rs b/crates/oxc_ecmascript/src/constant_evaluation/mod.rs index a368262908466..ab47066c7de25 100644 --- a/crates/oxc_ecmascript/src/constant_evaluation/mod.rs +++ b/crates/oxc_ecmascript/src/constant_evaluation/mod.rs @@ -347,6 +347,27 @@ pub trait ConstantEvaluation<'a> { } None } + BinaryOperator::Instanceof => { + if left.may_have_side_effects() { + return None; + } + + let left_ty = ValueType::from(left); + if left_ty == ValueType::Undetermined { + return None; + } + if left_ty == ValueType::Object { + if let Some(right_ident) = right.get_identifier_reference() { + if right_ident.name == "Object" && self.is_global_reference(right_ident) { + return Some(ConstantValue::Boolean(true)); + } + } + None + } else { + // Non-object types are never instances. + Some(ConstantValue::Boolean(false)) + } + } _ => None, } } 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 dbff2b5eb207b..3e915b39e0802 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_fold_constants.rs @@ -245,7 +245,8 @@ impl<'a, 'b> PeepholeFoldConstants { | BinaryOperator::Division | BinaryOperator::Remainder | BinaryOperator::Multiplication - | BinaryOperator::Exponential => { + | BinaryOperator::Exponential + | BinaryOperator::Instanceof => { ctx.eval_binary_expression(e).map(|v| ctx.value_to_expr(e.span, v)) } BinaryOperator::Addition => Self::try_fold_add(e, ctx), @@ -1503,6 +1504,45 @@ mod test { test("(+x & 1) & 2", "+x & 0"); } + #[test] + fn test_fold_instance_of() { + // Non object types are never instances of anything. + test("64 instanceof Object", "false"); + test("64 instanceof Number", "false"); + test("'' instanceof Object", "false"); + test("'' instanceof String", "false"); + test("true instanceof Object", "false"); + test("true instanceof Boolean", "false"); + test("!0 instanceof Object", "false"); + test("!0 instanceof Boolean", "false"); + test("false instanceof Object", "false"); + test("null instanceof Object", "false"); + test("undefined instanceof Object", "false"); + test("NaN instanceof Object", "false"); + test("Infinity instanceof Object", "false"); + + // Array and object literals are known to be objects. + test("[] instanceof Object", "true"); + test("({}) instanceof Object", "true"); + + // These cases is foldable, but no handled currently. + test_same("new Foo() instanceof Object"); + // These would require type information to fold. + test_same("[] instanceof Foo"); + test_same("({}) instanceof Foo"); + + test("(function() {}) instanceof Object", "true"); + + // An unknown value should never be folded. + test_same("x instanceof Foo"); + } + + #[test] + fn test_fold_instance_of_additional() { + test("(typeof {}) instanceof Object", "false"); + test("(+{}) instanceof Number", "false"); + } + #[test] fn test_fold_left_child_op() { test_same("x & infinity & 2"); // FIXME: want x & 0