feat(ecmascript): fold typeof with ValueType information (#9086)

This commit is contained in:
sapphi-red committed 2025-02-13 13:58:55 +00:00
1 parent 2ab2a8f1a7
commit 6936b08cb2
2 files changed
+21 -30

No files matched your search

@@ -424,42 +424,31 @@ pub trait ConstantEvaluation<'a>: MayHaveSideEffects + DetermineValueType {
fn eval_unary_expression(&self, expr: &UnaryExpression<'a>) -> Option<ConstantValue<'a>> {
match expr.operator {
UnaryOperator::Typeof => {
let s = match &expr.argument {
Expression::ObjectExpression(_) | Expression::ArrayExpression(_) => {
if self.expression_may_have_side_effects(&expr.argument) {
return None;
if self.expression_may_have_side_effects(&expr.argument) {
return None;
}
let arg_ty = self.expression_value_type(&expr.argument);
let s = match arg_ty {
ValueType::BigInt => "bigint",
ValueType::Number => "number",
ValueType::String => "string",
ValueType::Boolean => "boolean",
ValueType::Undefined => "undefined",
ValueType::Null => "object",
_ => match &expr.argument {
Expression::ObjectExpression(_) | Expression::ArrayExpression(_) => {
"object"
}
"object"
}
Expression::ClassExpression(_) => {
if self.expression_may_have_side_effects(&expr.argument) {
return None;
}
"function"
}
Expression::FunctionExpression(_) | Expression::ArrowFunctionExpression(_) => {
"function"
}
Expression::StringLiteral(_) => "string",
Expression::NumericLiteral(_) => "number",
Expression::BooleanLiteral(_) => "boolean",
Expression::NullLiteral(_) => "object",
Expression::UnaryExpression(e) if e.operator == UnaryOperator::Void => {
"undefined"
}
Expression::BigIntLiteral(_) => "bigint",
Expression::Identifier(ident) => match ident.name.as_str() {
"undefined" if self.is_global_reference(ident) => "undefined",
"NaN" | "Infinity" if self.is_global_reference(ident) => "number",
Expression::ClassExpression(_)
| Expression::FunctionExpression(_)
| Expression::ArrowFunctionExpression(_) => "function",
_ => return None,
},
_ => return None,
};
Some(ConstantValue::String(Cow::Borrowed(s)))
}
UnaryOperator::Void => (expr.argument.is_literal()
|| !self.expression_may_have_side_effects(&expr.argument))
.then_some(ConstantValue::Undefined),
UnaryOperator::Void => (!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)
@@ -942,6 +942,7 @@ mod test {
#[test]
fn js_typeof() {
fold("x = typeof 1n", "x = \"bigint\"");
fold("x = typeof 1", "x = \"number\"");
fold("x = typeof 'foo'", "x = \"string\"");
fold("x = typeof true", "x = \"boolean\"");
@@ -953,6 +954,7 @@ mod test {
fold("x = typeof [1]", "x = \"object\"");
fold("x = typeof [1,[]]", "x = \"object\"");
fold("x = typeof {}", "x = \"object\"");
test("var a, b; NOOP(x = typeof (a === b))", "var a, b; NOOP(x = \"boolean\")");
test("var foo; NOOP(x = typeof { foo })", "var foo; NOOP(x = \"object\")");
fold("x = typeof function() {}", "x = 'function'");
fold("x = typeof (() => {})", "x = 'function'");