Skip to content

Commit cae222c

Browse files
committed
feat(minifier): compress return void foo() => foo(); return (#13271)
Compress `return void foo()` => `foo(); return`. `return void 0` and `return undefined` was handled but this wasn't.
1 parent a1b6ad4 commit cae222c

File tree

4 files changed

+37
-9
lines changed

4 files changed

+37
-9
lines changed

crates/oxc_minifier/src/ctx.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use oxc_syntax::{
1313
identifier::{is_identifier_part, is_identifier_start},
1414
reference::ReferenceId,
1515
};
16+
use oxc_traverse::Ancestor;
1617

1718
use crate::{options::CompressOptions, state::MinifierState, symbol_value::SymbolValue};
1819

@@ -253,4 +254,8 @@ impl<'a> Ctx<'a, '_> {
253254
chars.next().is_some_and(is_identifier_start)
254255
&& chars.all(|c| is_identifier_part(c) && c != '・' && c != '・')
255256
}
257+
258+
pub fn is_in_async_generator(&self) -> bool {
259+
self.ancestors().any(|ancestor| matches!(ancestor, Ancestor::FunctionBody(body) if *body.r#async() && *body.generator()))
260+
}
256261
}

crates/oxc_minifier/src/peephole/minimize_statements.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use std::{iter, ops::ControlFlow};
33
use oxc_allocator::{Box, TakeIn, Vec};
44
use oxc_ast::ast::*;
55
use oxc_ast_visit::Visit;
6-
use oxc_ecmascript::side_effects::MayHaveSideEffects;
6+
use oxc_ecmascript::{
7+
constant_evaluation::{DetermineValueType, ValueType},
8+
side_effects::MayHaveSideEffects,
9+
};
710
use oxc_semantic::ScopeId;
811
use oxc_span::{ContentEq, GetSpan};
912
use oxc_traverse::Ancestor;
@@ -610,6 +613,30 @@ impl<'a> PeepholeOptimizations {
610613

611614
ctx: &mut Ctx<'a, '_>,
612615
) {
616+
if let Some(argument) = &mut ret_stmt.argument
617+
&& argument.value_type(ctx) == ValueType::Undefined
618+
// `return undefined` has a different semantic in async generator function.
619+
&& !ctx.is_in_async_generator()
620+
{
621+
ctx.state.changed = true;
622+
if argument.may_have_side_effects(ctx) {
623+
if ctx.options().sequences
624+
&& let Some(Statement::ExpressionStatement(prev_expr_stmt)) = result.last_mut()
625+
{
626+
let a = &mut prev_expr_stmt.expression;
627+
prev_expr_stmt.expression = Self::join_sequence(a, argument, ctx);
628+
} else {
629+
result.push(
630+
ctx.ast.statement_expression(argument.span(), argument.take_in(ctx.ast)),
631+
);
632+
}
633+
}
634+
ret_stmt.argument = None;
635+
result.push(Statement::ReturnStatement(ret_stmt));
636+
*is_control_flow_dead = true;
637+
return;
638+
}
639+
613640
if ctx.options().sequences {
614641
if let Some(Statement::ExpressionStatement(prev_expr_stmt)) = result.last_mut() {
615642
if let Some(argument) = &mut ret_stmt.argument {

crates/oxc_minifier/src/peephole/substitute_alternate_syntax.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -790,12 +790,8 @@ impl<'a> PeepholeOptimizations {
790790
return;
791791
}
792792
// `return undefined` has a different semantic in async generator function.
793-
for ancestor in ctx.ancestors() {
794-
if let Ancestor::FunctionBody(func) = ancestor {
795-
if *func.r#async() && *func.generator() {
796-
return;
797-
}
798-
}
793+
if ctx.is_in_async_generator() {
794+
return;
799795
}
800796
stmt.argument = None;
801797
ctx.state.changed = true;
@@ -1482,7 +1478,7 @@ mod test {
14821478
test("function f(){return !1;}", "function f(){return !1}");
14831479
test("function f(){return null;}", "function f(){return null}");
14841480
test("function f(){return void 0;}", "function f(){}");
1485-
test("function f(){return void foo();}", "function f(){return void foo()}");
1481+
test("function f(){return void foo();}", "function f(){foo()}");
14861482
test("function f(){return undefined;}", "function f(){}");
14871483
test("function f(){if(a()){return undefined;}}", "function f(){a()}");
14881484
test_same("function a(undefined) { return undefined; }");

tasks/minsize/minsize.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ Original | minified | minified | gzip | gzip | Iterations | Fi
2323

2424
6.69 MB | 2.23 MB | 2.31 MB | 461.69 kB | 488.28 kB | 3 | antd.js
2525

26-
10.95 MB | 3.35 MB | 3.49 MB | 860.59 kB | 915.50 kB | 2 | typescript.js
26+
10.95 MB | 3.35 MB | 3.49 MB | 860.58 kB | 915.50 kB | 2 | typescript.js
2727

0 commit comments

Comments
 (0)