mirror of
https://github.com/oxc-project/oxc.git
synced 2026-09-14 19:36:11 +08:00
feat(ecma): define math constants as known globals and resolve their types (#26585)
`Number.*` constants will now be treated as side effect free `typeof Math.*` and `typeof Number.*` will now resolve to `number` ref: https://github.com/rolldown/rolldown/issues/10852
This commit is contained in:
@@ -455,6 +455,9 @@ pub(super) fn is_known_global_property(global: &str, property: &str) -> bool {
|
||||
match global {
|
||||
"Math" => matches!(property, "E" | "LN10" | "LN2" | "LOG10E" | "LOG2E" | "PI" | "SQRT1_2" | "SQRT2")
|
||||
|| is_pure_math_method(property),
|
||||
"Number" => matches!(property,
|
||||
"POSITIVE_INFINITY" | "NEGATIVE_INFINITY" | "EPSILON" | "NaN"
|
||||
| "MAX_VALUE" | "MIN_VALUE" | "MAX_SAFE_INTEGER" | "MIN_SAFE_INTEGER"),
|
||||
"console" => matches!(property,
|
||||
"assert" | "clear" | "count" | "countReset" | "debug" | "dir" | "dirxml"
|
||||
| "error" | "group" | "groupCollapsed" | "groupEnd" | "info" | "log"
|
||||
|
||||
@@ -272,12 +272,24 @@ impl<'a> DetermineValueType<'a> for LogicalExpression<'a> {
|
||||
|
||||
impl<'a> DetermineValueType<'a> for StaticMemberExpression<'a> {
|
||||
fn value_type(&self, ctx: &impl GlobalContext<'a>) -> ValueType {
|
||||
if matches!(self.property.name.as_str(), "POSITIVE_INFINITY" | "NEGATIVE_INFINITY")
|
||||
&& ctx.is_global_expr("Number", &self.object)
|
||||
{
|
||||
return ValueType::Number;
|
||||
match self.property.name.as_str() {
|
||||
"POSITIVE_INFINITY" | "NEGATIVE_INFINITY" | "EPSILON" | "NaN" | "MAX_VALUE"
|
||||
| "MIN_VALUE" => {
|
||||
if ctx.is_global_expr("Number", &self.object) {
|
||||
ValueType::Number
|
||||
} else {
|
||||
ValueType::Undetermined
|
||||
}
|
||||
}
|
||||
"E" | "LN10" | "LN2" | "LOG10E" | "LOG2E" | "PI" | "SQRT1_2" | "SQRT2" => {
|
||||
if ctx.is_global_expr("Math", &self.object) {
|
||||
ValueType::Number
|
||||
} else {
|
||||
ValueType::Undetermined
|
||||
}
|
||||
}
|
||||
_ => ValueType::Undetermined,
|
||||
}
|
||||
ValueType::Undetermined
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -915,11 +915,28 @@ fn test_known_global_property_reads() {
|
||||
// Math properties
|
||||
test("Math.PI", false);
|
||||
test("Math.E", false);
|
||||
test("Math.LN10", false);
|
||||
test("Math.LN2", false);
|
||||
test("Math.LOG10E", false);
|
||||
test("Math.LOG2E", false);
|
||||
test("Math.SQRT1_2", false);
|
||||
test("Math.SQRT2", false);
|
||||
test("Math.abs", false);
|
||||
test("Math.floor", false);
|
||||
test("Math.random", false);
|
||||
test("Math.unknownProp", true);
|
||||
|
||||
// Number properties
|
||||
test("Number.POSITIVE_INFINITY", false);
|
||||
test("Number.NEGATIVE_INFINITY", false);
|
||||
test("Number.EPSILON", false);
|
||||
test("Number.NaN", false);
|
||||
test("Number.MAX_VALUE", false);
|
||||
test("Number.MIN_VALUE", false);
|
||||
test("Number.MAX_SAFE_INTEGER", false);
|
||||
test("Number.MIN_SAFE_INTEGER", false);
|
||||
test("Number.UNKNOWN", true);
|
||||
|
||||
// Object properties
|
||||
test("Object.keys", false);
|
||||
test("Object.create", false);
|
||||
|
||||
@@ -448,6 +448,28 @@ fn js_typeof() {
|
||||
fold_same("x = typeof[1,[foo()]]");
|
||||
fold_same("x = typeof{bathwater:baby()}");
|
||||
fold_same("x = typeof class { static { foo() } }");
|
||||
|
||||
fold("typeof NaN", "'number'");
|
||||
fold("typeof Infinity", "'number'");
|
||||
fold("typeof Math.E", "'number'");
|
||||
fold("typeof Math.LN10", "'number'");
|
||||
fold("typeof Math.LN2", "'number'");
|
||||
fold("typeof Math.LOG10E", "'number'");
|
||||
fold("typeof Math.LOG2E", "'number'");
|
||||
fold("typeof Math.PI", "'number'");
|
||||
fold("typeof Math.SQRT1_2", "'number'");
|
||||
fold("typeof Math.SQRT2", "'number'");
|
||||
fold_same("typeof Math.missing");
|
||||
|
||||
fold("typeof Number.POSITIVE_INFINITY", "'number'");
|
||||
fold("typeof Number.NEGATIVE_INFINITY", "'number'");
|
||||
fold("typeof Number.EPSILON", "'number'");
|
||||
fold("typeof Number.NaN", "'number'");
|
||||
fold("typeof Number.MAX_VALUE", "'number'");
|
||||
fold("typeof Number.MIN_VALUE", "'number'");
|
||||
fold("typeof Number.MAX_SAFE_INTEGER", "'number'");
|
||||
fold("typeof Number.MIN_SAFE_INTEGER", "'number'");
|
||||
fold_same("typeof Number.UNKNOWN");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -130,8 +130,8 @@ fn test_mathematical_expression_edge_cases() {
|
||||
test("Infinity + 1", ""); // eliminated as unused expression
|
||||
test("Infinity - Infinity", ""); // eliminated as unused expression
|
||||
test("Infinity / Infinity", ""); // eliminated as unused expression
|
||||
test_same("Math.PI * 2"); // runtime value
|
||||
test_same("Math.E + 1"); // runtime value
|
||||
test("Math.PI * 2", ""); // eliminated as unused expression
|
||||
test("Math.E + 1", ""); // eliminated as unused expression
|
||||
test("-0 + 0", ""); // eliminated as unused expression
|
||||
test("-0 * 1", ""); // eliminated as unused expression
|
||||
test("1 / -0", ""); // eliminated as unused expression
|
||||
|
||||
Reference in New Issue
Block a user