diff --git a/quickjs.c b/quickjs.c index 118251613..913b03dfc 100644 --- a/quickjs.c +++ b/quickjs.c @@ -7232,6 +7232,25 @@ static JSValue JS_ThrowStackOverflow(JSContext *ctx) return JS_ThrowRangeError(ctx, "Maximum call stack size exceeded"); } +static JSValue JS_ThrowTypeErrorNotAConstructor(JSContext *ctx, + JSValueConst func_obj) +{ + JSObject *p; + JSAtom name; + + if (JS_TAG_OBJECT != JS_VALUE_GET_TAG(func_obj)) + goto fini; + p = JS_VALUE_GET_OBJ(func_obj); + if (!js_class_has_bytecode(p->class_id)) + goto fini; + name = p->u.func.function_bytecode->func_name; + if (name == JS_ATOM_NULL) + goto fini; + return JS_ThrowTypeErrorAtom(ctx, "%s is not a constructor", name); +fini: + return JS_ThrowTypeError(ctx, "not a constructor"); +} + static JSValue JS_ThrowTypeErrorNotAFunction(JSContext *ctx) { return JS_ThrowTypeError(ctx, "not a function"); @@ -18822,7 +18841,7 @@ static JSValue JS_CallConstructorInternal(JSContext *ctx, goto not_a_function; p = JS_VALUE_GET_OBJ(func_obj); if (unlikely(!p->is_constructor)) - return JS_ThrowTypeError(ctx, "not a constructor"); + return JS_ThrowTypeErrorNotAConstructor(ctx, func_obj); if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) { JSClassCall *call_func; call_func = ctx->rt->class_array[p->class_id].call; @@ -38668,8 +38687,9 @@ static JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj, if (JS_IsUndefined(species) || JS_IsNull(species)) return js_dup(defaultConstructor); if (!JS_IsConstructor(ctx, species)) { + JS_ThrowTypeErrorNotAConstructor(ctx, species); JS_FreeValue(ctx, species); - return JS_ThrowTypeError(ctx, "not a constructor"); + return JS_EXCEPTION; } return species; } @@ -47555,7 +47575,7 @@ static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val, if (argc > 2) { new_target = argv[2]; if (!JS_IsConstructor(ctx, new_target)) - return JS_ThrowTypeError(ctx, "not a constructor"); + return JS_ThrowTypeErrorNotAConstructor(ctx, new_target); } else { new_target = func; } @@ -48475,7 +48495,7 @@ static JSValue js_proxy_call_constructor(JSContext *ctx, JSValueConst func_obj, if (!s) return JS_EXCEPTION; if (!JS_IsConstructor(ctx, s->target)) - return JS_ThrowTypeError(ctx, "not a constructor"); + return JS_ThrowTypeErrorNotAConstructor(ctx, s->target); if (JS_IsUndefined(method)) return JS_CallConstructor2(ctx, s->target, new_target, argc, argv); arg_array = js_create_array(ctx, argc, argv); @@ -48707,7 +48727,7 @@ static JSValue js_symbol_constructor(JSContext *ctx, JSValueConst new_target, JSString *p; if (!JS_IsUndefined(new_target)) - return JS_ThrowTypeError(ctx, "not a constructor"); + return JS_ThrowTypeErrorNotAConstructor(ctx, new_target); if (argc == 0 || JS_IsUndefined(argv[0])) { p = NULL; } else { @@ -53317,7 +53337,7 @@ static JSValue js_bigint_constructor(JSContext *ctx, int argc, JSValueConst *argv) { if (!JS_IsUndefined(new_target)) - return JS_ThrowTypeError(ctx, "not a constructor"); + return JS_ThrowTypeErrorNotAConstructor(ctx, new_target); return JS_ToBigIntCtorFree(ctx, js_dup(argv[0])); } diff --git a/tests/test_language.js b/tests/test_language.js index dbb4947c7..3a56117a5 100644 --- a/tests/test_language.js +++ b/tests/test_language.js @@ -259,6 +259,15 @@ function test_delete() assert(err, true, "delete"); } +function test_constructor() +{ + function *G() {} + let ex + try { new G() } catch (ex_) { ex = ex_ } + assert(ex instanceof TypeError) + assert(ex.message, "G is not a constructor") +} + function test_prototype() { var f = function f() { }; @@ -718,6 +727,7 @@ test_eq(); test_inc_dec(); test_op2(); test_delete(); +test_constructor(); test_prototype(); test_arguments(); test_class();