mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 01:02:45 +00:00 
			
		
		
		
	LibJS: Improve error messages for primitive strict mode property access
Using ErrorType::ReferencePrimitiveSetProperty the errors for primitives now look like "Cannot set property 'foo' of number '123'". The strict-mode-errors test has been adjusted and re-enabled.
This commit is contained in:
		
							parent
							
								
									b9c9315bcb
								
							
						
					
					
						commit
						eaf8c2e398
					
				
					 3 changed files with 19 additions and 15 deletions
				
			
		|  | @ -147,6 +147,11 @@ ThrowCompletionOr<Value> get_global(Bytecode::Interpreter& interpreter, Identifi | ||||||
| 
 | 
 | ||||||
| ThrowCompletionOr<void> put_by_property_key(VM& vm, Value base, Value this_value, Value value, PropertyKey name, Op::PropertyKind kind) | ThrowCompletionOr<void> put_by_property_key(VM& vm, Value base, Value this_value, Value value, PropertyKey name, Op::PropertyKind kind) | ||||||
| { | { | ||||||
|  |     // Better error message than to_object would give
 | ||||||
|  |     if (vm.in_strict_mode() && base.is_nullish()) | ||||||
|  |         return vm.throw_completion<TypeError>(ErrorType::ReferenceNullishSetProperty, name, base.to_string_without_side_effects()); | ||||||
|  | 
 | ||||||
|  |     // a. Let baseObj be ? ToObject(V.[[Base]]).
 | ||||||
|     auto object = TRY(base.to_object(vm)); |     auto object = TRY(base.to_object(vm)); | ||||||
|     if (kind == Op::PropertyKind::Getter || kind == Op::PropertyKind::Setter) { |     if (kind == Op::PropertyKind::Getter || kind == Op::PropertyKind::Setter) { | ||||||
|         // The generator should only pass us functions for getters and setters.
 |         // The generator should only pass us functions for getters and setters.
 | ||||||
|  | @ -169,8 +174,11 @@ ThrowCompletionOr<void> put_by_property_key(VM& vm, Value base, Value this_value | ||||||
|     } |     } | ||||||
|     case Op::PropertyKind::KeyValue: { |     case Op::PropertyKind::KeyValue: { | ||||||
|         bool succeeded = TRY(object->internal_set(name, value, this_value)); |         bool succeeded = TRY(object->internal_set(name, value, this_value)); | ||||||
|         if (!succeeded && vm.in_strict_mode()) |         if (!succeeded && vm.in_strict_mode()) { | ||||||
|             return vm.throw_completion<TypeError>(ErrorType::ReferenceNullishSetProperty, name, base.to_string_without_side_effects()); |             if (base.is_object()) | ||||||
|  |                 return vm.throw_completion<TypeError>(ErrorType::ReferenceNullishSetProperty, name, base.to_string_without_side_effects()); | ||||||
|  |             return vm.throw_completion<TypeError>(ErrorType::ReferencePrimitiveSetProperty, name, base.typeof(), base.to_string_without_side_effects()); | ||||||
|  |         } | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case Op::PropertyKind::DirectKeyValue: |     case Op::PropertyKind::DirectKeyValue: | ||||||
|  |  | ||||||
|  | @ -23,5 +23,5 @@ test("setting new properties on a symbol is an error in strict mode", () => { | ||||||
|     var symbol = Symbol("foo"); |     var symbol = Symbol("foo"); | ||||||
|     expect(() => { |     expect(() => { | ||||||
|         symbol.bar = 42; |         symbol.bar = 42; | ||||||
|     }).toThrowWithMessage(TypeError, "Cannot set property 'bar' of Symbol(foo)"); |     }).toThrowWithMessage(TypeError, "Cannot set property 'bar' of symbol 'Symbol(foo)'"); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | @ -1,23 +1,19 @@ | ||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| test.xfail("basic functionality", () => { | test("basic functionality", () => { | ||||||
|     [true, false, "foo", 123].forEach(primitive => { |     [true, false, "foo", 123, 123n, null, undefined].forEach(primitive => { | ||||||
|  |         let description = `${typeof primitive} '${primitive}${ | ||||||
|  |             typeof primitive == "bigint" ? "n" : "" | ||||||
|  |         }'`;
 | ||||||
|  |         if (primitive == null) description = String(primitive); | ||||||
|         expect(() => { |         expect(() => { | ||||||
|             primitive.foo = "bar"; |             primitive.foo = "bar"; | ||||||
|         }).toThrowWithMessage(TypeError, `Cannot set property 'foo' of ${primitive}`); |         }).toThrowWithMessage(TypeError, `Cannot set property 'foo' of ${description}`); | ||||||
|         expect(() => { |         expect(() => { | ||||||
|             primitive[Symbol.hasInstance] = 123; |             primitive[Symbol.hasInstance] = 123; | ||||||
|         }).toThrowWithMessage( |         }).toThrowWithMessage( | ||||||
|             TypeError, |             TypeError, | ||||||
|             `Cannot set property 'Symbol(Symbol.hasInstance)' of ${primitive}` |             `Cannot set property 'Symbol(Symbol.hasInstance)' of ${description}` | ||||||
|         ); |         ); | ||||||
|     }); |     }); | ||||||
|     [null, undefined].forEach(primitive => { |  | ||||||
|         expect(() => { |  | ||||||
|             primitive.foo = "bar"; |  | ||||||
|         }).toThrowWithMessage(TypeError, `${primitive} cannot be converted to an object`); |  | ||||||
|         expect(() => { |  | ||||||
|             primitive[Symbol.hasInstance] = 123; |  | ||||||
|         }).toThrowWithMessage(TypeError, `${primitive} cannot be converted to an object`); |  | ||||||
|     }); |  | ||||||
| }); | }); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Simon Wanner
						Simon Wanner