instanceof Promise on values that are never promises now compiles to
false after the operand is evaluated, so the diagnostics fixture no longer
lists it as refused. 8326-never-promise-instanceof covers records, arrays,
dates, collections, regular expressions, byte arrays and unions with null,
and a call operand that still runs.
- A binding that a local class captures counts as written: the class's
methods may assign it while the loop runs, so the call keeps its helper.
- Copied bodies rename the labels of switch and for-of statements and the
binding of for-of loops.
- The known-union and record-temporary cleanups rewrite switch cases and
for-of bodies, where they left declarations of removed locals.
- Copied locals keep their source bindings. In programs that write
contract types, a parameter with a source binding keeps its own local,
so an Int32 parameter is checked against the elements the loop passes.
A class declared `extends Array` (or `extends Array<T>`) was refused with
"extending classes not declared in the program ('Array')", which blocked
lru-cache at module load. An instance is now an array of the class's
element type: its struct begins with the runtime's array header, whose
reference count it shares, and the class's own fields follow it. The
class's TypeScript type maps to its element array type, so every array
operation applies to an instance, and passing it where an array is
expected passes the same object. The class's own fields, methods,
accessors and statics read the array as the class object.
super() follows the Array constructor: one number argument sets the
length (a RangeError for an invalid one), other arguments become the
elements, and the implicit constructor forwards its arguments the same
way. The runtime finds the class through the array's ext (ScrArrClass:
name, destroy, the own fields, the species constructor), so instanceof
the class (or a binding that holds it) works on static, array-typed and
dyn values, util.inspect
prints `Name(length) [ ..., field: value ]`, Object.keys lists the own
fields, and a release through any array path reaches the class's
teardown. Instances whose elements or fields can form cycles carry the
collector header and are traced.
map, filter, slice, splice, concat, flat and flatMap construct their
result through the class as ArraySpeciesCreate does: `new C(length)` with
the specification's argument, then the elements, then the length where
the specification sets it. A map to another element type retypes the
new instance when its constructor added no elements. Array.of and
Array.from called on the class construct through it. Programs that
declare no Array subclass compile as before.
A generic subclass, a subclass of such a class and `static
[Symbol.species]` are refused at compile time; a species result the
class's constructor cannot construct throws a TypeError.
String() of an array with checked-dynamic elements now uses the
runtime's String() instead of being refused.
Corpus 7720-7726, diagnostics fixture array-subclass-fences.ts.
`x!` performs no runtime check, but the compiler extracted the asserted arm
with a checked narrow, so a value that still held undefined or null threw
"TypeError: undefined is not representable in the target union" wherever it
was used. In Node the value reaches the operator, which converts it.
When `x!` is an operand of an arithmetic, bitwise or relational operator,
`+`, a compound assignment, a unary `-`, `+` or `~`, or an argument of a
Math function, and `x` is a union of numbers, strings, booleans, null and
undefined, the operand is now converted with ToNumber: undefined is NaN and
null is 0. As an operand of an equality operator, of `!`, of a template
span, of `+` with a string, or of a comparison with a string, the union
itself reaches the operator, so `x! === 0` is false and `${x!}` is
"undefined". Array and typed-array element reads keep their handling of a
missing element, and `+` whose result TypeScript types as a string keeps
the checked narrow where Node's result is NaN.
`x == null` on a union with both null and undefined arms evaluated its
operand twice, so an operand other than a plain read was refused. It is now
evaluated once into a hidden local.
Corpus 7392.
existsSync and the fs.promises functions accept a file: URL wherever
they accept a path. They convert it after their arguments are evaluated,
and a URL that does not convert gives false from existsSync and a promise
rejected with fileURLToPath's error from fs.promises, as in Node.
copyFileSync and renameSync check a string source for null bytes before
they convert a URL destination, and readFileSync checks a runtime
encoding before it converts a URL path, so the error Node reports first
is the one thrown.
Refs #1616
Co-authored-by: jlucaso1 <55464917+jlucaso1@users.noreply.github.com>