diff --git a/src/vm/wren_primitive.c b/src/vm/wren_primitive.c index 3671e22f..6ead2867 100644 --- a/src/vm/wren_primitive.c +++ b/src/vm/wren_primitive.c @@ -45,7 +45,7 @@ bool validateInt(WrenVM* vm, Value arg, const char* argName) return validateIntValue(vm, AS_NUM(arg), argName); } -bool validateKey(WrenVM* vm, Value arg) +inline bool validateKeyType(WrenVM* vm, Value arg) { if (IS_BOOL(arg) || IS_CLASS(arg) || IS_NULL(arg) || IS_NUM(arg) || IS_RANGE(arg) || IS_STRING(arg)) @@ -53,6 +53,13 @@ bool validateKey(WrenVM* vm, Value arg) return true; } + return false; +} + +bool validateKey(WrenVM* vm, Value arg) +{ + if (validateKeyType(vm, arg)) return true; + RETURN_ERROR("Key must be a value type."); } diff --git a/src/vm/wren_primitive.h b/src/vm/wren_primitive.h index eb55fe84..4b7c9346 100644 --- a/src/vm/wren_primitive.h +++ b/src/vm/wren_primitive.h @@ -79,9 +79,14 @@ bool validateIntValue(WrenVM* vm, double value, const char* argName); // reports an error and returns false. bool validateInt(WrenVM* vm, Value arg, const char* argName); +// Validates that [arg] is a valid object for use as a map key. Returns true if +// it is and returns false otherwise. Use validateKey usually, for a runtime error. +// This separation exists to aid the API in surfacing errors to the developer as well. +bool validateKeyType(WrenVM * vm, Value arg); + // Validates that [arg] is a valid object for use as a map key. Returns true if // it is. If not, reports an error and returns false. -bool validateKey(WrenVM* vm, Value arg); +bool validateKey(WrenVM * vm, Value arg); // Validates that the argument at [argIndex] is an integer within `[0, count)`. // Also allows negative indices which map backwards from the end. Returns the diff --git a/src/vm/wren_vm.c b/src/vm/wren_vm.c index c53f2090..c1f7ce8f 100644 --- a/src/vm/wren_vm.c +++ b/src/vm/wren_vm.c @@ -1826,6 +1826,7 @@ bool wrenGetMapContainsKey(WrenVM* vm, int mapSlot, int keySlot) ASSERT(IS_MAP(vm->apiStack[mapSlot]), "Slot must hold a map."); Value key = vm->apiStack[keySlot]; + ASSERT(validateKeyType(vm, key), "Key must be a value type"); if (!validateKey(vm, key)) return false; ObjMap* map = AS_MAP(vm->apiStack[mapSlot]); @@ -1858,6 +1859,8 @@ void wrenSetMapValue(WrenVM* vm, int mapSlot, int keySlot, int valueSlot) ASSERT(IS_MAP(vm->apiStack[mapSlot]), "Must insert into a map."); Value key = vm->apiStack[keySlot]; + ASSERT(validateKeyType(vm, key), "Key must be a value type"); + if (!validateKey(vm, key)) { return; }