mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(minifier): fold string.length / array.length (#8172)
This commit is contained in:
parent
29dc0dc070
commit
fc43ec530e
3 changed files with 67 additions and 4 deletions
|
|
@ -1,7 +1,7 @@
|
|||
use std::{borrow::Cow, cmp::Ordering};
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use num_traits::Zero;
|
||||
use num_traits::{ToPrimitive, Zero};
|
||||
|
||||
use oxc_ast::ast::*;
|
||||
|
||||
|
|
@ -193,6 +193,7 @@ pub trait ConstantEvaluation<'a> {
|
|||
Expression::StringLiteral(lit) => {
|
||||
Some(ConstantValue::String(Cow::Borrowed(lit.value.as_str())))
|
||||
}
|
||||
Expression::StaticMemberExpression(e) => self.eval_static_member_expression(e),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
@ -458,6 +459,31 @@ pub trait ConstantEvaluation<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn eval_static_member_expression(
|
||||
&self,
|
||||
expr: &StaticMemberExpression<'a>,
|
||||
) -> Option<ConstantValue<'a>> {
|
||||
match expr.property.name.as_str() {
|
||||
"length" => {
|
||||
if let Some(ConstantValue::String(s)) = self.eval_expression(&expr.object) {
|
||||
// TODO(perf): no need to actually convert, only need the length
|
||||
Some(ConstantValue::Number(s.encode_utf16().count().to_f64().unwrap()))
|
||||
} else {
|
||||
if expr.object.may_have_side_effects() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Expression::ArrayExpression(arr) = &expr.object {
|
||||
Some(ConstantValue::Number(arr.elements.len().to_f64().unwrap()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// <https://tc39.es/ecma262/#sec-abstract-relational-comparison>
|
||||
fn is_less_than(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ impl<'a> Traverse<'a> for PeepholeFoldConstants {
|
|||
_ => ctx.eval_unary_expression(e).map(|v| ctx.value_to_expr(e.span, v)),
|
||||
}
|
||||
}
|
||||
// TODO: return tryFoldGetProp(subtree);
|
||||
Expression::StaticMemberExpression(e) => {
|
||||
Self::try_fold_static_member_expression(e, ctx)
|
||||
}
|
||||
Expression::LogicalExpression(e) => Self::try_fold_logical_expression(e, ctx),
|
||||
Expression::ChainExpression(e) => Self::try_fold_optional_chain(e, ctx),
|
||||
// TODO: tryFoldGetElem
|
||||
|
|
@ -97,6 +99,16 @@ impl<'a, 'b> PeepholeFoldConstants {
|
|||
None
|
||||
}
|
||||
|
||||
fn try_fold_static_member_expression(
|
||||
static_member_expr: &mut StaticMemberExpression<'a>,
|
||||
ctx: Ctx<'a, 'b>,
|
||||
) -> Option<Expression<'a>> {
|
||||
// TODO: tryFoldObjectPropAccess(n, left, name)
|
||||
|
||||
ctx.eval_static_member_expression(static_member_expr)
|
||||
.map(|value| ctx.value_to_expr(static_member_expr.span, value))
|
||||
}
|
||||
|
||||
fn try_fold_logical_expression(
|
||||
logical_expr: &mut LogicalExpression<'a>,
|
||||
ctx: Ctx<'a, 'b>,
|
||||
|
|
@ -1504,6 +1516,31 @@ mod test {
|
|||
test("(+x & 1) & 2", "+x & 0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fold_array_length() {
|
||||
// Can fold
|
||||
test("x = [].length", "x = 0");
|
||||
test("x = [1,2,3].length", "x = 3");
|
||||
// test("x = [a,b].length", "x = 2");
|
||||
|
||||
// Not handled yet
|
||||
test("x = [,,1].length", "x = 3");
|
||||
|
||||
// Cannot fold
|
||||
test("x = [foo(), 0].length", "x = [foo(),0].length");
|
||||
test_same("x = y.length");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fold_string_length() {
|
||||
// Can fold basic strings.
|
||||
test("x = ''.length", "x = 0");
|
||||
test("x = '123'.length", "x = 3");
|
||||
|
||||
// Test Unicode escapes are accounted for.
|
||||
test("x = '123\\u01dc'.length", "x = 4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fold_instance_of() {
|
||||
// Non object types are never instances of anything.
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ Original | minified | minified | gzip | gzip | Fixture
|
|||
|
||||
555.77 kB | 274.10 kB | 270.13 kB | 91.25 kB | 90.80 kB | d3.js
|
||||
|
||||
1.01 MB | 461.06 kB | 458.89 kB | 126.91 kB | 126.71 kB | bundle.min.js
|
||||
1.01 MB | 461.05 kB | 458.89 kB | 126.89 kB | 126.71 kB | bundle.min.js
|
||||
|
||||
1.25 MB | 656.99 kB | 646.76 kB | 164.18 kB | 163.73 kB | three.js
|
||||
|
||||
|
|
@ -23,5 +23,5 @@ Original | minified | minified | gzip | gzip | Fixture
|
|||
|
||||
6.69 MB | 2.34 MB | 2.31 MB | 493.51 kB | 488.28 kB | antd.js
|
||||
|
||||
10.95 MB | 3.51 MB | 3.49 MB | 910.88 kB | 915.50 kB | typescript.js
|
||||
10.95 MB | 3.51 MB | 3.49 MB | 910.84 kB | 915.50 kB | typescript.js
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue