feat(minifier): constant fold instanceof (#8142)

This commit is contained in:
翠 / green 2024-12-27 22:45:31 +09:00 committed by GitHub
parent 75264ed7d6
commit 6615e1ea93
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 62 additions and 1 deletions

View file

@ -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,
}
}

View file

@ -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