More informative "not a constructor" error message (initial patch by bnoordhuis) (#368)

This commit is contained in:
Fabrice Bellard
2025-11-03 18:52:39 +01:00
parent c6fe5a98fd
commit 080c01f346
2 changed files with 33 additions and 6 deletions

View File

@@ -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]));
}

View File

@@ -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();