A class with a parameterless *[Symbol.iterator]() generator method can now
be iterated by for-of, array spread, Array.from, Math.max and Math.min
spreads, new Set, new Map, Object.fromEntries and Iterator.from. Each site
calls the method once and drives the generator it returns.
obj[Symbol.iterator]() and the other well-known symbol methods called
through element access now call the class's method, so iterator helpers
apply to the result instead of failing on an untyped value.
Writes that can replace a well-known symbol method (a symbol-keyed write,
Object.defineProperty, a prototype write) now enter the method census, and
those classes keep the existing checked or refused paths.
An object literal with a computed key that does not fold to a constant,
such as `{ [key]: 1 }`, entered the method replacement census as a write
with an unknown key and no receiver. That marked every class method name
in the program as replaceable, so method calls went through the checked
property lookup. A computed key in an object literal defines a property of
the new object, which is not a class instance, so the census now skips it.
Literals passed to Object.assign or Object.defineProperties are still
judged with their receiver.
Closes#962
Co-authored-by: Quim T. <26749475+espetro@users.noreply.github.com>
An element write whose key is asserted to a number, such as
`slots[at as number] = x` or `slots[at!] = x`, was judged by the type of
the key before the assertion. A `number | undefined` key counted as a key
that can name any string, so calls of every method in the program went
through the checked property lookup. The census now reads the type of the
key with its assertions, so these writes only mark methods with numeric
names.
Fixes#1148
Co-authored-by: Alan Leal <33952+alantriesagain@users.noreply.github.com>
The class method census marks a method name as replaceable when a
function-typed property write uses that name, so a scanner storing its
error callback in `this.onError` made every call of any class's
`onError` method go through the checked property bag. That bag is a
dynamic store naming any property, so the int32 slot analysis also gave up
int32 storage for every class field exposed to dynamic code.
A function-typed write now marks the name only when an instance of a class
that has the method can inhabit the receiver's type: an assignability check
against the instance types of the method's owners, with `this` in an
instance member read as its class. Generic or anonymous owners, `this`
outside instance members, type parameters, `any` and `unknown` receivers
keep the conservative answer. Writes through interfaces or subclasses that
can reach a method still replace it.
Test: class-method-mutations.test.ts. Corpus:
4597-callback-field-method-name.