diff --git a/.changeset/empty-steaks-dream.md b/.changeset/empty-steaks-dream.md new file mode 100644 index 000000000000..fc00c6afceaa --- /dev/null +++ b/.changeset/empty-steaks-dream.md @@ -0,0 +1,6 @@ +--- +swc_ecma_ast: minor +swc_ecma_utils: major +--- + +perf(es/utils): Restrict recursion of `get_type` diff --git a/crates/swc_ecma_minifier/src/compress/optimize/bools.rs b/crates/swc_ecma_minifier/src/compress/optimize/bools.rs index cbd015c374e2..c541ee8c34ca 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/bools.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/bools.rs @@ -42,13 +42,13 @@ impl Optimizer<'_> { } if !is_ret_val_ignored { - if let Known(Type::Bool) = e.left.get_type() { + if let Known(Type::Bool) = e.left.get_type(self.ctx.expr_ctx) { } else { // Don't change type. return false; } - if let Known(Type::Bool) = e.right.get_type() { + if let Known(Type::Bool) = e.right.get_type(self.ctx.expr_ctx) { } else { // Don't change type. return false; @@ -277,8 +277,8 @@ impl Optimizer<'_> { _ => return None, }; - let lt = left.get_type(); - let rt = right.get_type(); + let lt = left.get_type(self.ctx.expr_ctx); + let rt = right.get_type(self.ctx.expr_ctx); if let Value::Known(lt) = lt { if let Value::Known(rt) = rt { match (lt, rt) { diff --git a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs index 138a1efd6f6f..3679b542ccec 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs @@ -1630,11 +1630,11 @@ impl VisitMut for Optimizer<'_> { self.optimize_bin_and_or(n); if n.op == op!(bin, "+") { - if let Known(Type::Str) = n.left.get_type() { + if let Known(Type::Str) = n.left.get_type(self.ctx.expr_ctx) { self.optimize_expr_in_str_ctx(&mut n.right); } - if let Known(Type::Str) = n.right.get_type() { + if let Known(Type::Str) = n.right.get_type(self.ctx.expr_ctx) { self.optimize_expr_in_str_ctx(&mut n.left); } } diff --git a/crates/swc_ecma_minifier/src/compress/optimize/ops.rs b/crates/swc_ecma_minifier/src/compress/optimize/ops.rs index 5025e0dfd404..b4bc8e4e70bb 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/ops.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/ops.rs @@ -58,8 +58,8 @@ impl Optimizer<'_> { } } - let lt = e.left.get_type(); - let rt = e.right.get_type(); + let lt = e.left.get_type(self.ctx.expr_ctx); + let rt = e.right.get_type(self.ctx.expr_ctx); if e.op == op!("===") { if let Known(lt) = lt { @@ -127,7 +127,10 @@ impl Optimizer<'_> { .into(), ) }; - match (n.left.get_type().opt()?, n.right.get_type().opt()?) { + match ( + n.left.get_type(self.ctx.expr_ctx).opt()?, + n.right.get_type(self.ctx.expr_ctx).opt()?, + ) { // Abort if types differ, or one of them is unknown. (lt, rt) if lt != rt => {} (Type::Obj, Type::Obj) => {} @@ -181,7 +184,7 @@ impl Optimizer<'_> { | Expr::Bin(BinExpr { op: op!("<"), .. }) | Expr::Bin(BinExpr { op: op!(">="), .. }) | Expr::Bin(BinExpr { op: op!(">"), .. }) => { - if let Known(Type::Bool) = arg.get_type() { + if let Known(Type::Bool) = arg.get_type(self.ctx.expr_ctx) { self.changed = true; report_change!("Optimizing: `!!expr` => `expr`"); *e = *arg.take(); @@ -299,14 +302,14 @@ impl Optimizer<'_> { _ => {} } - let lt = bin.left.get_type(); + let lt = bin.left.get_type(self.ctx.expr_ctx); match lt { // Don't change type Known(Type::Bool) => {} _ => return, } - let rt = bin.right.get_type(); + let rt = bin.right.get_type(self.ctx.expr_ctx); match rt { Known(Type::Bool) => {} _ => return, diff --git a/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs b/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs index 3924f631322d..a91aea93ac34 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs @@ -2371,7 +2371,7 @@ impl Optimizer<'_> { Mergable::Drop => return Ok(false), }; - let a_type = a_right.as_deref().map(|a| a.get_type()); + let a_type = a_right.as_deref().map(|a| a.get_type(self.ctx.expr_ctx)); if let Some(a_right) = a_right { if a_right.is_this() || a_right.is_ident_ref_to("arguments") { @@ -2484,7 +2484,7 @@ impl Optimizer<'_> { let Some(a_type) = a_type else { return Ok(false); }; - let b_type = b.right.get_type(); + let b_type = b.right.get_type(self.ctx.expr_ctx); if let Some(a_op) = a_op { if can_drop_op_for(a_op, b.op, var_type, a_type, b_type) { diff --git a/crates/swc_ecma_minifier/src/compress/pure/bools.rs b/crates/swc_ecma_minifier/src/compress/pure/bools.rs index b8b775d7a070..fda1b06c3bff 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/bools.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/bools.rs @@ -85,7 +85,7 @@ impl Pure<'_> { matches!(op, op!("==") | op!("===") | op!("!=") | op!("!==")) } - fn can_absorb_negate(e: &Expr) -> bool { + fn can_absorb_negate(e: &Expr, ctx: ExprCtx) -> bool { match e { Expr::Lit(_) => true, Expr::Bin(BinExpr { @@ -93,11 +93,11 @@ impl Pure<'_> { left, right, .. - }) => can_absorb_negate(left) && can_absorb_negate(right), + }) => can_absorb_negate(left, ctx) && can_absorb_negate(right, ctx), Expr::Bin(BinExpr { op, .. }) if is_eq(*op) => true, Expr::Unary(UnaryExpr { op: op!("!"), arg, .. - }) => arg.get_type() == Value::Known(Type::Bool), + }) => arg.get_type(ctx) == Value::Known(Type::Bool), _ => false, } } @@ -123,7 +123,7 @@ impl Pure<'_> { return; }; - let arg_can_negate = can_absorb_negate(arg); + let arg_can_negate = can_absorb_negate(arg, self.expr_ctx); match &mut **arg { Expr::Bin(BinExpr { op, .. }) if is_eq(*op) => { @@ -158,7 +158,7 @@ impl Pure<'_> { } pub(super) fn compress_cmp_with_long_op(&mut self, e: &mut BinExpr) { - fn should_optimize(l: &Expr, r: &Expr, opts: &CompressOptions) -> bool { + fn should_optimize(l: &Expr, r: &Expr, ctx: ExprCtx, opts: &CompressOptions) -> bool { match (l, r) { ( Expr::Unary(UnaryExpr { @@ -168,7 +168,7 @@ impl Pure<'_> { ) => true, _ => { if opts.comparisons { - match (l.get_type(), r.get_type()) { + match (l.get_type(ctx), r.get_type(ctx)) { (Value::Known(lt), Value::Known(rt)) => lt == rt, _ => false, @@ -185,8 +185,8 @@ impl Pure<'_> { _ => return, } - if should_optimize(&e.left, &e.right, self.options) - || should_optimize(&e.right, &e.left, self.options) + if should_optimize(&e.left, &e.right, self.expr_ctx, self.options) + || should_optimize(&e.right, &e.left, self.expr_ctx, self.options) { report_change!("bools: Compressing comparison of `typeof` with literal"); self.changed = true; @@ -226,8 +226,8 @@ impl Pure<'_> { right, .. }) => { - let lt = left.get_type(); - let rt = right.get_type(); + let lt = left.get_type(self.expr_ctx); + let rt = right.get_type(self.expr_ctx); if let (Value::Known(Type::Bool), Value::Known(Type::Bool)) = (lt, rt) { let rb = right.as_pure_bool(self.expr_ctx); diff --git a/crates/swc_ecma_minifier/src/compress/pure/conds.rs b/crates/swc_ecma_minifier/src/compress/pure/conds.rs index c48f8321b4d0..06545c93ecaa 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/conds.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/conds.rs @@ -21,7 +21,7 @@ impl Pure<'_> { let Expr::Cond(cond) = e else { return }; - let lt = cond.cons.get_type(); + let lt = cond.cons.get_type(self.expr_ctx); if let Value::Known(Type::Bool) = lt { let lb = cond.cons.as_pure_bool(self.expr_ctx); if let Value::Known(true) = lb { @@ -59,7 +59,7 @@ impl Pure<'_> { } } - let rt = cond.alt.get_type(); + let rt = cond.alt.get_type(self.expr_ctx); if let Value::Known(Type::Bool) = rt { let rb = cond.alt.as_pure_bool(self.expr_ctx); if let Value::Known(false) = rb { @@ -220,8 +220,8 @@ impl Pure<'_> { return; } - let lt = bin.left.get_type(); - let rt = bin.right.get_type(); + let lt = bin.left.get_type(self.expr_ctx); + let rt = bin.right.get_type(self.expr_ctx); let _lb = bin.left.as_pure_bool(self.expr_ctx); let rb = bin.right.as_pure_bool(self.expr_ctx); diff --git a/crates/swc_ecma_minifier/src/compress/pure/misc.rs b/crates/swc_ecma_minifier/src/compress/pure/misc.rs index 308b1fc0d2f7..98747637c9d1 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/misc.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/misc.rs @@ -1675,8 +1675,8 @@ impl Pure<'_> { _ => return, }; - let lt = cond.cons.get_type(); - let rt = cond.alt.get_type(); + let lt = cond.cons.get_type(self.expr_ctx); + let rt = cond.alt.get_type(self.expr_ctx); match (lt, rt) { (Known(Type::Bool), Known(Type::Bool)) => {} _ => return, diff --git a/crates/swc_ecma_minifier/src/compress/pure/strings.rs b/crates/swc_ecma_minifier/src/compress/pure/strings.rs index 07fd1c96135b..9d41f323b367 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/strings.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/strings.rs @@ -28,11 +28,11 @@ impl Pure<'_> { _ => return, }; - match l_l.get_type() { + match l_l.get_type(self.expr_ctx) { Known(Type::Str) => {} _ => return, } - match r_l.get_type() { + match r_l.get_type(self.expr_ctx) { Known(Type::Str) => {} _ => return, } @@ -487,8 +487,8 @@ impl Pure<'_> { }, ) = &mut *bin.left { - let type_of_second = left.right.get_type(); - let type_of_third = bin.right.get_type(); + let type_of_second = left.right.get_type(self.expr_ctx); + let type_of_third = bin.right.get_type(self.expr_ctx); if let Value::Known(Type::Str) = type_of_second { if let Value::Known(Type::Str) = type_of_third { @@ -534,8 +534,8 @@ impl Pure<'_> { .. }) = e { - let lt = left.get_type(); - let rt = right.get_type(); + let lt = left.get_type(self.expr_ctx); + let rt = right.get_type(self.expr_ctx); if let Value::Known(Type::Str) = lt { if let Value::Known(Type::Str) = rt { match &**left { diff --git a/crates/swc_ecma_minifier/tests/benches-full/react.js b/crates/swc_ecma_minifier/tests/benches-full/react.js index 0db6b584af04..a7bd2916ceda 100644 --- a/crates/swc_ecma_minifier/tests/benches-full/react.js +++ b/crates/swc_ecma_minifier/tests/benches-full/react.js @@ -512,7 +512,8 @@ throw payload._result; } function isValidElementType(type) { - return 'string' == typeof type || 'function' == typeof type || type === exports.Fragment || type === exports.Profiler || type === REACT_DEBUG_TRACING_MODE_TYPE || type === exports.StrictMode || type === exports.Suspense || type === REACT_SUSPENSE_LIST_TYPE || type === REACT_LEGACY_HIDDEN_TYPE || 'object' == typeof type && null !== type && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_BLOCK_TYPE || type[0] === REACT_SERVER_BLOCK_TYPE); + return 'string' == typeof type || 'function' == typeof type || type === exports.Fragment || type === exports.Profiler || type === REACT_DEBUG_TRACING_MODE_TYPE || type === exports.StrictMode || type === exports.Suspense || type === REACT_SUSPENSE_LIST_TYPE || type === REACT_LEGACY_HIDDEN_TYPE || 'object' == typeof type && null !== type && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_BLOCK_TYPE || type[0] === REACT_SERVER_BLOCK_TYPE) || !1 // Note: typeof might be other than 'symbol' or 'number' (e.g. if it's a polyfill). + ; } function resolveDispatcher() { var dispatcher = ReactCurrentDispatcher.current; diff --git a/crates/swc_ecma_minifier/tests/fixture/next/styled-components/1/output.js b/crates/swc_ecma_minifier/tests/fixture/next/styled-components/1/output.js index f23d5b19c071..d808cc0ec162 100644 --- a/crates/swc_ecma_minifier/tests/fixture/next/styled-components/1/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/next/styled-components/1/output.js @@ -6701,7 +6701,7 @@ * LICENSE file in the root directory of this source tree. */ var u, b = Symbol.for("react.element"), c = Symbol.for("react.portal"), d = Symbol.for("react.fragment"), e = Symbol.for("react.strict_mode"), f = Symbol.for("react.profiler"), g = Symbol.for("react.provider"), h = Symbol.for("react.context"), k = Symbol.for("react.server_context"), l = Symbol.for("react.forward_ref"), m = Symbol.for("react.suspense"), n = Symbol.for("react.suspense_list"), p = Symbol.for("react.memo"), q = Symbol.for("react.lazy"), t = Symbol.for("react.offscreen"); u = Symbol.for("react.module.reference"), exports.isValidElementType = function(a) { - return "string" == typeof a || "function" == typeof a || a === d || a === f || a === e || a === m || a === n || a === t || "object" == typeof a && null !== a && (a.$$typeof === q || a.$$typeof === p || a.$$typeof === g || a.$$typeof === h || a.$$typeof === l || a.$$typeof === u || void 0 !== a.getModuleId); + return "string" == typeof a || "function" == typeof a || a === d || a === f || a === e || a === m || a === n || a === t || "object" == typeof a && null !== a && (a.$$typeof === q || a.$$typeof === p || a.$$typeof === g || a.$$typeof === h || a.$$typeof === l || a.$$typeof === u || void 0 !== a.getModuleId) || !1; }, exports.typeOf = function(a) { if ("object" == typeof a && null !== a) { var r = a.$$typeof; diff --git a/crates/swc_ecma_minifier/tests/fixture/next/syncfusion/933-e9f9a6bf671b96fc/output.js b/crates/swc_ecma_minifier/tests/fixture/next/syncfusion/933-e9f9a6bf671b96fc/output.js index 2f8f825a6329..21ca64cf8622 100644 --- a/crates/swc_ecma_minifier/tests/fixture/next/syncfusion/933-e9f9a6bf671b96fc/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/next/syncfusion/933-e9f9a6bf671b96fc/output.js @@ -27994,7 +27994,7 @@ */ ToolbarRenderer.prototype.renderColorPickerDropDown = function(args, item, colorPicker, defaultColor) { var range, _this = this, proxy = this, css = classes /* CLS_RTE_ELEMENTS */ .i7 + ' ' + classes /* CLS_TB_BTN */ .Fs + (this.parent.inlineMode ? ' ' + classes /* CLS_INLINE_DROPDOWN */ .ZV : ''); - css += ' ' + ('backgroundcolor' === item ? classes /* CLS_BACKGROUND_COLOR_DROPDOWN */ .Z8 : classes /* CLS_FONT_COLOR_DROPDOWN */ .UQ) + ' ' + this.parent.cssClass; + css += ' ' + ('backgroundcolor' === item ? classes /* CLS_BACKGROUND_COLOR_DROPDOWN */ .Z8 : classes /* CLS_FONT_COLOR_DROPDOWN */ .UQ), css += ' ' + this.parent.cssClass; var content = proxy.parent.createElement('span', { className: classes /* CLS_COLOR_CONTENT */ .uN }), inlineEle = proxy.parent.createElement('span', { @@ -30011,7 +30011,7 @@ * @returns {boolean} - returns the boolean value * @hidden */ function isEditableValueEmpty(value) { - return '