Skip to content

Incorrect side effect ordering in destructuring transform #39205

Closed
@evanw

Description

@evanw

TypeScript Version: Nightly

Search Terms: side effect ordering destructuring transform lowering spread rest binding pattern

Code

I recently implemented object rest properties for esbuild, a new TypeScript transpiler. When doing this I noticed several bugs with TypeScript's destructuring transform.

These bugs were identified by a fuzzer for JavaScript destructuring that I wrote while developing the transform code for esbuild. The fuzzer generates random test cases and compares the execution of the transpiled code with the execution of the original JavaScript. You can see example output from the fuzzer here.

This issue is for tracking bugs where expressions with side effects are accidentally reordered. There may be more than one individual bug in this class of bugs, and the fuzzer could be a good tool for finding them all.

Here's an example ordering issue:

let trace = []
let order = n => trace.push(n)
let [{ [order(1)]: x } = order(0)] = []
console.log(trace)

Expected behavior:

This should always print [0, 1]. Default values must always be evaluated before computed property keys.

Actual behavior:

The TypeScript transpiler generates code that correctly prints [0, 1] when targeting ES6 and above but generates code that incorrectly prints [1, 0] when targeting ES5 and below.

Playground Link: link

Related Issues:

This ordering issue can also come up when targeting ES6, although the reproduction is a little more complicated:

let trace = []
let order = n => trace.push(n)
let { [order(0)]: { [order(2)]: y } = order(1), ...z } = {}
console.log(trace)

This prints [0, 1, 2] when run natively and prints [0, 2, 1] when transpiled with TypeScript targeting ES6.

Another ordering bug was mentioned in #39181:

var [{ ...a }, b = a] = [{ x: 1 }]
console.log(b.x === 1) // true

This should print true but crashes with Uncaught TypeError: Cannot read property 'x' of undefined when transpiled with TypeScript targeting ES6.

As I mentioned above, there may also be more ordering bugs like this depending on if these all have the same root cause or not. Hopefully the fuzzer will be a useful tool for getting to the bottom of these bugs.

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issueRescheduledThis issue was previously scheduled to an earlier milestone

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions