Skip to content

es/minifier: shadowed undefined parameter renamed to undefined1, leaving an undeclared reference #12438

Description

@bminer

Describe the bug

When a function has a parameter named undefined (the old UMD idiom (function (window, document, undefined) { ... })(window, document)) and the same file also refers to the global undefined, SWC renames the parameter to undefined1. The compressor then removes the parameter because it is never passed and rewrites most uses to void 0. It misses uses inside a hoisted function declaration that gets inlined into its call site -- those uses keep the name undefined1, which is no longer declared anywhere. In this case, we get a runtime error ReferenceError: undefined1 is not defined when that code runs.

This does not reproduce through swc.minify(), only through swc.transform() with jsc.minify. That is the call Parcel 2's @parcel/optimizer-swc makes.

To reproduce, the following is needed:

  • A top-level reference to the global undefined. Without it the output is correct.
  • A parameter named undefined.
  • A function declaration that reads it and is inlined. The same body written as an inline function expression (foo(function (x) { ... })) compiles correctly.

Both isModule: true and false reproduce the bug, as does mangle: false. compress: false does not reproduce the bug.

Input code

undefined;
(function (undefined) {
	foo(bar);
	function bar(x) {
		return x === undefined;
	}
})();

Config

{
	"jsc": {
		"target": "es2022",
		"minify": {
			"compress": true,
			"mangle": true
		}
	},
	"minify": true
}

Link to the code that reproduces this issue

https://play.swc.rs/?version=1.16.12&code=H4sIAAAAAAAAAyvNS0lNy8xLTbFW0EgrzUsuyczPU9AohYlqKlQrpOXnayQlFmlaK8AVALkaFSC5otSS0qI8hQoFW1tbhVKEWbUKtZoamtYAYW4Sq14AAAA%3D&config=H4sIAAAAAAAAA41VQY7bMAy87ysCn3vY5lAUfUBvfYOgWJSjVBYNkfImWOTvpRU7m93QRi9BzNGQIjmk3l92u%2BZEbfNr9y5%2F5WOwmSDfv8VCl8T2LJYG2t5Sm8PAzbcFPdEEeRsJqul6Qxq2uQOuLNq%2F7vczo4mIBAtjtvUhBX95jNliP2QgerCJVVyWHhLTZ%2F6MZXybAM7l0X5AjGDTBmIsmZAYOsia4xZjtAOBGW1WvEw3tTkQaiEmsDA4M2QcVDy5wAGTxHxGHVhnWnSgQCFDy2EEjSaxhJZI0lPyqbCDQ%2Bm62ucvbBhtLJaVmHCuLZHbKl6PGIiNL0kr4Q1cqcENnIv7lRm8ycAlp2feCUNa6clfAKlAtETJ9qD5rSe86GmN7TeZIXmRLF8UXPStZZmgk6KaELxS2akykDlo3czgSgtTZVvtOjO8Uj4KDgx4L1pRXNNb4PaoBeXLAOgVQPprvaaqG2DuU7iCTwOxAf%2BWLFkX2Hyit3xcR%2BnSHzBuBOiBj%2Bg2DkgrGNfhLFviPKzjJTkQaYBTjxSqwPMSkAFgNLHuyydtyHiIR9NFPHysifnA9b6He5u6Ou8P%2B5JxiDBCXJPxf4zIJip3GydVL5P9NL3wUxOllcEL318%2FPRuSysvyW5NqenTlIaGqydtz8qP5OLS8HEvVmkB%2FFmKt0%2FUfj5GfKOMGAAA%3D

SWC Info output

Operating System:
    Platform: win32
    Arch: x64
    Machine Type: x86_64
    Version: Windows 11 Pro
    CPU: (14 cores)
        Models: Intel(R) Core(TM) Ultra 7 165U

Binaries:
    Node: 22.23.2
    npm: N/A
    Yarn: N/A
    pnpm: N/A

Relevant Packages:
    @swc/core: 1.16.12
    @swc/helpers: 0.5.23
    @swc/types: 0.1.28
    

SWC Config:
    output: N/A
    .swcrc path: N/A

Next.js info:
    output: N/A

Expected behavior

The shadowed undefined is either kept declared or replaced with void 0 everywhere:

foo(function(o){return void 0===o});

That is what swc.minify() produces for the same input with { compress: true, mangle: true } (checked on 1.16.2).

Actual behavior

foo(function(n){return n===undefined1});

undefined1 is never declared, so calling the callback throws ReferenceError: undefined1 is not defined.

Version

1.16.12

Additional context

Found in a Parcel 2 production build (minified by @parcel/optimizer-swc), where Hammer.js 2.0.8 is pulled in by chartjs-plugin-zoom 2.2.0. Hammer's UMD wrapper is (function(window, document, exportName, undefined) { ... })(window, document, 'Hammer'), and another module in the same bundle uses the global undefined (interaction: { axis: undefined } in chartjs-plugin-annotation). The minified bundle ends up with:

if(8!=t.eventType&&(l>25||i.velocity===undefined1))

from hammer.js line 610:

if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {

The reproduction script:

const swc = require("@swc/core")

const src = `
undefined;
(function (undefined) {
	foo(bar);
	function bar(x) {
		return x === undefined;
	}
})();
`

swc
	.transform(src, {
		jsc: { target: "es2022", minify: { compress: true, mangle: true } },
		minify: true,
		configFile: false,
		swcrc: false,
	})
	.then(({ code }) => console.log(code))
// foo(function(n){return n===undefined1});

Related issues:

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions