diff --git a/quickjs.c b/quickjs.c index fcc7368..66880f1 100644 --- a/quickjs.c +++ b/quickjs.c @@ -7326,6 +7326,22 @@ static JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx) return JS_ThrowTypeError(ctx, "not an object"); } +static JSValue JS_ThrowTypeErrorNotAConstructor(JSContext *ctx, + JSValueConst func_obj) +{ + const char *name; + if (!JS_IsFunction(ctx, func_obj)) + goto fail; + name = get_prop_string(ctx, func_obj, JS_ATOM_name); + if (!name) { + fail: + return JS_ThrowTypeError(ctx, "not a constructor"); + } + JS_ThrowTypeError(ctx, "%s is not a constructor", name); + JS_FreeCString(ctx, name); + return JS_EXCEPTION; +} + static JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx) { return JS_ThrowTypeError(ctx, "not a symbol"); @@ -20086,7 +20102,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; @@ -39947,8 +39963,9 @@ static JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj, if (JS_IsUndefined(species) || JS_IsNull(species)) return JS_DupValue(ctx, 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; } @@ -48791,7 +48808,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; } @@ -49710,7 +49727,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); @@ -49936,7 +49953,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 { @@ -54598,7 +54615,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_DupValue(ctx, argv[0])); } diff --git a/tests/test_language.js b/tests/test_language.js index 2f4578c..5c51f0d 100644 --- a/tests/test_language.js +++ b/tests/test_language.js @@ -248,6 +248,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() { }; @@ -660,6 +669,7 @@ test_cvt(); test_eq(); test_inc_dec(); test_op2(); +test_constructor(); test_delete(); test_prototype(); test_arguments();