Skip to content

Commit a72567a

Browse files
authored
Fix Iterator.prototype.constructor (#1060)
TC39 in its wisdom decided the property should be an accessor with a setter that enforces certain properties on the set value. Make it so.
1 parent ed2ff1e commit a72567a

File tree

2 files changed

+34
-4
lines changed

2 files changed

+34
-4
lines changed

quickjs.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ struct JSContext {
454454
JSValue error_prepare_stack;
455455
JSValue error_stack_trace_limit;
456456
JSValue iterator_ctor;
457+
JSValue iterator_ctor_getset;
457458
JSValue iterator_proto;
458459
JSValue async_iterator_proto;
459460
JSValue array_proto_values;
@@ -2303,6 +2304,7 @@ JSContext *JS_NewContextRaw(JSRuntime *rt)
23032304
ctx->class_proto[i] = JS_NULL;
23042305
ctx->array_ctor = JS_NULL;
23052306
ctx->iterator_ctor = JS_NULL;
2307+
ctx->iterator_ctor_getset = JS_NULL;
23062308
ctx->regexp_ctor = JS_NULL;
23072309
ctx->promise_ctor = JS_NULL;
23082310
ctx->error_ctor = JS_NULL;
@@ -2433,6 +2435,7 @@ static void JS_MarkContext(JSRuntime *rt, JSContext *ctx,
24332435
JS_MarkValue(rt, ctx->class_proto[i], mark_func);
24342436
}
24352437
JS_MarkValue(rt, ctx->iterator_ctor, mark_func);
2438+
JS_MarkValue(rt, ctx->iterator_ctor_getset, mark_func);
24362439
JS_MarkValue(rt, ctx->async_iterator_proto, mark_func);
24372440
JS_MarkValue(rt, ctx->promise_ctor, mark_func);
24382441
JS_MarkValue(rt, ctx->array_ctor, mark_func);
@@ -2503,6 +2506,7 @@ void JS_FreeContext(JSContext *ctx)
25032506
}
25042507
js_free_rt(rt, ctx->class_proto);
25052508
JS_FreeValue(ctx, ctx->iterator_ctor);
2509+
JS_FreeValue(ctx, ctx->iterator_ctor_getset);
25062510
JS_FreeValue(ctx, ctx->async_iterator_proto);
25072511
JS_FreeValue(ctx, ctx->promise_ctor);
25082512
JS_FreeValue(ctx, ctx->array_ctor);
@@ -41672,6 +41676,26 @@ static const JSCFunctionListEntry js_iterator_wrap_proto_funcs[] = {
4167241676
JS_ITERATOR_NEXT_DEF("return", 0, js_iterator_wrap_next, GEN_MAGIC_RETURN ),
4167341677
};
4167441678

41679+
static JSValue js_iterator_constructor_getset(JSContext *ctx,
41680+
JSValueConst this_val,
41681+
int argc, JSValueConst *argv,
41682+
int magic,
41683+
JSValueConst *func_data)
41684+
{
41685+
int ret;
41686+
41687+
if (argc > 0) { // if setter
41688+
if (!JS_IsObject(argv[0]))
41689+
return JS_ThrowTypeErrorNotAnObject(ctx);
41690+
ret = JS_DefinePropertyValue(ctx, this_val, JS_ATOM_constructor,
41691+
js_dup(argv[0]),
41692+
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
41693+
if (ret < 0)
41694+
return JS_EXCEPTION;
41695+
}
41696+
return js_dup(func_data[0]);
41697+
}
41698+
4167541699
static JSValue js_iterator_constructor(JSContext *ctx, JSValueConst new_target,
4167641700
int argc, JSValueConst *argv)
4167741701
{
@@ -53275,6 +53299,16 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
5327553299
countof(js_iterator_proto_funcs));
5327653300
obj = JS_NewGlobalCConstructor(ctx, "Iterator", js_iterator_constructor, 0,
5327753301
ctx->class_proto[JS_CLASS_ITERATOR]);
53302+
// quirk: Iterator.prototype.constructor is an accessor property
53303+
// TODO(bnoordhuis) mildly inefficient because JS_NewGlobalCConstructor
53304+
// first creates a .constructor value property that we then replace with
53305+
// an accessor
53306+
ctx->iterator_ctor_getset = JS_NewCFunctionData(ctx, js_iterator_constructor_getset,
53307+
0, 0, 1, vc(&obj));
53308+
JS_DefineProperty(ctx, ctx->class_proto[JS_CLASS_ITERATOR],
53309+
JS_ATOM_constructor, JS_UNDEFINED,
53310+
ctx->iterator_ctor_getset, ctx->iterator_ctor_getset,
53311+
JS_PROP_HAS_GET|JS_PROP_HAS_SET|JS_PROP_WRITABLE|JS_PROP_CONFIGURABLE);
5327853312
ctx->iterator_ctor = js_dup(obj);
5327953313
JS_SetPropertyFunctionList(ctx, obj,
5328053314
js_iterator_funcs,

test262_errors.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,6 @@ test262/test/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-retu
2424
test262/test/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-not-object.js:72: strict mode: TypeError: $DONE() not called
2525
test262/test/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-object.js:66: TypeError: $DONE() not called
2626
test262/test/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-undefined-return-object.js:66: strict mode: TypeError: $DONE() not called
27-
test262/test/built-ins/Iterator/prototype/constructor/prop-desc.js:10: Test262Error: Expected SameValue(«"undefined"», «"function"») to be true
28-
test262/test/built-ins/Iterator/prototype/constructor/prop-desc.js:10: strict mode: Test262Error: Expected SameValue(«"undefined"», «"function"») to be true
29-
test262/test/built-ins/Iterator/prototype/constructor/weird-setter.js:23: TypeError: cannot read property 'call' of undefined
30-
test262/test/built-ins/Iterator/prototype/constructor/weird-setter.js:23: strict mode: TypeError: cannot read property 'call' of undefined
3127
test262/test/built-ins/Object/defineProperties/typedarray-backed-by-resizable-buffer.js:20: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
3228
test262/test/built-ins/Object/defineProperties/typedarray-backed-by-resizable-buffer.js:20: strict mode: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
3329
test262/test/built-ins/Object/defineProperty/coerced-P-grow.js:45: TypeError: out-of-bound index in typed array

0 commit comments

Comments
 (0)