mirror of
https://github.com/danbulant/oxc
synced 2026-05-21 21:29:01 +00:00
feat(minifier): complete implementation of statement fusion (#6566)
- enables all test in statement fusion - implements some more node in `may_have_side_effects`
This commit is contained in:
parent
c67acfaae7
commit
ef237cf8ff
3 changed files with 178 additions and 4 deletions
|
|
@ -3,7 +3,7 @@ use oxc_ast::ast::*;
|
||||||
use oxc_span::SPAN;
|
use oxc_span::SPAN;
|
||||||
use oxc_traverse::{Traverse, TraverseCtx};
|
use oxc_traverse::{Traverse, TraverseCtx};
|
||||||
|
|
||||||
use crate::CompressorPass;
|
use crate::{node_util::MayHaveSideEffects, CompressorPass};
|
||||||
|
|
||||||
/// Statement Fusion
|
/// Statement Fusion
|
||||||
///
|
///
|
||||||
|
|
@ -73,8 +73,7 @@ impl<'a> StatementFusion {
|
||||||
for_stmt.init.is_none()
|
for_stmt.init.is_none()
|
||||||
|| for_stmt.init.as_ref().is_some_and(ForStatementInit::is_expression)
|
|| for_stmt.init.as_ref().is_some_and(ForStatementInit::is_expression)
|
||||||
}
|
}
|
||||||
// TODO: support for-in, we need to check the init for side effects
|
Statement::ForInStatement(for_in_stmt) => !for_in_stmt.left.may_have_side_effects(),
|
||||||
Statement::ForInStatement(_for_in_stmt) => false,
|
|
||||||
Statement::LabeledStatement(labeled_stmt) => {
|
Statement::LabeledStatement(labeled_stmt) => {
|
||||||
Self::is_fusable_control_statement(&labeled_stmt.body)
|
Self::is_fusable_control_statement(&labeled_stmt.body)
|
||||||
}
|
}
|
||||||
|
|
@ -144,6 +143,7 @@ impl<'a> StatementFusion {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Statement::ForInStatement(for_stmt) => &mut for_stmt.right,
|
||||||
Statement::LabeledStatement(labeled_stmt) => {
|
Statement::LabeledStatement(labeled_stmt) => {
|
||||||
Self::fuse_expression_into_control_flow_statement(
|
Self::fuse_expression_into_control_flow_statement(
|
||||||
&mut labeled_stmt.body,
|
&mut labeled_stmt.body,
|
||||||
|
|
@ -261,7 +261,6 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
|
||||||
fn fuse_into_for_in1() {
|
fn fuse_into_for_in1() {
|
||||||
fuse("a;b;c;for(x in y){}", "for(x in a,b,c,y){}");
|
fuse("a;b;c;for(x in y){}", "for(x in a,b,c,y){}");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -145,3 +145,177 @@ impl<'a, 'b> CheckForStateChange<'a, 'b> for PropertyKey<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> CheckForStateChange<'a, 'b> for ForStatementLeft<'a> {
|
||||||
|
fn check_for_state_change(&self, check_for_new_objects: bool) -> bool {
|
||||||
|
match self {
|
||||||
|
match_assignment_target!(Self) => {
|
||||||
|
self.to_assignment_target().check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
ForStatementLeft::VariableDeclaration(variable_declaration) => {
|
||||||
|
variable_declaration.check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> CheckForStateChange<'a, 'b> for VariableDeclaration<'a> {
|
||||||
|
fn check_for_state_change(&self, check_for_new_objects: bool) -> bool {
|
||||||
|
self.declarations.iter().any(|decl| decl.check_for_state_change(check_for_new_objects))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> CheckForStateChange<'a, 'b> for VariableDeclarator<'a> {
|
||||||
|
fn check_for_state_change(&self, check_for_new_objects: bool) -> bool {
|
||||||
|
self.id.check_for_state_change(check_for_new_objects)
|
||||||
|
|| self
|
||||||
|
.init
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |init| init.check_for_state_change(check_for_new_objects))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CheckForStateChange<'_, '_> for BindingPattern<'_> {
|
||||||
|
fn check_for_state_change(&self, check_for_new_objects: bool) -> bool {
|
||||||
|
match &self.kind {
|
||||||
|
BindingPatternKind::BindingIdentifier(_) => false,
|
||||||
|
BindingPatternKind::ObjectPattern(object_pattern) => {
|
||||||
|
object_pattern
|
||||||
|
.properties
|
||||||
|
.iter()
|
||||||
|
.any(|element| element.check_for_state_change(check_for_new_objects))
|
||||||
|
|| object_pattern
|
||||||
|
.rest
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|rest| rest.check_for_state_change(check_for_new_objects))
|
||||||
|
}
|
||||||
|
BindingPatternKind::ArrayPattern(array_pattern) => {
|
||||||
|
array_pattern.elements.iter().any(|element| {
|
||||||
|
element.as_ref().is_some_and(|element| {
|
||||||
|
element.check_for_state_change(check_for_new_objects)
|
||||||
|
})
|
||||||
|
}) || array_pattern
|
||||||
|
.rest
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|rest| rest.check_for_state_change(check_for_new_objects))
|
||||||
|
}
|
||||||
|
BindingPatternKind::AssignmentPattern(assignment_pattern) => {
|
||||||
|
assignment_pattern.left.check_for_state_change(check_for_new_objects)
|
||||||
|
&& assignment_pattern.right.check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CheckForStateChange<'_, '_> for BindingRestElement<'_> {
|
||||||
|
fn check_for_state_change(&self, check_for_new_objects: bool) -> bool {
|
||||||
|
self.argument.check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CheckForStateChange<'_, '_> for BindingProperty<'_> {
|
||||||
|
fn check_for_state_change(&self, check_for_new_objects: bool) -> bool {
|
||||||
|
self.key.check_for_state_change(check_for_new_objects)
|
||||||
|
|| self.value.check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CheckForStateChange<'_, '_> for AssignmentTarget<'_> {
|
||||||
|
fn check_for_state_change(&self, check_for_new_objects: bool) -> bool {
|
||||||
|
match self {
|
||||||
|
AssignmentTarget::AssignmentTargetIdentifier(_) => false,
|
||||||
|
AssignmentTarget::TSAsExpression(ts_as_expression) => {
|
||||||
|
ts_as_expression.expression.check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
AssignmentTarget::TSSatisfiesExpression(ts_satisfies_expression) => {
|
||||||
|
ts_satisfies_expression.expression.check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
AssignmentTarget::TSNonNullExpression(ts_non_null_expression) => {
|
||||||
|
ts_non_null_expression.expression.check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
AssignmentTarget::TSTypeAssertion(ts_type_assertion) => {
|
||||||
|
ts_type_assertion.expression.check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
AssignmentTarget::TSInstantiationExpression(ts_instantiation_expression) => {
|
||||||
|
ts_instantiation_expression.expression.check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
AssignmentTarget::ComputedMemberExpression(computed_member_expression) => {
|
||||||
|
computed_member_expression.object.check_for_state_change(check_for_new_objects)
|
||||||
|
|| computed_member_expression
|
||||||
|
.expression
|
||||||
|
.check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
AssignmentTarget::StaticMemberExpression(static_member_expression) => {
|
||||||
|
static_member_expression.object.check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
AssignmentTarget::PrivateFieldExpression(private_field_expression) => {
|
||||||
|
private_field_expression.object.check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
AssignmentTarget::ArrayAssignmentTarget(array_assignment_target) => {
|
||||||
|
array_assignment_target.elements.iter().any(|element| {
|
||||||
|
element.as_ref().is_some_and(|element| {
|
||||||
|
element.check_for_state_change(check_for_new_objects)
|
||||||
|
})
|
||||||
|
}) || array_assignment_target
|
||||||
|
.rest
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|rest| rest.check_for_state_change(check_for_new_objects))
|
||||||
|
}
|
||||||
|
AssignmentTarget::ObjectAssignmentTarget(object_assignment_target) => {
|
||||||
|
object_assignment_target
|
||||||
|
.properties
|
||||||
|
.iter()
|
||||||
|
.any(|property| property.check_for_state_change(check_for_new_objects))
|
||||||
|
|| object_assignment_target
|
||||||
|
.rest
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|rest| rest.check_for_state_change(check_for_new_objects))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CheckForStateChange<'_, '_> for AssignmentTargetProperty<'_> {
|
||||||
|
fn check_for_state_change(&self, check_for_new_objects: bool) -> bool {
|
||||||
|
match self {
|
||||||
|
AssignmentTargetProperty::AssignmentTargetPropertyIdentifier(
|
||||||
|
assignment_target_property_identifier,
|
||||||
|
) => assignment_target_property_identifier
|
||||||
|
.init
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |init| init.check_for_state_change(check_for_new_objects)),
|
||||||
|
AssignmentTargetProperty::AssignmentTargetPropertyProperty(
|
||||||
|
assignment_target_property_property,
|
||||||
|
) => {
|
||||||
|
assignment_target_property_property
|
||||||
|
.name
|
||||||
|
.check_for_state_change(check_for_new_objects)
|
||||||
|
|| assignment_target_property_property
|
||||||
|
.binding
|
||||||
|
.check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CheckForStateChange<'_, '_> for AssignmentTargetRest<'_> {
|
||||||
|
fn check_for_state_change(&self, check_for_new_objects: bool) -> bool {
|
||||||
|
self.target.check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CheckForStateChange<'_, '_> for AssignmentTargetMaybeDefault<'_> {
|
||||||
|
fn check_for_state_change(&self, check_for_new_objects: bool) -> bool {
|
||||||
|
match self {
|
||||||
|
match_assignment_target!(Self) => {
|
||||||
|
self.to_assignment_target().check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
Self::AssignmentTargetWithDefault(assignment_target_with_default) => {
|
||||||
|
assignment_target_with_default.binding.check_for_state_change(check_for_new_objects)
|
||||||
|
&& assignment_target_with_default
|
||||||
|
.init
|
||||||
|
.check_for_state_change(check_for_new_objects)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,3 +18,4 @@ where
|
||||||
|
|
||||||
impl<'a, 'b> MayHaveSideEffects<'a, 'b> for Expression<'a> {}
|
impl<'a, 'b> MayHaveSideEffects<'a, 'b> for Expression<'a> {}
|
||||||
impl<'a, 'b> MayHaveSideEffects<'a, 'b> for UnaryExpression<'a> {}
|
impl<'a, 'b> MayHaveSideEffects<'a, 'b> for UnaryExpression<'a> {}
|
||||||
|
impl<'a, 'b> MayHaveSideEffects<'a, 'b> for ForStatementLeft<'a> {}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue