Repository: swc-project/swc
File: crates/swc_ecma_minifier/src/compress/optimize/iife.rs (Rust)

Code before:
                    // Use `0` if it's removed.
                    arg.expr = Number {
                        span: arg.expr.span(),
                        value: 0.0,
                        raw: None,
                    }
                    .into();
                }
            } else {
                break;
            }
        }

        if e.args.len() > params.len() {
            for i in (params.len()..e.args.len()).rev() {
                if let Some(arg) = e.args.get_mut(i) {
                    let new = self.ignore_return_value(&mut arg.expr);

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

    #[cfg_attr(feature = "debug", tracing::instrument(level = "debug", skip_all))]
    pub(super) fn inline_vars_in_node<N>(&mut self, n: &mut N, mut vars: FxHashMap<Id, Box<Expr>>)
    where
        N: for<'aa> VisitMutWith<NormalMultiReplacer<'aa>>,
    {
        trace_op!("inline: inline_vars_in_node");

        let mut v = NormalMultiReplacer::new(&mut vars, false);
        n.visit_mut_with(&mut v);
        self.changed |= v.changed;
    }

    fn may_invoke_iife(&self, call: &mut CallExpr) -> bool {
        if self.options.inline == 0
            && !(self.options.reduce_vars && self.options.reduce_fns && self.options.evaluate)
        {
            if !call.callee.span().is_dummy() {
                log_abort!("skip");
                return false;
            }
        }

        trace_op!("iife: Checking noinline");

Review comment (bug):
This change introduces new behavior (dropping trailing IIFE call arguments) with several tricky edge cases (e.g. spread args, rest params, side-effect-only rewrites). Please add a focused regression fixture/test that covers the reported pattern from #11089 and at least one spread/rest scenario, so future optimizer changes don't reintroduce incorrect argument dropping.

Code after:
                    // Use `0` if it's removed.
                    arg.expr = Number {
                        span: arg.expr.span(),
                        value: 0.0,
                        raw: None,
                    }
                    .into();
                }
            } else {
                break;
            }
        }

        if e.args.len() > params.len() && !params.iter().any(|p| p.is_rest()) {
            for i in (params.len()..e.args.len()).rev() {
                if let Some(arg) = e.args.get_mut(i) {
                    let new = self.ignore_return_value(&mut arg.expr);

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

    #[cfg_attr(feature = "debug", tracing::instrument(level = "debug", skip_all))]
    pub(super) fn inline_vars_in_node<N>(&mut self, n: &mut N, mut vars: FxHashMap<Id, Box<Expr>>)
    where
        N: for<'aa> VisitMutWith<NormalMultiReplacer<'aa>>,
    {
        trace_op!("inline: inline_vars_in_node");

        let mut v = NormalMultiReplacer::new(&mut vars, false);
        n.visit_mut_with(&mut v);
        self.changed |= v.changed;
    }

    fn may_invoke_iife(&self, call: &mut CallExpr) -> bool {
        if self.options.inline == 0
            && !(self.options.reduce_vars && self.options.reduce_fns && self.options.evaluate)
        {
            if !call.callee.span().is_dummy() {
                log_abort!("skip");
                return false;
            }
        }

        trace_op!("iife: Checking noinline");