mirror of
https://gitee.com/zhangsken/opencode.git
synced 2026-10-16 10:30:01 +08:00
feat(codemode): add Object.freeze/seal/create/getPrototypeOf and structuredClone (#50834)
This commit is contained in:
@@ -102,6 +102,7 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
synchronous iterators, and confined synchronous generators. Abrupt completion invokes the iterator's optional `return()`.
|
||||
- [x] `for...in` over own keys of plain objects, arrays, strings, and tool references. `null`, `undefined`, and other
|
||||
non-objects iterate nothing. An un-awaited promise throws rather than iterating.
|
||||
- [ ] `for...in` over inherited enumerable keys (`Object.create(proto)`), and skipping keys deleted during the loop.
|
||||
- [x] Unlabeled `break` and `continue`.
|
||||
- [x] `try`, `catch`, optional catch bindings, and `finally`.
|
||||
- [x] `throw` with arbitrary values.
|
||||
@@ -154,6 +155,8 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
- [x] Redeclaring a function in the same scope, or alongside a `var`, is allowed: the last declaration wins.
|
||||
- [x] Generator functions have their own `prototype` (inheriting the shared generator prototype), so
|
||||
`g() instanceof g` holds. Plain functions have none, since they cannot construct.
|
||||
- [ ] `GeneratorFunction.prototype`: every function, generator or not, inherits directly from `Function.prototype`,
|
||||
and a generator whose `prototype` was replaced by a non-object still creates from the shared generator prototype.
|
||||
- [x] Generator and async generator functions bind parameters (defaults, destructuring) at the call and defer only the
|
||||
body to the first `next()`, so a bad argument throws synchronously from the call site, as in JS.
|
||||
- [x] Synchronous and async generator declarations/expressions, `yield`, and `yield*`, including lazy bodies,
|
||||
@@ -295,9 +298,27 @@ reject }` object.
|
||||
- [x] Every value has a real prototype chain built fresh for each run: `Object.prototype`, `Array.prototype`,
|
||||
`String.prototype`, `Error.prototype` → `TypeError.prototype`, and so on hold the built-in methods as
|
||||
non-enumerable properties, and each constructor's `prototype` points at it (`[].constructor === Array`,
|
||||
`Object.getPrototypeOf` is not exposed). Programs may read and even overwrite these prototypes; the change is
|
||||
confined to that run. `__proto__` is an ordinary own data key, so `o.__proto__ = x` never changes the chain, and
|
||||
`Object.groupBy` results have no prototype at all, as in JS.
|
||||
`Object.getPrototypeOf([]) === Array.prototype`). Programs may read and even overwrite these prototypes; the
|
||||
change is confined to that run. `__proto__` is an ordinary own data key, so `o.__proto__ = x` never changes the
|
||||
chain, and `Object.groupBy` results have no prototype at all, as in JS.
|
||||
- [x] `Object.getPrototypeOf`: the prototype of an object, or the built-in prototype for a string, number, or boolean
|
||||
(`Object.getPrototypeOf("a") === String.prototype`); `null`, `undefined`, and the two confined symbols throw a
|
||||
`TypeError`.
|
||||
- [x] `Object.create(proto)` with an object or `null` prototype; any other prototype is a `TypeError`
|
||||
(`Object prototype may only be an Object or null`). Inherited reads, `in`, `hasOwnProperty`, and own-only
|
||||
`Object.keys` follow the chain as in JS, but `for...in` still enumerates own keys only. A second `properties`
|
||||
argument other than `undefined` throws a `TypeError`: property descriptors are not supported (there is no
|
||||
`Object.defineProperty` either).
|
||||
- [x] `Object.freeze`, `Object.seal`, and `Object.preventExtensions`, with `isFrozen`, `isSealed`, and `isExtensible`.
|
||||
Each returns its argument and passes primitives through (`Object.freeze(1) === 1`, `Object.isFrozen(1)`).
|
||||
Programs run as strict code, so violations throw `TypeError`: `Cannot assign to read only property 'a'`,
|
||||
`Cannot add property b, object is not extensible`, and `Cannot delete property 'a'`. Arrays enforce the same
|
||||
rules for index writes, `length`, and the mutating methods (`Object.freeze([1]).push(2)` throws; a sealed array's
|
||||
`pop()` throws; a non-extensible array's `pop()`, `sort()`, and `splice(0, 1, x)` work). The mutating methods are
|
||||
checked once up front, so a `fill` or `sort` that would land on a hole of a non-extensible array succeeds here
|
||||
where JS throws. Maps, Sets, and Dates freeze their properties only, not their contents, as in JS.
|
||||
`Object.freeze(new Uint8Array(1))` and `seal` throw `TypeError` like JS (`preventExtensions` and empty typed
|
||||
arrays are fine). Functions are objects and freeze like any other value.
|
||||
- [x] Circular references are rejected when created (`o.self = o`, `array.push(array)`), not at serialization as in JS.
|
||||
- [x] `Object.is` for supported data values.
|
||||
- [x] `Object.groupBy` over finite collections and custom synchronous iterators/generators, with string-key coercion
|
||||
@@ -325,8 +346,8 @@ reject }` object.
|
||||
- [x] `keys`, `values`, `entries`, and `[Symbol.iterator]` (the same function as `values`) return live iterator objects
|
||||
with `next()` and `[Symbol.iterator]`, as in JS. Iterator objects are opaque references: they print as
|
||||
`[opaque reference]`, serialize to `{}`, and cannot be passed to extensions. Every built-in collection iterator
|
||||
shares one prototype. JavaScript gives each collection its own; the difference is not observable here because
|
||||
`Object.getPrototypeOf` is not exposed.
|
||||
shares one prototype, where JavaScript gives each collection its own; `Object.getPrototypeOf` shows the
|
||||
difference.
|
||||
- [x] `length`, numeric indexing, index assignment, spread, and `for...of`.
|
||||
- [x] The `thisArg` argument of `Array.from` is accepted and ignored, like JS arrows.
|
||||
- [x] `Array.prototype.toSpliced`.
|
||||
@@ -518,6 +539,12 @@ with a hint to encode as text first (`TextDecoder`, `toBase64`, `toHex`).
|
||||
- [x] `atob` and `btoa` with forgiving-base64 decoding and WebIDL string conversion; invalid input throws a
|
||||
`TypeError`, since there is no `DOMException`.
|
||||
- [x] `crypto.randomUUID()` and `crypto.getRandomValues(uint8Array)`.
|
||||
- [x] `structuredClone(value)` deep-copies primitives, plain objects (own enumerable string keys onto a plain object;
|
||||
the prototype is not kept), arrays (holes and extra keys kept), Map, Set, Date, RegExp (`lastIndex` reset to 0),
|
||||
Uint8Array, and errors (standard `name`, `message`, `cause`, and `stack`; other names become `Error`, extra
|
||||
fields drop). Shared references stay shared in the copy, and the copy is extensible even when the source was
|
||||
frozen. Functions, symbols, promises, iterators, URL, Headers, and tool references cannot be cloned; without a
|
||||
`DOMException`, the failure is a `TypeError` whose message starts with `DataCloneError:`.
|
||||
- [x] `TextEncoder` and `TextDecoder` for UTF-8 only: any other label is a `RangeError`. `TextDecoder` accepts the
|
||||
`fatal` and `ignoreBOM` options; `decode` takes a Uint8Array or nothing.
|
||||
- [x] `new Headers()` from records, synchronous iterables of pairs, and Headers, wrapping the host's `Headers`: names
|
||||
@@ -569,6 +596,8 @@ Nothing is exposed unless a host provides it; extension calls are not tool calls
|
||||
non-enumerable: an extension Error carries it, and this JSON form does not. Errors have no `stack`; the diagnostic
|
||||
carries a 1-based line and column in the submitted source instead.
|
||||
- [x] `instanceof` against any constructor with a `prototype`, including every built-in and `Function`.
|
||||
- [ ] The derived error constructors inheriting from `Error`: `Object.getPrototypeOf(TypeError)` is
|
||||
`Function.prototype` here, while `TypeError.prototype` does inherit from `Error.prototype`.
|
||||
- [x] Catchable user throws, runtime failures raised during interpreted evaluation, awaited tool failures, and awaited
|
||||
tool-call-limit failures; parse/compile failures, cooperative timeout, and output bounding remain outside program
|
||||
`catch`.
|
||||
|
||||
@@ -15,7 +15,7 @@ import { uriGlobal, urlGlobal, urlSearchParamsGlobal } from "../stdlib/url.js"
|
||||
import { headersGlobal } from "../stdlib/headers.js"
|
||||
import { iteratorGlobals } from "../stdlib/iterator.js"
|
||||
import { coercion } from "../stdlib/value.js"
|
||||
import { base64Global, cryptoGlobal } from "../stdlib/web.js"
|
||||
import { base64Global, cryptoGlobal, structuredCloneGlobal } from "../stdlib/web.js"
|
||||
import { ToolReference } from "../tool-runtime.js"
|
||||
import { errorGlobal } from "./errors.js"
|
||||
import { errorTypes } from "./intrinsics.js"
|
||||
@@ -95,6 +95,7 @@ const table: Record<string, Factory> = {
|
||||
atob: (ctx) => base64Global(ctx, "atob"),
|
||||
btoa: (ctx) => base64Global(ctx, "btoa"),
|
||||
crypto: (ctx) => cryptoGlobal(ctx),
|
||||
structuredClone: (ctx) => structuredCloneGlobal(ctx),
|
||||
...Object.fromEntries(errorTypes.map((type) => [type, <R>(ctx: Interpreter<R>) => errorGlobal(type, ctx)])),
|
||||
}
|
||||
|
||||
|
||||
@@ -2218,7 +2218,6 @@ class Frame<R> {
|
||||
}
|
||||
})()
|
||||
if (written) return
|
||||
if (target instanceof Arr && key === "length") throw rangeError("Invalid array length", node)
|
||||
throw typeError(`Cannot assign to read only property '${String(key)}'.`, node)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ import {
|
||||
type GeneratorRequestKind,
|
||||
IteratorSymbol,
|
||||
type PendingThrow,
|
||||
rangeError,
|
||||
typeError,
|
||||
} from "./model.js"
|
||||
|
||||
/** Property attributes, as in a JS property descriptor. */
|
||||
@@ -41,6 +43,8 @@ export const frozen: Attributes = { writable: false, enumerable: false, configur
|
||||
*/
|
||||
export class Obj {
|
||||
readonly props = new Map<string | symbol, Slot>()
|
||||
/** [[Extensible]]: cleared by `Object.preventExtensions`, `seal`, and `freeze`. */
|
||||
extensible = true
|
||||
constructor(public proto: Obj | null) {}
|
||||
|
||||
/** The class name `Object.prototype.toString` reports: `[object Map]`. */
|
||||
@@ -91,6 +95,8 @@ export class Obj {
|
||||
|
||||
export class Arr extends Obj {
|
||||
override readonly tag = "Array"
|
||||
/** The attributes every live element shares; `seal` and `freeze` narrow them since elements have no slots. */
|
||||
elements: Attributes = data
|
||||
constructor(
|
||||
proto: Obj,
|
||||
readonly items: Array<Value> = [],
|
||||
@@ -460,10 +466,11 @@ export const own = (target: Obj, key: PropertyKey): Slot | undefined => {
|
||||
const at = index(target, name)
|
||||
if (at !== undefined) {
|
||||
const items = elements(target)
|
||||
return at in items ? { value: items[at], ...data } : undefined
|
||||
if (!(at in items)) return undefined
|
||||
return { value: items[at], ...(target instanceof Arr ? target.elements : data) }
|
||||
}
|
||||
if (target instanceof Arr && name === "length") {
|
||||
return { value: target.items.length, writable: true, enumerable: false, configurable: false }
|
||||
return { value: target.items.length, writable: target.elements.writable, enumerable: false, configurable: false }
|
||||
}
|
||||
}
|
||||
return target.props.get(name)
|
||||
@@ -505,13 +512,19 @@ export const hasPrototype = (value: Value, proto: Obj): boolean => {
|
||||
const writeElement = (target: Indexed, name: string | symbol, value: Value): boolean | undefined => {
|
||||
const at = index(target, name)
|
||||
if (at !== undefined) {
|
||||
if (target instanceof Bytes) target.bytes[at] = typeof value === "number" ? value : Number(value)
|
||||
else target.items[at] = value
|
||||
if (target instanceof Bytes) {
|
||||
target.bytes[at] = typeof value === "number" ? value : Number(value)
|
||||
return true
|
||||
}
|
||||
if (!(at in target.items)) rejectAddition(target, at)
|
||||
target.items[at] = value
|
||||
return true
|
||||
}
|
||||
if (!(target instanceof Arr) || name !== "length") return undefined
|
||||
const length = typeof value === "number" ? value : Number(value)
|
||||
if (!Number.isInteger(length) || length < 0) return false
|
||||
if (!Number.isInteger(length) || length < 0) throw rangeError("Invalid array length")
|
||||
// Shrinking deletes elements, which a sealed array forbids.
|
||||
if (length < target.items.length && !target.elements.configurable) return false
|
||||
checkArrayLength(length)
|
||||
target.items.length = length
|
||||
return true
|
||||
@@ -541,10 +554,17 @@ export const set = (target: Obj, key: PropertyKey, value: Value): boolean => {
|
||||
const written = writeElement(target, name, value)
|
||||
if (written !== undefined) return written
|
||||
}
|
||||
rejectAddition(target, name)
|
||||
target.props.set(name, { value, ...data })
|
||||
return true
|
||||
}
|
||||
|
||||
/** Creating a property on a non-extensible object is the one [[Set]] failure with its own message. */
|
||||
export const rejectAddition = (target: Obj, key: string | symbol | number): void => {
|
||||
if (target.extensible) return
|
||||
throw typeError(`Cannot add property ${String(key)}, object is not extensible.`)
|
||||
}
|
||||
|
||||
/** [[DefineOwnProperty]] for a data property, ignoring the chain. */
|
||||
export const define = (target: Obj, key: PropertyKey, value: Value, attrs: Attributes = data): void => {
|
||||
const name = canonical(key)
|
||||
@@ -560,7 +580,11 @@ export const remove = (target: Obj, key: PropertyKey): boolean => {
|
||||
const name = canonical(key)
|
||||
if (isIndexed(target)) {
|
||||
const at = index(target, name)
|
||||
if (at !== undefined) return target instanceof Bytes ? !(at in target.bytes) : delete target.items[at]
|
||||
if (at !== undefined) {
|
||||
if (target instanceof Bytes) return !(at in target.bytes)
|
||||
if (at in target.items && !target.elements.configurable) return false
|
||||
return delete target.items[at]
|
||||
}
|
||||
if (target instanceof Arr && name === "length") return false
|
||||
}
|
||||
const slot = target.props.get(name)
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
coerceToInteger,
|
||||
coerceToNumber,
|
||||
coerceToString,
|
||||
rejectAddition,
|
||||
type Value,
|
||||
} from "../interpreter/objects.js"
|
||||
import { describeValue, rejectCircularInsertion } from "../interpreter/references.js"
|
||||
@@ -124,6 +125,20 @@ export const arrayGlobal = <R>(ctx: Interpreter<R>) => {
|
||||
])
|
||||
|
||||
const self = (thisValue: Value, name: string) => receiver(Arr, thisValue, `Array.prototype.${name}`)
|
||||
// A mutating method fails where its first element write, delete, or `length` write would on a frozen, sealed, or
|
||||
// non-extensible array. `growth` is given by the methods that always write `length`, even when it is 0; holes a
|
||||
// method would fill on a non-extensible array are not checked.
|
||||
const mutable = (target: Arr, growth?: number): Arr => {
|
||||
const length = target.items.length
|
||||
if ((growth ?? 0) > 0) rejectAddition(target, length)
|
||||
if ((growth ?? 0) < 0 && length > 0 && !target.elements.configurable) {
|
||||
throw typeError(`Cannot delete property '${length - 1}'.`)
|
||||
}
|
||||
if (!target.elements.writable && (length > 0 || growth !== undefined)) {
|
||||
throw typeError(`Cannot assign to read only property '${length > 0 ? 0 : "length"}'.`)
|
||||
}
|
||||
return target
|
||||
}
|
||||
const optNumber = (value: Value): number | undefined => (value === undefined ? undefined : coerceToInteger(value))
|
||||
|
||||
methods(builtins, proto, [
|
||||
@@ -196,6 +211,8 @@ export const arrayGlobal = <R>(ctx: Interpreter<R>) => {
|
||||
0,
|
||||
(thisValue) => {
|
||||
const target = self(thisValue, "reverse")
|
||||
// Fewer than two elements means no writes at all, so a frozen one-element array reverses fine.
|
||||
if (target.items.length > 1) mutable(target)
|
||||
target.items.reverse()
|
||||
return target
|
||||
},
|
||||
@@ -204,7 +221,7 @@ export const arrayGlobal = <R>(ctx: Interpreter<R>) => {
|
||||
"sort",
|
||||
1,
|
||||
(thisValue, args) => {
|
||||
const target = self(thisValue, "sort")
|
||||
const target = mutable(self(thisValue, "sort"))
|
||||
const items = target.items
|
||||
const length = items.length
|
||||
const holeCount = Array.from({ length }, (_, index) => Object.hasOwn(items, index)).filter((o) => !o).length
|
||||
@@ -244,7 +261,7 @@ export const arrayGlobal = <R>(ctx: Interpreter<R>) => {
|
||||
"push",
|
||||
1,
|
||||
(thisValue, args) => {
|
||||
const target = self(thisValue, "push")
|
||||
const target = mutable(self(thisValue, "push"), args.length)
|
||||
// Validate all insertions before mutating to avoid partial cyclic updates.
|
||||
for (const item of args) rejectCircularInsertion(target, item, "Array.push result")
|
||||
return target.items.push(...args)
|
||||
@@ -254,25 +271,27 @@ export const arrayGlobal = <R>(ctx: Interpreter<R>) => {
|
||||
"unshift",
|
||||
1,
|
||||
(thisValue, args) => {
|
||||
const target = self(thisValue, "unshift")
|
||||
const target = mutable(self(thisValue, "unshift"), args.length)
|
||||
for (const item of args) rejectCircularInsertion(target, item, "Array.unshift result")
|
||||
return target.items.unshift(...args)
|
||||
},
|
||||
],
|
||||
["pop", 0, (thisValue) => self(thisValue, "pop").items.pop()],
|
||||
["shift", 0, (thisValue) => self(thisValue, "shift").items.shift()],
|
||||
["pop", 0, (thisValue) => mutable(self(thisValue, "pop"), -1).items.pop()],
|
||||
["shift", 0, (thisValue) => mutable(self(thisValue, "shift"), -1).items.shift()],
|
||||
[
|
||||
"splice",
|
||||
2,
|
||||
(thisValue, args) => {
|
||||
const target = self(thisValue, "splice")
|
||||
if (args.length === 0) return wrap(target.items.splice(0, 0))
|
||||
const length = target.items.length
|
||||
const start = optNumber(args[0]) ?? 0
|
||||
if (args.length === 1) return wrap(target.items.splice(start))
|
||||
const deleteCount = optNumber(args[1]) ?? 0
|
||||
const from = start < 0 ? Math.max(length + start, 0) : Math.min(start, length)
|
||||
const deleteCount =
|
||||
args.length === 1 ? length - from : Math.min(Math.max(optNumber(args[1]) ?? 0, 0), length - from)
|
||||
const inserted = args.slice(2)
|
||||
for (const item of inserted) rejectCircularInsertion(target, item, "Array.splice result")
|
||||
return wrap(target.items.splice(start, deleteCount, ...inserted))
|
||||
mutable(target, inserted.length - deleteCount)
|
||||
return wrap(target.items.splice(from, deleteCount, ...inserted))
|
||||
},
|
||||
],
|
||||
[
|
||||
@@ -291,7 +310,7 @@ export const arrayGlobal = <R>(ctx: Interpreter<R>) => {
|
||||
"fill",
|
||||
1,
|
||||
(thisValue, args) => {
|
||||
const target = self(thisValue, "fill")
|
||||
const target = mutable(self(thisValue, "fill"))
|
||||
rejectCircularInsertion(target, args[0], "Array.fill result")
|
||||
target.items.fill(args[0], optNumber(args[1]), optNumber(args[2]))
|
||||
return target
|
||||
@@ -301,7 +320,7 @@ export const arrayGlobal = <R>(ctx: Interpreter<R>) => {
|
||||
"copyWithin",
|
||||
2,
|
||||
(thisValue, args) => {
|
||||
const target = self(thisValue, "copyWithin")
|
||||
const target = mutable(self(thisValue, "copyWithin"))
|
||||
target.items.copyWithin(optNumber(args[0]) ?? 0, optNumber(args[1]) ?? 0, optNumber(args[2]))
|
||||
return target
|
||||
},
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
import { Effect } from "effect"
|
||||
import { constructor, methods, receiver } from "../interpreter/native.js"
|
||||
import {
|
||||
type AstNode,
|
||||
AsyncIteratorSymbol,
|
||||
invalidData,
|
||||
IteratorSymbol,
|
||||
rangeError,
|
||||
typeError,
|
||||
} from "../interpreter/model.js"
|
||||
import { type AstNode, AsyncIteratorSymbol, invalidData, IteratorSymbol, typeError } from "../interpreter/model.js"
|
||||
import {
|
||||
define,
|
||||
entries,
|
||||
@@ -18,13 +11,16 @@ import {
|
||||
hidden,
|
||||
keys,
|
||||
own,
|
||||
ownKeys,
|
||||
Arr,
|
||||
Bytes,
|
||||
Obj,
|
||||
PromiseObj,
|
||||
set,
|
||||
coerceToString,
|
||||
type Value,
|
||||
} from "../interpreter/objects.js"
|
||||
import { primitivePrototype } from "../interpreter/intrinsics.js"
|
||||
import { containsOpaqueReference, describeValue, rejectCircularInsertion } from "../interpreter/references.js"
|
||||
import { invoke, preserveConsumerError } from "../interpreter/callback.js"
|
||||
import type { Interpreter } from "../interpreter/interpreter.js"
|
||||
@@ -63,7 +59,6 @@ export const objectAssign = <R>(ctx: Interpreter<R>, args: Array<Value>): Value
|
||||
for (const key of enumerableKeys(from)) {
|
||||
rejectCircularInsertion(target, getOwn(from, key), "Object.assign result", seen)
|
||||
if (!set(target, key, getOwn(from, key))) {
|
||||
if (target instanceof Arr && key === "length") throw rangeError("Invalid array length")
|
||||
throw typeError(`Cannot assign to read only property '${String(key)}'.`)
|
||||
}
|
||||
}
|
||||
@@ -107,6 +102,34 @@ const classTag = (value: Value): string => {
|
||||
const propertyKey = (value: Value): PropertyKey =>
|
||||
value === AsyncIteratorSymbol || value === IteratorSymbol ? value : coerceToString(value)
|
||||
|
||||
// SetIntegrityLevel: primitives pass through. A typed array's bytes cannot carry attributes, so JS throws after
|
||||
// already making it non-extensible.
|
||||
const restrict = (level: "freeze" | "seal" | "preventExtensions", value: Value): Value => {
|
||||
if (!(value instanceof Obj)) return value
|
||||
value.extensible = false
|
||||
if (level === "preventExtensions") return value
|
||||
if (value instanceof Bytes && value.bytes.length > 0) {
|
||||
throw typeError(`Cannot ${level} array buffer views with elements.`)
|
||||
}
|
||||
for (const slot of value.props.values()) {
|
||||
slot.configurable = false
|
||||
if (level === "freeze" && "value" in slot) slot.writable = false
|
||||
}
|
||||
if (value instanceof Arr) value.elements = { writable: level === "seal", enumerable: true, configurable: false }
|
||||
return value
|
||||
}
|
||||
|
||||
// TestIntegrityLevel: array elements and `length` answer through `own`, so a non-extensible empty array is sealed
|
||||
// but not frozen, as in JS.
|
||||
const integrity = (value: Value, frozen: boolean): boolean => {
|
||||
if (!(value instanceof Obj)) return true
|
||||
if (value.extensible) return false
|
||||
return ownKeys(value).every((key) => {
|
||||
const slot = own(value, key)
|
||||
return slot !== undefined && !slot.configurable && !(frozen && "value" in slot && slot.writable)
|
||||
})
|
||||
}
|
||||
|
||||
// Object constructs identically with or without new, like JS. Only `keys` copies its result into the
|
||||
// program; `values`, `entries`, `assign`, and `fromEntries` hand back the program's own values.
|
||||
export const objectGlobal = <R>(ctx: Interpreter<R>) => {
|
||||
@@ -157,6 +180,39 @@ export const objectGlobal = <R>(ctx: Interpreter<R>) => {
|
||||
["is", 2, (_, args) => Object.is(args[0], args[1])],
|
||||
["assign", 2, (_, args) => objectAssign(ctx, args)],
|
||||
["fromEntries", 1, (_, args) => objectFromEntries(ctx, args[0])],
|
||||
["freeze", 1, (_, args) => restrict("freeze", args[0])],
|
||||
["seal", 1, (_, args) => restrict("seal", args[0])],
|
||||
["preventExtensions", 1, (_, args) => restrict("preventExtensions", args[0])],
|
||||
["isFrozen", 1, (_, args) => integrity(args[0], true)],
|
||||
["isSealed", 1, (_, args) => integrity(args[0], false)],
|
||||
["isExtensible", 1, (_, args) => args[0] instanceof Obj && args[0].extensible],
|
||||
[
|
||||
"getPrototypeOf",
|
||||
1,
|
||||
(_, args) => {
|
||||
if (args[0] instanceof Obj) return args[0].proto
|
||||
const proto = primitivePrototype(builtins, args[0])
|
||||
if (proto === undefined) {
|
||||
throw typeError(`Object.getPrototypeOf cannot convert ${describeValue(args[0])} to an object.`)
|
||||
}
|
||||
return proto
|
||||
},
|
||||
],
|
||||
[
|
||||
"create",
|
||||
2,
|
||||
(_, args) => {
|
||||
if (args[0] !== null && !(args[0] instanceof Obj)) {
|
||||
throw typeError("Object prototype may only be an Object or null.")
|
||||
}
|
||||
if (args[1] !== undefined) {
|
||||
throw typeError(
|
||||
"Object.create property descriptors are not supported; assign the fields after creating the object.",
|
||||
)
|
||||
}
|
||||
return new Obj(args[0])
|
||||
},
|
||||
],
|
||||
])
|
||||
define(object, "groupBy", groupBy(ctx, "Object"), hidden)
|
||||
methods(builtins, builtins.Object, [
|
||||
|
||||
@@ -1,8 +1,28 @@
|
||||
import { fn, methods } from "../interpreter/native.js"
|
||||
import { typeError } from "../interpreter/model.js"
|
||||
import { Bytes, Obj, coerceToString } from "../interpreter/objects.js"
|
||||
import {
|
||||
define,
|
||||
entries,
|
||||
get,
|
||||
getOwn,
|
||||
hasOwn,
|
||||
hidden,
|
||||
isRuntimeReference,
|
||||
Arr,
|
||||
Bytes,
|
||||
DateObj,
|
||||
ErrorObj,
|
||||
MapObj,
|
||||
Obj,
|
||||
RegExpObj,
|
||||
SetObj,
|
||||
coerceToString,
|
||||
type Value,
|
||||
} from "../interpreter/objects.js"
|
||||
import { createErrorValue, isErrorType } from "../interpreter/intrinsics.js"
|
||||
import { describeValue } from "../interpreter/references.js"
|
||||
import type { Interpreter } from "../interpreter/interpreter.js"
|
||||
import { ToolReference } from "../tool-runtime.js"
|
||||
|
||||
// WebIDL DOMString conversion: a missing argument is a TypeError, anything else stringifies. Invalid input is a
|
||||
// TypeError as well; browsers throw a DOMException named InvalidCharacterError, which CodeMode does not have.
|
||||
@@ -17,6 +37,63 @@ export const base64Global = <R>(ctx: Interpreter<R>, name: "atob" | "btoa") =>
|
||||
}
|
||||
})
|
||||
|
||||
// HTML structured clone over CodeMode's data kinds. Shared references survive through the memo; prototypes and
|
||||
// frozen state do not, as in JS. Without a DOMException, DataCloneError is a TypeError carrying that prefix.
|
||||
export const structuredCloneGlobal = <R>(ctx: Interpreter<R>) =>
|
||||
fn<R>(ctx.builtins, "structuredClone", 1, (_, args) => {
|
||||
if (args.length === 0) throw typeError("structuredClone requires 1 argument")
|
||||
const builtins = ctx.builtins
|
||||
const memo = new Map<Obj, Obj>()
|
||||
const clone = (value: Value): Value => {
|
||||
if (typeof value === "symbol" || value instanceof ToolReference) {
|
||||
throw typeError(`DataCloneError: ${describeValue(value)} could not be cloned.`)
|
||||
}
|
||||
if (!(value instanceof Obj)) return value
|
||||
const seen = memo.get(value)
|
||||
if (seen !== undefined) return seen
|
||||
const remember = <T extends Obj>(copy: T): T => {
|
||||
memo.set(value, copy)
|
||||
return copy
|
||||
}
|
||||
if (value instanceof MapObj) {
|
||||
const copy = remember(new MapObj(builtins.Map))
|
||||
for (const [key, item] of value.map) copy.map.set(clone(key), clone(item))
|
||||
return copy
|
||||
}
|
||||
if (value instanceof SetObj) {
|
||||
const copy = remember(new SetObj(builtins.Set))
|
||||
for (const item of value.set) copy.set.add(clone(item))
|
||||
return copy
|
||||
}
|
||||
if (value instanceof DateObj) return remember(new DateObj(builtins.Date, value.time))
|
||||
if (value instanceof RegExpObj) {
|
||||
return remember(new RegExpObj(builtins.RegExp, value.regex.source, value.regex.flags))
|
||||
}
|
||||
if (value instanceof Bytes) return remember(new Bytes(builtins.Uint8Array, new Uint8Array(value.bytes)))
|
||||
if (value instanceof ErrorObj) {
|
||||
const name = get(value, "name")
|
||||
const message = get(value, "message")
|
||||
const copy = remember(
|
||||
createErrorValue(
|
||||
builtins[typeof name === "string" && isErrorType(name) ? name : "Error"],
|
||||
message === undefined ? undefined : coerceToString(message),
|
||||
),
|
||||
)
|
||||
const stack = getOwn(value, "stack")
|
||||
if (typeof stack === "string") define(copy, "stack", stack, hidden)
|
||||
if (hasOwn(value, "cause")) define(copy, "cause", clone(getOwn(value, "cause")), hidden)
|
||||
return copy
|
||||
}
|
||||
if (isRuntimeReference(value)) throw typeError(`DataCloneError: ${describeValue(value)} could not be cloned.`)
|
||||
const copy = remember(
|
||||
value instanceof Arr ? new Arr(builtins.Array, new Array(value.items.length)) : new Obj(builtins.Object),
|
||||
)
|
||||
for (const [key, item] of entries(value)) define(copy, key, clone(item))
|
||||
return copy
|
||||
}
|
||||
return clone(args[0])
|
||||
})
|
||||
|
||||
export const cryptoGlobal = <R>(ctx: Interpreter<R>) => {
|
||||
const object = new Obj(ctx.builtins.Object)
|
||||
methods(ctx.builtins, object, [
|
||||
|
||||
@@ -1231,3 +1231,233 @@ describe("loose equality and operator gates on opaque references", () => {
|
||||
).toEqual(["1,2", null, "[object Function]", true, true, "function", false])
|
||||
})
|
||||
})
|
||||
|
||||
describe("Object.freeze, seal, and preventExtensions", () => {
|
||||
test("a frozen object rejects writes, additions, and deletes with TypeErrors", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const o = Object.freeze({ a: 1 })
|
||||
const errors = []
|
||||
try { o.a = 2 } catch (e) { errors.push(e.name + ": " + e.message) }
|
||||
try { o.b = 2 } catch (e) { errors.push(e.name + ": " + e.message) }
|
||||
try { delete o.a } catch (e) { errors.push(e.name + ": " + e.message) }
|
||||
return [errors, o.a, Object.isFrozen(o), Object.isSealed(o), Object.isExtensible(o)]
|
||||
`),
|
||||
).toEqual([
|
||||
[
|
||||
"TypeError: Cannot assign to read only property 'a'.",
|
||||
"TypeError: Cannot add property b, object is not extensible.",
|
||||
"TypeError: Cannot delete property 'a'.",
|
||||
],
|
||||
1,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
])
|
||||
})
|
||||
|
||||
test("seal keeps writes, preventExtensions keeps deletes, and each returns its argument", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const s = { a: 1 }, p = { a: 1 }
|
||||
const errors = []
|
||||
Object.seal(s).a = 2
|
||||
try { delete s.a } catch (e) { errors.push(e.name) }
|
||||
delete Object.preventExtensions(p).a
|
||||
try { p.b = 1 } catch (e) { errors.push(e.name) }
|
||||
return [errors, s.a, Object.keys(p), Object.isSealed(s), Object.isFrozen(s), Object.isSealed(p), Object.isFrozen(p)]
|
||||
`),
|
||||
).toEqual([["TypeError", "TypeError"], 2, [], true, false, true, true])
|
||||
})
|
||||
|
||||
test("primitives pass through, and Object.assign honors the flags", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
return [Object.freeze(1) === 1, Object.isFrozen(1), Object.isSealed("a"), Object.isExtensible(null), Object.isFrozen({}), Object.isExtensible({})]
|
||||
`),
|
||||
).toEqual([true, true, true, false, false, true])
|
||||
const failure = await error(`Object.assign(Object.freeze({ a: 1 }), { b: 1 })`)
|
||||
expect(failure.message).toContain("Cannot add property b, object is not extensible")
|
||||
})
|
||||
|
||||
test("frozen arrays reject element, length, and mutating-method writes like JS", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const a = Object.freeze([1, 2])
|
||||
const attempt = (f) => { try { f(); return "ok" } catch (e) { return e.name + ": " + e.message } }
|
||||
return [
|
||||
attempt(() => a.push(3)),
|
||||
attempt(() => { a[0] = 9 }),
|
||||
attempt(() => { a[5] = 9 }),
|
||||
attempt(() => { a.length = 0 }),
|
||||
attempt(() => a.pop()),
|
||||
attempt(() => a.sort()),
|
||||
attempt(() => a.reverse()),
|
||||
attempt(() => a.fill(0)),
|
||||
attempt(() => a.copyWithin(0, 1)),
|
||||
attempt(() => a.splice(0, 1)),
|
||||
attempt(() => a.unshift(0)),
|
||||
a, a.map((x) => x * 2), Object.isFrozen(a), Object.isFrozen(Object.freeze([])),
|
||||
]
|
||||
`),
|
||||
).toEqual([
|
||||
"TypeError: Cannot add property 2, object is not extensible.",
|
||||
"TypeError: Cannot assign to read only property '0'.",
|
||||
"TypeError: Cannot add property 5, object is not extensible.",
|
||||
"TypeError: Cannot assign to read only property 'length'.",
|
||||
"TypeError: Cannot delete property '1'.",
|
||||
"TypeError: Cannot assign to read only property '0'.",
|
||||
"TypeError: Cannot assign to read only property '0'.",
|
||||
"TypeError: Cannot assign to read only property '0'.",
|
||||
"TypeError: Cannot assign to read only property '0'.",
|
||||
"TypeError: Cannot delete property '1'.",
|
||||
"TypeError: Cannot add property 2, object is not extensible.",
|
||||
[1, 2],
|
||||
[2, 4],
|
||||
true,
|
||||
true,
|
||||
])
|
||||
})
|
||||
|
||||
test("sealed and non-extensible arrays allow exactly the writes JS does", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const s = Object.seal([1, 2]), p = Object.preventExtensions([1, 2, 3])
|
||||
const attempt = (f) => { try { f(); return "ok" } catch (e) { return e.name } }
|
||||
const results = [attempt(() => { s[0] = 5 }), attempt(() => s.pop()), attempt(() => { s.length = 0 }), attempt(() => s.push(1))]
|
||||
p.pop(); p.sort(); p.reverse(); p.fill(0, 1); p.copyWithin(0, 1); p.length = 5
|
||||
results.push(attempt(() => p.push(1)), attempt(() => p.splice(0, 1, 7, 8)), p.splice(0, 1, 7), attempt(() => { p[9] = 1 }))
|
||||
return [results, s, p, Object.isSealed(p), Object.isFrozen(p), Object.isSealed(Object.preventExtensions([])), Object.isFrozen(Object.preventExtensions([]))]
|
||||
`),
|
||||
).toEqual([
|
||||
["ok", "TypeError", "TypeError", "TypeError", "TypeError", "TypeError", [0], "TypeError"],
|
||||
[5, 2],
|
||||
[7, 0, null, null, null],
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
])
|
||||
})
|
||||
|
||||
test("typed arrays with elements cannot be frozen; wrappers freeze their properties only", async () => {
|
||||
const failure = await error(`Object.freeze(new Uint8Array([1]))`)
|
||||
expect(failure.message).toContain("Cannot freeze array buffer views with elements")
|
||||
expect(
|
||||
await value(`
|
||||
const empty = Object.freeze(new Uint8Array(0))
|
||||
const bytes = Object.preventExtensions(new Uint8Array([1]))
|
||||
const m = Object.freeze(new Map()); m.set(1, 2)
|
||||
const f = Object.freeze(() => 1)
|
||||
let named = "ok"
|
||||
try { f.x = 1 } catch (e) { named = e.name }
|
||||
return [Object.isFrozen(empty), Object.isFrozen(bytes), Object.isExtensible(bytes), m.size, Object.isFrozen(f), named, f()]
|
||||
`),
|
||||
).toEqual([true, false, false, 1, true, "TypeError", 1])
|
||||
})
|
||||
})
|
||||
|
||||
describe("Object.getPrototypeOf and Object.create", () => {
|
||||
test("getPrototypeOf returns the built-in prototypes for objects and primitives", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
return [
|
||||
Object.getPrototypeOf([]) === Array.prototype,
|
||||
Object.getPrototypeOf({}) === Object.prototype,
|
||||
Object.getPrototypeOf(Object.prototype),
|
||||
Object.getPrototypeOf("a") === String.prototype,
|
||||
Object.getPrototypeOf(1) === Number.prototype,
|
||||
Object.getPrototypeOf(true) === Boolean.prototype,
|
||||
Object.getPrototypeOf(new TypeError("x")) === TypeError.prototype,
|
||||
Object.getPrototypeOf(TypeError.prototype) === Error.prototype,
|
||||
Object.getPrototypeOf(() => 1) === Function.prototype,
|
||||
]
|
||||
`),
|
||||
).toEqual([true, true, null, true, true, true, true, true, true])
|
||||
})
|
||||
|
||||
test("getPrototypeOf rejects null, undefined, and symbols", async () => {
|
||||
expect((await error(`Object.getPrototypeOf(null)`)).message).toContain("cannot convert null to an object")
|
||||
expect((await error(`Object.getPrototypeOf(undefined)`)).message).toContain("cannot convert undefined to an object")
|
||||
expect((await error(`Object.getPrototypeOf(Symbol.iterator)`)).message).toContain("cannot convert a symbol")
|
||||
})
|
||||
|
||||
test("Object.create links the prototype: inherited reads, in, and own-only keys", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const p = { greet(name) { return "hi " + name }, a: 1 }
|
||||
const c = Object.create(p)
|
||||
c.name = "x"
|
||||
const seen = []
|
||||
for (const key in c) seen.push(key)
|
||||
return ["greet" in c, Object.keys(c), c.hasOwnProperty("a"), c.a, c.greet(c.name), Object.getPrototypeOf(c) === p, Object.getPrototypeOf(Object.create(null)), seen]
|
||||
`),
|
||||
).toEqual([true, ["name"], false, 1, "hi x", true, null, ["name"]])
|
||||
})
|
||||
|
||||
test("Object.create rejects non-object prototypes and property descriptors", async () => {
|
||||
expect((await error(`Object.create(1)`)).message).toContain("Object prototype may only be an Object or null")
|
||||
expect((await error(`Object.create()`)).message).toContain("Object prototype may only be an Object or null")
|
||||
expect((await error(`Object.create(null, { a: { value: 1 } })`)).message).toContain(
|
||||
"Object.create property descriptors are not supported",
|
||||
)
|
||||
expect(await value(`return Object.keys(Object.create({}, undefined))`)).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe("structuredClone", () => {
|
||||
test("deep-copies data values and keeps shared references shared", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const shared = { n: 1 }
|
||||
const source = { a: shared, b: shared, list: [1, , shared], map: new Map([[1, { a: [1, 2] }]]), set: new Set([shared]), when: new Date(5), bytes: new Uint8Array([1, 2]) }
|
||||
const c = structuredClone(source)
|
||||
c.a.n = 2
|
||||
return [
|
||||
c !== source, c.a === c.b, c.a !== shared, shared.n, c.list[2] === c.a, 1 in c.list, c.list.length,
|
||||
c.map.get(1).a, c.map !== source.map, c.set.has(c.a), c.when.getTime(), c.when instanceof Date,
|
||||
c.bytes instanceof Uint8Array, c.bytes[1], Array.isArray(c.list),
|
||||
]
|
||||
`),
|
||||
).toEqual([true, true, true, 1, true, false, 3, [1, 2], true, true, 5, true, true, 2, true])
|
||||
})
|
||||
|
||||
test("regexps reset lastIndex, errors keep name, message, and cause, and extras are dropped", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const r = /a/g
|
||||
r.lastIndex = 3
|
||||
const e = new TypeError("boom", { cause: { code: 1 } })
|
||||
e.extra = 1
|
||||
const custom = new Error("x")
|
||||
custom.name = "Custom"
|
||||
const [cr, ce, cc] = [structuredClone(r), structuredClone(e), structuredClone(custom)]
|
||||
return [cr.source, cr.flags, cr.lastIndex, ce instanceof TypeError, ce.name, ce.message, ce.cause, ce.cause !== e.cause, ce.extra, Object.keys(ce), cc.name]
|
||||
`),
|
||||
).toEqual(["a", "g", 0, true, "TypeError", "boom", { code: 1 }, true, null, [], "Error"])
|
||||
})
|
||||
|
||||
test("the clone is a plain extensible object: prototypes, symbols, undefined fields, and frozen state drop", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const c = structuredClone(Object.freeze(Object.assign(Object.create({ inherited: 1 }), { a: undefined, [Symbol.iterator]: 1, b: 2 })))
|
||||
return [Object.isFrozen(c), Object.getPrototypeOf(c) === Object.prototype, "a" in c, Symbol.iterator in c, c.b, c.inherited]
|
||||
`),
|
||||
).toEqual([false, true, true, false, 2, null])
|
||||
})
|
||||
|
||||
test("functions, symbols, promises, wrappers, and tool references throw a DataCloneError TypeError", async () => {
|
||||
for (const code of [
|
||||
`structuredClone(() => 1)`,
|
||||
`structuredClone({ deep: [Symbol.iterator] })`,
|
||||
`structuredClone(Promise.resolve(1))`,
|
||||
`structuredClone(new URL("http://x"))`,
|
||||
`structuredClone(tools)`,
|
||||
]) {
|
||||
const failure = await error(code)
|
||||
expect(failure.message).toMatch(/^TypeError: DataCloneError: .* could not be cloned\./)
|
||||
}
|
||||
expect(await value(`try { structuredClone(() => 1) } catch (e) { return e.name }`)).toBe("TypeError")
|
||||
expect((await error(`structuredClone()`)).message).toContain("structuredClone requires 1 argument")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -24,7 +24,7 @@ Without them the runner registers no tests, so CI is unaffected. Licensed under
|
||||
|
||||
`script/sync-test262.ts` skips a file when its frontmatter declares a `flags`, `features`, or `includes` value the
|
||||
manifest marks unsupported, or when its code matches one of the manifest's `boundaries` patterns. The sync checks the
|
||||
checkout is at the pinned revision, so every machine runs the same 4478 files. Boundaries are
|
||||
checkout is at the pinned revision, so every machine runs the same 4595 files. Boundaries are
|
||||
intentional limits of the interpreter, not compatibility work: classes, `this`, `arguments`, prototype objects,
|
||||
property descriptors, accessors, boxed primitives, sloppy mode, `eval`, `Symbol()`, and the `$262` host API. If one
|
||||
of those decisions changes, delete its entry and re-sync; the tests are upstream, not lost.
|
||||
|
||||
@@ -3,7 +3,13 @@
|
||||
"directories": [
|
||||
"built-ins/Array/prototype",
|
||||
"built-ins/Iterator",
|
||||
"built-ins/Object/freeze",
|
||||
"built-ins/Object/getPrototypeOf",
|
||||
"built-ins/Object/is",
|
||||
"built-ins/Object/isExtensible",
|
||||
"built-ins/Object/isFrozen",
|
||||
"built-ins/Object/isSealed",
|
||||
"built-ins/Object/preventExtensions",
|
||||
"built-ins/String/raw",
|
||||
"language/expressions/does-not-equals",
|
||||
"language/expressions/equals",
|
||||
@@ -18,7 +24,7 @@
|
||||
"arguments": "\\barguments\\b",
|
||||
"call/apply/bind": "\\.(call|apply|bind)\\s*\\(",
|
||||
"accessor properties": "\\b(get|set)\\s+[\\w$\\[][^\\n(]*\\(",
|
||||
"property descriptors": "Object\\.(defineProperty|defineProperties|getOwnPropertyDescriptors?|getOwnPropertyNames|create|getPrototypeOf|setPrototypeOf|freeze|seal|preventExtensions|isFrozen|isSealed|isExtensible)\\b",
|
||||
"property descriptors": "Object\\.(defineProperty|defineProperties|getOwnPropertyDescriptors?|getOwnPropertyNames|setPrototypeOf)\\b",
|
||||
"boxed primitives": "\\bnew\\s+(String|Number|Boolean)\\s*\\(",
|
||||
"sloppy mode": "\\bwith\\s*\\(",
|
||||
"eval": "\\b(eval|Function)\\b",
|
||||
|
||||
@@ -194,6 +194,7 @@ built-ins/Array/prototype/unshift/S15.4.4.13_A3_T2.js # Array.prototype.unshift
|
||||
built-ins/Array/prototype/unshift/S15.4.4.13_A4_T1.js # Array.prototype.unshift called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/unshift/S15.4.4.13_A4_T2.js # #3: Array.prototype[0] = 1; x = []; x.length = 1; x.unshift(0); x[1] === 1. Actual: undefined
|
||||
built-ins/Iterator/from/return-method-returns-iterator-result.js # Iterator next must be a function.
|
||||
built-ins/Iterator/prototype/Symbol.iterator/is-function.js # every built-in collection iterator shares one prototype, so its parent is Object.prototype
|
||||
built-ins/Iterator/prototype/drop/limit-tonumber-throws.js # Expected a Test262Error but got a RangeError
|
||||
built-ins/Iterator/prototype/drop/limit-tonumber.js # Iterator.prototype.drop expects a non-negative count, received NaN.
|
||||
built-ins/Iterator/prototype/take/limit-tonumber-throws.js # Expected a Test262Error but got a RangeError
|
||||
@@ -205,6 +206,20 @@ language/expressions/does-not-equals/S11.9.2_A7.9.js # #1: ({valueOf: function(
|
||||
language/expressions/equals/S11.9.1_A7.8.js # #1: ({valueOf: function() {return 1}} == true) === true
|
||||
language/expressions/equals/S11.9.1_A7.9.js # #1: (true == {valueOf: function() {return 1}}) === true
|
||||
language/expressions/equals/S9.1_A1_T3.js # #1: var object = {valueOf: function() {return 1}, toString: function() {return 0}}; object + "" ===
|
||||
built-ins/Object/freeze/throws-when-false.js # Unknown identifier 'Proxy'.
|
||||
built-ins/Object/getPrototypeOf/15.2.3.2-2-12.js # Object.getPrototypeOf(EvalError) Expected SameValue(«», «Error») to be true
|
||||
built-ins/Object/getPrototypeOf/15.2.3.2-2-13.js # Object.getPrototypeOf(RangeError) Expected SameValue(«», «Error») to be true
|
||||
built-ins/Object/getPrototypeOf/15.2.3.2-2-14.js # Object.getPrototypeOf(ReferenceError) Expected SameValue(«», «Error») to be true
|
||||
built-ins/Object/getPrototypeOf/15.2.3.2-2-15.js # Object.getPrototypeOf(SyntaxError) Expected SameValue(«», «Error») to be true
|
||||
built-ins/Object/getPrototypeOf/15.2.3.2-2-16.js # Object.getPrototypeOf(TypeError) Expected SameValue(«», «Error») to be true
|
||||
built-ins/Object/getPrototypeOf/15.2.3.2-2-17.js # Object.getPrototypeOf(URIError) Expected SameValue(«», «Error») to be true
|
||||
built-ins/Object/getPrototypeOf/15.2.3.2-2-2.js # … cannot be constructed: user-defined constructors and classes are not supported.
|
||||
built-ins/Object/isExtensible/15.2.3.13-2-24.js # … cannot be constructed: user-defined constructors and classes are not supported.
|
||||
built-ins/Object/isExtensible/15.2.3.13-2-25.js # … cannot be constructed: user-defined constructors and classes are not supported.
|
||||
built-ins/Object/isExtensible/15.2.3.13-2-26.js # … cannot be constructed: user-defined constructors and classes are not supported.
|
||||
built-ins/Object/isExtensible/15.2.3.13-2-27.js # … cannot be constructed: user-defined constructors and classes are not supported.
|
||||
built-ins/Object/preventExtensions/15.2.3.10-3-24.js # … cannot be constructed: user-defined constructors and classes are not supported.
|
||||
built-ins/Object/preventExtensions/throws-when-false.js # Unknown identifier 'Proxy'.
|
||||
language/expressions/tagged-template/constructor-invocation.js # The called value cannot be constructed: user-defined constructors and classes are not supported.
|
||||
language/expressions/tagged-template/template-object-frozen-strict.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/async-generator/dstr/ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
@@ -221,6 +236,8 @@ language/statements/for-await-of/async-gen-decl-dstr-obj-empty-num.js # TypeErr
|
||||
language/statements/for-await-of/async-gen-decl-dstr-obj-empty-string.js # TypeError: Object destructuring requires a data object or array value, received a string.
|
||||
language/statements/for-await-of/async-gen-decl-dstr-obj-rest-number.js # TypeError: Object destructuring requires a data object or array value, received a number.
|
||||
language/statements/for-await-of/async-gen-decl-dstr-obj-rest-str-val.js # TypeError: Object destructuring requires a data object or array value, received a string.
|
||||
language/statements/for-in/S12.6.4_A7_T2.js # for...in visits keys deleted during the loop
|
||||
language/statements/for-in/order-enumerable-shadowed.js # Object.create property descriptors are not supported; assign the fields after creating the object.
|
||||
language/statements/for-of/dstr/array-elem-iter-rtrn-close-err.js # Iterator next must be a function.
|
||||
language/statements/for-of/dstr/array-elem-iter-thrw-close-err.js # Expected SameValue(«1», «0») to be true
|
||||
language/statements/for-of/dstr/array-elem-trlg-iter-list-thrw-close-err.js # Expected SameValue(«1», «0») to be true
|
||||
@@ -258,8 +275,10 @@ language/statements/function/S13.2_A4_T1.js # Unknown identifier '…'.
|
||||
language/statements/function/S13.2_A4_T2.js # #1: typeof __gunc.prototype === '…'. Actual: typeof __gunc.prototype ===undefined
|
||||
language/statements/function/dstr/ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/function/dstr/dflt-ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/generators/default-proto.js # generator functions have no GeneratorFunction.prototype
|
||||
language/statements/generators/dstr/ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/generators/dstr/dflt-ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/generators/prototype-relation-to-function.js # generator functions have no GeneratorFunction.prototype
|
||||
language/statements/labeled/value-await-non-module.js # Failed to parse TypeScript: Expression expected.
|
||||
language/statements/let/dstr/ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/return/S12.9_A1_T1.js # expected SyntaxError but the program ran
|
||||
|
||||
Reference in New Issue
Block a user