Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
export var x = function() {
return 1;
};
x('a', 'b');
x();
Original file line number Diff line number Diff line change
Expand Up @@ -218,5 +218,5 @@ function _templateObject21() {
}
function fn2() {}
_templateObject(), _templateObject1();
var d1 = fn2(_templateObject2(), 0, void 0), d2 = fn2(_templateObject3(), 0, void 0);
var d1 = fn2(_templateObject2()), d2 = fn2(_templateObject3());
d1.foo(), d2(), _templateObject4(), _templateObject5(), _templateObject6(), _templateObject7(), _templateObject8(), _templateObject9(), _templateObject10(), _templateObject11(), _templateObject12(), _templateObject13(), _templateObject14(), _templateObject15(), _templateObject16(), _templateObject17(), _templateObject18(), _templateObject19(), _templateObject20(), _templateObject21();
67 changes: 67 additions & 0 deletions crates/swc_ecma_minifier/src/compress/optimize/call_args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use swc_ecma_ast::*;

use super::Optimizer;
use crate::program_data::VarUsageInfoFlags;

impl Optimizer<'_> {
/// Drop trailing call arguments that are guaranteed to be unused by a
/// known function binding.
pub(super) fn drop_unused_args_of_known_fn_call(&mut self, e: &mut CallExpr) {
if !self.options.unused && !self.options.reduce_vars {
return;
}

let callee = match &e.callee {
Callee::Super(_) | Callee::Import(_) => return,
Callee::Expr(callee) => match &**callee {
Expr::Ident(callee) => callee,
_ => return,
},
#[cfg(swc_ast_unknown)]
_ => panic!("unable to access unknown nodes"),
};

let Some(usage) = self.data.vars.get(&callee.to_id()) else {
return;
};
if usage.flags.contains(VarUsageInfoFlags::REASSIGNED) {
return;
}

let Some(metadata) = self.functions.get(&callee.to_id()) else {
return;
};

if metadata.has_rest || metadata.uses_arguments {
return;
}

if e.args.len() <= metadata.param_count {
return;
}

if e.args.iter().any(|arg| arg.spread.is_some()) {
return;
}

let mut removed = false;

for idx in (metadata.param_count..e.args.len()).rev() {
if let Some(arg) = e.args.get_mut(idx) {
let new = self.ignore_return_value(&mut arg.expr);

if let Some(new) = new {
arg.expr = Box::new(new);
} else {
e.args.remove(idx);
removed = true;
}
}
}

if removed {
self.changed = true;
report_change!("unused: Dropped trailing unused call arguments");
}
}
}
66 changes: 51 additions & 15 deletions crates/swc_ecma_minifier/src/compress/optimize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use crate::{

mod arguments;
mod bools;
mod call_args;
mod conditionals;
mod dead_code;
mod drop_console;
Expand Down Expand Up @@ -336,21 +337,40 @@ impl Repeated for Optimizer<'_> {
#[derive(Debug, Clone, Copy)]
struct FnMetadata {
len: usize,
param_count: usize,
has_rest: bool,
uses_arguments: bool,
}

impl From<&Function> for FnMetadata {
fn from(f: &Function) -> Self {
fn function_length_from_params<'a>(params: impl IntoIterator<Item = &'a Pat>) -> usize {
params
.into_iter()
.filter(|p| matches!(p, Pat::Ident(..) | Pat::Array(..) | Pat::Object(..)))
.count()
}

impl Optimizer<'_> {
fn fn_metadata_of_function(&self, f: &Function) -> FnMetadata {
FnMetadata {
len: f
.params
.iter()
.filter(|p| matches!(&p.pat, Pat::Ident(..) | Pat::Array(..) | Pat::Object(..)))
.count(),
len: function_length_from_params(f.params.iter().map(|p| &p.pat)),
param_count: f.params.len(),
has_rest: f.params.iter().any(|p| p.pat.is_rest()),
uses_arguments: self
.data
.get_scope(f.ctxt)
.is_some_and(|scope| scope.contains(ScopeData::USED_ARGUMENTS)),
}
}

fn fn_metadata_of_arrow(&self, a: &ArrowExpr) -> FnMetadata {
FnMetadata {
len: function_length_from_params(a.params.iter()),
param_count: a.params.len(),
has_rest: a.params.iter().any(Pat::is_rest),
uses_arguments: false,
}
}
}

impl Optimizer<'_> {
fn may_remove_ident(&self, id: &Ident) -> bool {
if self
.data
Expand Down Expand Up @@ -1711,6 +1731,7 @@ impl VisitMut for Optimizer<'_> {
self.ignore_unused_args_of_iife(e);
self.inline_args_of_iife(e);
self.drop_arguments_of_symbol_call(e);
self.drop_unused_args_of_known_fn_call(e);

// Try to replace static method call with alias (after other transformations)
if let Callee::Expr(callee) = &mut e.callee {
Expand Down Expand Up @@ -2135,9 +2156,8 @@ impl VisitMut for Optimizer<'_> {
)
.entered();

self.functions
.entry(f.ident.to_id())
.or_insert_with(|| FnMetadata::from(&*f.function));
let metadata = self.fn_metadata_of_function(&f.function);
self.functions.entry(f.ident.to_id()).or_insert(metadata);

self.drop_unused_params(&mut f.function.params);

Expand All @@ -2154,9 +2174,8 @@ impl VisitMut for Optimizer<'_> {
#[cfg_attr(feature = "debug", tracing::instrument(level = "debug", skip_all))]
fn visit_mut_fn_expr(&mut self, e: &mut FnExpr) {
if let Some(ident) = &e.ident {
self.functions
.entry(ident.to_id())
.or_insert_with(|| FnMetadata::from(&*e.function));
let metadata = self.fn_metadata_of_function(&e.function);
self.functions.entry(ident.to_id()).or_insert(metadata);
}

if !self.options.keep_fnames {
Expand Down Expand Up @@ -3016,6 +3035,23 @@ impl VisitMut for Optimizer<'_> {

debug_assert_valid(&var.init);

if let VarDeclarator {
name: Pat::Ident(id),
init: Some(init),
..
} = var
{
let metadata = match &**init {
Expr::Fn(FnExpr { function, .. }) => Some(self.fn_metadata_of_function(function)),
Expr::Arrow(arrow) => Some(self.fn_metadata_of_arrow(arrow)),
_ => None,
};

if let Some(metadata) = metadata {
self.functions.entry(id.id.to_id()).or_insert(metadata);
}
}

if let VarDeclarator {
name: Pat::Ident(id),
init: Some(init),
Expand Down
10 changes: 5 additions & 5 deletions crates/swc_ecma_minifier/tests/benches-full/victory.js
Original file line number Diff line number Diff line change
Expand Up @@ -30598,7 +30598,7 @@
scale: scale,
axisType: axisType,
text: text
}).tickStyle, axisAngle = "radial" === axisType ? getAxisAngle(props, scale) : void 0, tickPadding = tickStyle.padding || tickStyle.size || 0, padAngle = victory_core__WEBPACK_IMPORTED_MODULE_3__.Helpers.degreesToRadians(90 - axisAngle), tickAngle = "angular" === axisType ? scale(tickValue) : victory_core__WEBPACK_IMPORTED_MODULE_3__.Helpers.degreesToRadians(-1 * axisAngle), tickRadius = "angular" === axisType ? radius : scale(tickValue);
}).tickStyle, axisAngle = "radial" === axisType ? getAxisAngle(props) : void 0, tickPadding = tickStyle.padding || tickStyle.size || 0, padAngle = victory_core__WEBPACK_IMPORTED_MODULE_3__.Helpers.degreesToRadians(90 - axisAngle), tickAngle = "angular" === axisType ? scale(tickValue) : victory_core__WEBPACK_IMPORTED_MODULE_3__.Helpers.degreesToRadians(-1 * axisAngle), tickRadius = "angular" === axisType ? radius : scale(tickValue);
return "angular" === axisType ? {
index: index,
datum: tick,
Expand Down Expand Up @@ -30627,7 +30627,7 @@
radius: radius,
scale: scale,
axisType: axisType
}).labelStyle, tickLabelComponent = props.tickLabelComponent, labelPlacement = tickLabelComponent.props && tickLabelComponent.props.labelPlacement ? tickLabelComponent.props.labelPlacement : props.labelPlacement, tickPadding = labelStyle.padding || 0, axisAngle = "radial" === axisType ? getAxisAngle(props, scale) : void 0, labelAngle = "angular" === axisType ? victory_core__WEBPACK_IMPORTED_MODULE_3__.Helpers.radiansToDegrees(scale(tickValue)) : axisAngle + 0, textAngle = void 0 === labelStyle.angle ? victory_core__WEBPACK_IMPORTED_MODULE_3__.LabelHelpers.getPolarAngle(lodash_assign__WEBPACK_IMPORTED_MODULE_2___default()({}, props, {
}).labelStyle, tickLabelComponent = props.tickLabelComponent, labelPlacement = tickLabelComponent.props && tickLabelComponent.props.labelPlacement ? tickLabelComponent.props.labelPlacement : props.labelPlacement, tickPadding = labelStyle.padding || 0, axisAngle = "radial" === axisType ? getAxisAngle(props) : void 0, labelAngle = "angular" === axisType ? victory_core__WEBPACK_IMPORTED_MODULE_3__.Helpers.radiansToDegrees(scale(tickValue)) : axisAngle + 0, textAngle = void 0 === labelStyle.angle ? victory_core__WEBPACK_IMPORTED_MODULE_3__.LabelHelpers.getPolarAngle(lodash_assign__WEBPACK_IMPORTED_MODULE_2___default()({}, props, {
labelPlacement: labelPlacement
}), labelAngle) : labelStyle.angle, labelRadius = "angular" === axisType ? radius + tickPadding : scale(tickValue), textAnchor = labelStyle.textAnchor || victory_core__WEBPACK_IMPORTED_MODULE_3__.LabelHelpers.getPolarTextAnchor(lodash_assign__WEBPACK_IMPORTED_MODULE_2___default()({}, props, {
labelPlacement: labelPlacement
Expand Down Expand Up @@ -30673,9 +30673,9 @@
endAngle: endAngle
};
}, getAxisLabelProps = function(props, calculatedValues) {
var axisType = calculatedValues.axisType, radius = calculatedValues.radius, style = calculatedValues.style, scale = calculatedValues.scale, origin = calculatedValues.origin, axisLabelComponent = props.axisLabelComponent;
var axisType = calculatedValues.axisType, radius = calculatedValues.radius, style = calculatedValues.style, origin = (calculatedValues.scale, calculatedValues.origin), axisLabelComponent = props.axisLabelComponent;
if ("radial" !== axisType) return {};
var labelPlacement = axisLabelComponent.props && axisLabelComponent.props.labelPlacement ? axisLabelComponent.props.labelPlacement : props.labelPlacement, labelStyle = style && style.axisLabel || {}, axisAngle = "radial" === axisType ? getAxisAngle(props, scale) : void 0, textAngle = void 0 === labelStyle.angle ? victory_core__WEBPACK_IMPORTED_MODULE_3__.LabelHelpers.getPolarAngle(lodash_assign__WEBPACK_IMPORTED_MODULE_2___default()({}, props, {
var labelPlacement = axisLabelComponent.props && axisLabelComponent.props.labelPlacement ? axisLabelComponent.props.labelPlacement : props.labelPlacement, labelStyle = style && style.axisLabel || {}, axisAngle = "radial" === axisType ? getAxisAngle(props) : void 0, textAngle = void 0 === labelStyle.angle ? victory_core__WEBPACK_IMPORTED_MODULE_3__.LabelHelpers.getPolarAngle(lodash_assign__WEBPACK_IMPORTED_MODULE_2___default()({}, props, {
labelPlacement: labelPlacement
}), axisAngle) : labelStyle.angle, labelRadius = radius + (labelStyle.padding || 0), textAnchor = labelStyle.textAnchor || victory_core__WEBPACK_IMPORTED_MODULE_3__.LabelHelpers.getTextPolarAnchor(lodash_assign__WEBPACK_IMPORTED_MODULE_2___default()({}, props, {
labelPlacement: labelPlacement
Expand All @@ -30692,7 +30692,7 @@
y: getPosition(labelRadius, victory_core__WEBPACK_IMPORTED_MODULE_3__.Helpers.degreesToRadians(axisAngle), "y") + origin.y
};
}, getAxisProps = function(modifiedProps, calculatedValues) {
var style = calculatedValues.style, axisType = calculatedValues.axisType, radius = calculatedValues.radius, scale = calculatedValues.scale, origin = calculatedValues.origin, startAngle = modifiedProps.startAngle, endAngle = modifiedProps.endAngle, _modifiedProps$innerR = modifiedProps.innerRadius, innerRadius = void 0 === _modifiedProps$innerR ? 0 : _modifiedProps$innerR, axisAngle = "radial" === axisType ? victory_core__WEBPACK_IMPORTED_MODULE_3__.Helpers.degreesToRadians(getAxisAngle(modifiedProps, scale)) : void 0;
var style = calculatedValues.style, axisType = calculatedValues.axisType, radius = calculatedValues.radius, origin = (calculatedValues.scale, calculatedValues.origin), startAngle = modifiedProps.startAngle, endAngle = modifiedProps.endAngle, _modifiedProps$innerR = modifiedProps.innerRadius, innerRadius = void 0 === _modifiedProps$innerR ? 0 : _modifiedProps$innerR, axisAngle = "radial" === axisType ? victory_core__WEBPACK_IMPORTED_MODULE_3__.Helpers.degreesToRadians(getAxisAngle(modifiedProps)) : void 0;
return "radial" === axisType ? {
style: style.axis,
x1: getPosition(innerRadius, axisAngle, "x") + origin.x,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1704,7 +1704,7 @@
};
} // CONCATENATED MODULE: ./node_modules/_@swc_helpers@0.2.13@@swc/helpers/src/_sliced_to_array.js
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArray(arr, i) || _nonIterableRest();
return _arrayWithHoles(arr) || _iterableToArray(arr) || _nonIterableRest();
} // CONCATENATED MODULE: ./node_modules/_@swc_helpers@0.2.13@@swc/helpers/src/_sliced_to_array_loose.js
function _slicedToArrayLoose(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimitLoose(arr, i) || _nonIterableRest();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ export function f(i, e, cmp) {
function g() {
return i++, e || 0;
}
return e = g(e), cmp(i, e) && console.log(e), g;
return e = g(), cmp(i, e) && console.log(e), g;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11097,7 +11097,7 @@
try {
var muted = Html5.TEST_VID.muted; // in some versions of iOS muted property doesn't always
return(// work, so we want to set both property and attribute
Html5.TEST_VID.muted = !muted, Html5.TEST_VID.muted ? setAttribute(Html5.TEST_VID, "muted", "muted") : removeAttribute(Html5.TEST_VID, "muted", "muted"), muted !== Html5.TEST_VID.muted);
Html5.TEST_VID.muted = !muted, Html5.TEST_VID.muted ? setAttribute(Html5.TEST_VID, "muted", "muted") : removeAttribute(Html5.TEST_VID, "muted"), muted !== Html5.TEST_VID.muted);
} catch (e) {
return !1;
}
Expand Down
13 changes: 4 additions & 9 deletions crates/swc_ecma_minifier/tests/fixture/next/47005/output.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,12 @@
...k.platform,
_c: E
};
return V(m, S, {
...k,
platform: R
});
return V();
};
var er = async ({ elementReference: m = null, tooltipReference: S = null, tooltipArrowReference: h = null, place: E = "top", offset: k = 10, strategy: R = "absolute", middlewares: A = [
X(Number(k)),
W(),
Y({
padding: 5
})
Y()
] })=>{
if (!m) return {
tooltipStyles: {},
Expand Down Expand Up @@ -213,7 +208,7 @@
};
eo(S), V.current = S;
}, ei = (m)=>{
ee(m), y;
ee(), y;
}, ea = (S)=>{
var h;
[
Expand All @@ -222,7 +217,7 @@
].some((m)=>null == m ? void 0 : m.contains(S.target)) || null != (h = m.current) && h.contains(S.target) || Z(!1);
}, eu = (m)=>{
"Escape" === m.key && Z(!1);
}, es = I(ee, 50), ec = I(et, 50);
}, es = I(), ec = I();
(0, A.useEffect)(()=>{
var S, h;
let E = new Set(W);
Expand Down
Loading
Loading