mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(minifier): constant fold undefined?.bar -> undefined (#8075)
This commit is contained in:
parent
d84d60a3a9
commit
5397fe978a
2 changed files with 46 additions and 5 deletions
|
|
@ -17,20 +17,28 @@ pub enum ValueType {
|
|||
}
|
||||
|
||||
impl ValueType {
|
||||
pub fn is_undefined(self) -> bool {
|
||||
self == Self::Undefined
|
||||
}
|
||||
|
||||
pub fn is_null(self) -> bool {
|
||||
self == Self::Null
|
||||
}
|
||||
|
||||
pub fn is_string(self) -> bool {
|
||||
matches!(self, Self::String)
|
||||
self == Self::String
|
||||
}
|
||||
|
||||
pub fn is_number(self) -> bool {
|
||||
matches!(self, Self::Number)
|
||||
self == Self::Number
|
||||
}
|
||||
|
||||
pub fn is_bigint(self) -> bool {
|
||||
matches!(self, Self::BigInt)
|
||||
self == Self::BigInt
|
||||
}
|
||||
|
||||
pub fn is_boolean(self) -> bool {
|
||||
matches!(self, Self::Boolean)
|
||||
self == Self::Boolean
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use oxc_ast::ast::*;
|
||||
use oxc_ecmascript::{
|
||||
constant_evaluation::{ConstantEvaluation, ValueType},
|
||||
constant_evaluation::{ConstantEvaluation, ConstantValue, ValueType},
|
||||
side_effects::MayHaveSideEffects,
|
||||
};
|
||||
use oxc_span::{GetSpan, SPAN};
|
||||
|
|
@ -53,6 +53,7 @@ impl<'a> Traverse<'a> for PeepholeFoldConstants {
|
|||
}
|
||||
// TODO: return tryFoldGetProp(subtree);
|
||||
Expression::LogicalExpression(e) => Self::try_fold_logical_expression(e, ctx),
|
||||
Expression::ChainExpression(e) => Self::try_fold_optional_chain(e, ctx),
|
||||
// TODO: tryFoldGetElem
|
||||
// TODO: tryFoldAssign
|
||||
_ => None,
|
||||
|
|
@ -106,6 +107,20 @@ impl<'a, 'b> PeepholeFoldConstants {
|
|||
}
|
||||
}
|
||||
|
||||
fn try_fold_optional_chain(
|
||||
chain_expr: &mut ChainExpression<'a>,
|
||||
ctx: Ctx<'a, 'b>,
|
||||
) -> Option<Expression<'a>> {
|
||||
let member_expr = chain_expr.expression.as_member_expression()?;
|
||||
if !member_expr.optional() {
|
||||
return None;
|
||||
}
|
||||
let object = member_expr.object();
|
||||
let ty = ValueType::from(object);
|
||||
(ty.is_null() || ty.is_undefined())
|
||||
.then(|| ctx.value_to_expr(chain_expr.span, ConstantValue::Undefined))
|
||||
}
|
||||
|
||||
/// Try to fold a AND / OR node.
|
||||
///
|
||||
/// port from [closure-compiler](https://github.com/google/closure-compiler/blob/09094b551915a6487a980a783831cba58b5739d1/src/com/google/javascript/jscomp/PeepholeFoldConstants.java#L587)
|
||||
|
|
@ -1149,6 +1164,24 @@ mod test {
|
|||
test_same("void x()");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fold_opt_chain() {
|
||||
// can't fold when optional part may execute
|
||||
test_same("a = x?.y");
|
||||
test_same("a = x?.()");
|
||||
|
||||
// fold args of optional call
|
||||
test("x = foo() ?. (true && bar())", "x = foo() ?.(bar())");
|
||||
test("a() ?. (1 ?? b())", "a() ?. (1)");
|
||||
|
||||
// test("({a})?.a.b.c.d()?.x.y.z", "a.b.c.d()?.x.y.z");
|
||||
|
||||
test("x = undefined?.y", "x = void 0");
|
||||
test("x = null?.y", "x = void 0");
|
||||
test("x = undefined?.[foo]", "x = void 0");
|
||||
test("x = null?.[foo]", "x = void 0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fold_bitwise_op() {
|
||||
test("x = 1 & 1", "x = 1");
|
||||
|
|
|
|||
Loading…
Reference in a new issue