mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 07:07:45 +00:00
LibJS/Bytecode: Do not coerce the receiver to Object for internal_set
This makes the behavior of `Symbol` correct in strict mode, wherein if the receiver is a symbol primitive, assigning new properties should throw a TypeError.
This commit is contained in:
parent
0cd85ab0fc
commit
d165590809
2 changed files with 16 additions and 7 deletions
|
@ -48,8 +48,9 @@ DeprecatedString Instruction::to_deprecated_string(Bytecode::Executable const& e
|
||||||
|
|
||||||
namespace JS::Bytecode::Op {
|
namespace JS::Bytecode::Op {
|
||||||
|
|
||||||
static ThrowCompletionOr<void> put_by_property_key(VM& vm, Object* object, Value value, PropertyKey name, PropertyKind kind)
|
static ThrowCompletionOr<void> put_by_property_key(VM& vm, Value base, Value value, PropertyKey name, PropertyKind kind)
|
||||||
{
|
{
|
||||||
|
auto object = TRY(base.to_object(vm));
|
||||||
if (kind == PropertyKind::Getter || kind == PropertyKind::Setter) {
|
if (kind == PropertyKind::Getter || kind == PropertyKind::Setter) {
|
||||||
// The generator should only pass us functions for getters and setters.
|
// The generator should only pass us functions for getters and setters.
|
||||||
VERIFY(value.is_function());
|
VERIFY(value.is_function());
|
||||||
|
@ -70,9 +71,9 @@ static ThrowCompletionOr<void> put_by_property_key(VM& vm, Object* object, Value
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PropertyKind::KeyValue: {
|
case PropertyKind::KeyValue: {
|
||||||
bool succeeded = TRY(object->internal_set(name, value, object));
|
bool succeeded = TRY(object->internal_set(name, value, base));
|
||||||
if (!succeeded && vm.in_strict_mode())
|
if (!succeeded && vm.in_strict_mode())
|
||||||
return vm.throw_completion<TypeError>(ErrorType::ReferenceNullishSetProperty, name, TRY_OR_THROW_OOM(vm, value.to_string_without_side_effects()));
|
return vm.throw_completion<TypeError>(ErrorType::ReferenceNullishSetProperty, name, TRY_OR_THROW_OOM(vm, base.to_string_without_side_effects()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PropertyKind::Spread:
|
case PropertyKind::Spread:
|
||||||
|
@ -548,9 +549,9 @@ ThrowCompletionOr<void> PutById::execute_impl(Bytecode::Interpreter& interpreter
|
||||||
auto& vm = interpreter.vm();
|
auto& vm = interpreter.vm();
|
||||||
// NOTE: Get the value from the accumulator before side effects have a chance to overwrite it.
|
// NOTE: Get the value from the accumulator before side effects have a chance to overwrite it.
|
||||||
auto value = interpreter.accumulator();
|
auto value = interpreter.accumulator();
|
||||||
auto object = TRY(interpreter.reg(m_base).to_object(vm));
|
auto base = interpreter.reg(m_base);
|
||||||
PropertyKey name = interpreter.current_executable().get_identifier(m_property);
|
PropertyKey name = interpreter.current_executable().get_identifier(m_property);
|
||||||
TRY(put_by_property_key(vm, object, value, name, m_kind));
|
TRY(put_by_property_key(vm, base, value, name, m_kind));
|
||||||
interpreter.accumulator() = value;
|
interpreter.accumulator() = value;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -1017,10 +1018,10 @@ ThrowCompletionOr<void> PutByValue::execute_impl(Bytecode::Interpreter& interpre
|
||||||
// NOTE: Get the value from the accumulator before side effects have a chance to overwrite it.
|
// NOTE: Get the value from the accumulator before side effects have a chance to overwrite it.
|
||||||
auto value = interpreter.accumulator();
|
auto value = interpreter.accumulator();
|
||||||
|
|
||||||
auto object = TRY(interpreter.reg(m_base).to_object(vm));
|
auto base = interpreter.reg(m_base);
|
||||||
|
|
||||||
auto property_key = TRY(interpreter.reg(m_property).to_property_key(vm));
|
auto property_key = TRY(interpreter.reg(m_property).to_property_key(vm));
|
||||||
TRY(put_by_property_key(vm, object, value, property_key, m_kind));
|
TRY(put_by_property_key(vm, base, value, property_key, m_kind));
|
||||||
interpreter.accumulator() = value;
|
interpreter.accumulator() = value;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,3 +17,11 @@ test("constructing symbol from symbol is an error", () => {
|
||||||
Symbol(Symbol("foo"));
|
Symbol(Symbol("foo"));
|
||||||
}).toThrowWithMessage(TypeError, "Cannot convert symbol to string");
|
}).toThrowWithMessage(TypeError, "Cannot convert symbol to string");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("setting new properties on a symbol is an error in strict mode", () => {
|
||||||
|
"use strict";
|
||||||
|
var symbol = Symbol("foo");
|
||||||
|
expect(() => {
|
||||||
|
symbol.bar = 42;
|
||||||
|
}).toThrowWithMessage(TypeError, "Cannot set property 'bar' of Symbol(foo)");
|
||||||
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue