Browse Source

Generic `JsResult<R>` in `context.throw_` methods (#1734)

Previously when we had the `context.throw_` methods (like `context.thtrow_type_error()`) they were limited as to where we could call them, e.i. a function that returned `JsResult<JsValue>`. So we had to call the `context.construct_` methods with an explicit `Err()` enum wrap to throw in functions that returned non-jsvalues (which happens a lot).
Now, with this PR the throw methods have a generic `JsResult<R>` return that can return in any `JsResult<T>` returning function. Which cleans the API and makes the user experience a bit better.

```rust
return Err(context.construct_type_error("..."));
// to
return context.throw_type_error("...");
```
pull/1735/head
Halid Odat 3 years ago
parent
commit
3269c1b901
  1. 8
      boa/src/bigint.rs
  2. 10
      boa/src/builtins/array/mod.rs
  3. 2
      boa/src/builtins/array_buffer/mod.rs
  4. 4
      boa/src/builtins/intl/mod.rs
  5. 2
      boa/src/builtins/iterable/mod.rs
  6. 6
      boa/src/builtins/json/mod.rs
  7. 9
      boa/src/builtins/number/mod.rs
  8. 33
      boa/src/builtins/regexp/mod.rs
  9. 113
      boa/src/builtins/typed_array/mod.rs
  10. 12
      boa/src/context.rs
  11. 10
      boa/src/environment/declarative_environment_record.rs
  12. 8
      boa/src/environment/global_environment_record.rs
  13. 2
      boa/src/environment/object_environment_record.rs
  14. 11
      boa/src/lib.rs
  15. 2
      boa/src/object/internal_methods/array.rs
  16. 101
      boa/src/object/internal_methods/proxy.rs
  17. 14
      boa/src/object/jsobject.rs
  18. 25
      boa/src/object/operations.rs
  19. 8
      boa/src/syntax/ast/node/declaration/mod.rs
  20. 42
      boa/src/value/mod.rs
  21. 6
      boa/src/value/operations.rs
  22. 20
      boa/src/vm/mod.rs
  23. 2
      boa_tester/src/exec/js262.rs
  24. 5
      boa_wasm/src/lib.rs

8
boa/src/bigint.rs

@ -166,7 +166,7 @@ impl JsBigInt {
let y = if let Some(y) = y.inner.to_biguint() {
y
} else {
return Err(context.construct_range_error("BigInt negative exponent"));
return context.throw_range_error("BigInt negative exponent");
};
let num_bits = (x.inner.bits() as f64
@ -175,7 +175,7 @@ impl JsBigInt {
+ 1f64;
if num_bits > 1_000_000_000f64 {
return Err(context.construct_range_error("Maximum BigInt size exceeded"));
return context.throw_range_error("Maximum BigInt size exceeded");
}
Ok(Self::new(x.inner.as_ref().clone().pow(y)))
@ -192,7 +192,7 @@ impl JsBigInt {
Ok(Self::new(inner))
} else {
Err(context.construct_range_error("Maximum BigInt size exceeded"))
context.throw_range_error("Maximum BigInt size exceeded")
}
}
@ -207,7 +207,7 @@ impl JsBigInt {
Ok(Self::new(inner))
} else {
Err(context.construct_range_error("Maximum BigInt size exceeded"))
context.throw_range_error("Maximum BigInt size exceeded")
}
}

10
boa/src/builtins/array/mod.rs

@ -165,7 +165,7 @@ impl Array {
let int_len = len.to_u32(context).unwrap();
// ii. If SameValueZero(intLen, len) is false, throw a RangeError exception.
if !JsValue::same_value_zero(&int_len.into(), len) {
return Err(context.construct_range_error("invalid array length"));
return context.throw_range_error("invalid array length");
}
int_len
};
@ -210,7 +210,7 @@ impl Array {
) -> JsResult<JsObject> {
// 1. If length > 2^32 - 1, throw a RangeError exception.
if length > 2usize.pow(32) - 1 {
return Err(context.construct_range_error("array exceeded max size"));
return context.throw_range_error("array exceeded max size");
}
// 7. Return A.
// 2. If proto is not present, set proto to %Array.prototype%.
@ -365,7 +365,7 @@ impl Array {
.unwrap(),
)
} else {
Err(context.construct_type_error("Symbol.species must be a constructor"))
context.throw_type_error("Symbol.species must be a constructor")
}
}
@ -1669,8 +1669,8 @@ impl Array {
} else {
// 1. If targetIndex >= 2^53 - 1, throw a TypeError exception
if target_index >= Number::MAX_SAFE_INTEGER as u64 {
return Err(context
.construct_type_error("Target index exceeded max safe integer value"));
return context
.throw_type_error("Target index exceeded max safe integer value");
}
// 2. Perform ? CreateDataPropertyOrThrow(target, targetIndex, element)

2
boa/src/builtins/array_buffer/mod.rs

@ -363,7 +363,7 @@ impl ArrayBuffer {
let src_block = if let Some(b) = &self.array_buffer_data {
b
} else {
return Err(context.construct_syntax_error("Cannot clone detached array buffer"));
return context.throw_syntax_error("Cannot clone detached array buffer");
};
{

4
boa/src/builtins/intl/mod.rs

@ -93,9 +93,7 @@ impl Intl {
let k_value = o.get(k, context)?;
// ii. If Type(kValue) is not String or Object, throw a TypeError exception.
if !(k_value.is_object() || k_value.is_string()) {
return Err(context
.throw_type_error("locale should be a String or Object")
.unwrap_err());
return context.throw_type_error("locale should be a String or Object");
}
// iii. If Type(kValue) is Object and kValue has an [[InitializedLocale]] internal slot, then
// TODO: handle checks for InitializedLocale internal slot (there should be an if statement here)

2
boa/src/builtins/iterable/mod.rs

@ -149,7 +149,7 @@ impl JsValue {
// 4. If Type(iterator) is not Object, throw a TypeError exception.
if !iterator.is_object() {
return Err(context.construct_type_error("the iterator is not an object"));
return context.throw_type_error("the iterator is not an object");
}
// 5. Let nextMethod be ? GetV(iterator, "next").

6
boa/src/builtins/json/mod.rs

@ -448,7 +448,7 @@ impl Json {
// 10. If Type(value) is BigInt, throw a TypeError exception.
if value.is_bigint() {
return Err(context.construct_type_error("cannot serialize bigint to JSON"));
return context.throw_type_error("cannot serialize bigint to JSON");
}
// 11. If Type(value) is Object and IsCallable(value) is false, then
@ -531,7 +531,7 @@ impl Json {
// 1. If state.[[Stack]] contains value, throw a TypeError exception because the structure is cyclical.
let limiter = RecursionLimiter::new(value);
if limiter.live {
return Err(context.construct_type_error("cyclic object value"));
return context.throw_type_error("cyclic object value");
}
// 2. Append value to state.[[Stack]].
@ -644,7 +644,7 @@ impl Json {
// 1. If state.[[Stack]] contains value, throw a TypeError exception because the structure is cyclical.
let limiter = RecursionLimiter::new(value);
if limiter.live {
return Err(context.construct_type_error("cyclic object value"));
return context.throw_type_error("cyclic object value");
}
// 2. Append value to state.[[Stack]].

9
boa/src/builtins/number/mod.rs

@ -222,8 +222,8 @@ impl Number {
let this_str_num = if let Some(precision) = precision {
// 5. If f < 0 or f > 100, throw a RangeError exception.
if !(0..=100).contains(&precision) {
return Err(context
.construct_range_error("toExponential() argument must be between 0 and 100"));
return context
.throw_range_error("toExponential() argument must be between 0 and 100");
}
f64_to_exponential_with_precision(this_num, precision as usize)
} else {
@ -256,9 +256,8 @@ impl Number {
0..=100 => n.to_integer(context)? as usize,
// 4, 5. If f < 0 or f > 100, throw a RangeError exception.
_ => {
return Err(context.construct_range_error(
"toFixed() digits argument must be between 0 and 100",
))
return context
.throw_range_error("toFixed() digits argument must be between 0 and 100")
}
},
// 3. If fractionDigits is undefined, then f is 0.

33
boa/src/builtins/regexp/mod.rs

@ -332,8 +332,8 @@ impl RegExp {
// 14. Set obj.[[RegExpMatcher]] to the Abstract Closure that evaluates parseResult by applying the semantics provided in 22.2.2 using patternCharacters as the pattern's List of SourceCharacter values and F as the flag parameters.
let matcher = match Regex::with_flags(&p, f.as_ref()) {
Err(error) => {
return Err(context
.construct_syntax_error(format!("failed to create matcher: {}", error.text)));
return context
.throw_syntax_error(format!("failed to create matcher: {}", error.text));
}
Ok(val) => val,
};
@ -779,9 +779,7 @@ impl RegExp {
// b. If Type(result) is neither Object nor Null, throw a TypeError exception.
if !result.is_object() && !result.is_null() {
return Err(
context.construct_type_error("regexp exec returned neither object nor null")
);
return context.throw_type_error("regexp exec returned neither object nor null");
}
// c. Return result.
@ -790,7 +788,7 @@ impl RegExp {
// 5. Perform ? RequireInternalSlot(R, [[RegExpMatcher]]).
if !this.is_regexp() {
return Err(context.construct_type_error("RegExpExec called with invalid value"));
return context.throw_type_error("RegExpExec called with invalid value");
}
// 6. Return ? RegExpBuiltinExec(R, S).
@ -814,9 +812,7 @@ impl RegExp {
if let Some(rx) = obj.as_regexp() {
rx.clone()
} else {
return Err(
context.construct_type_error("RegExpBuiltinExec called with invalid value")
);
return context.throw_type_error("RegExpBuiltinExec called with invalid value");
}
};
@ -870,9 +866,8 @@ impl RegExp {
) {
Ok(s) => s.len(),
Err(_) => {
return Err(context.construct_type_error(
"Failed to get byte index from utf16 encoded string",
))
return context
.throw_type_error("Failed to get byte index from utf16 encoded string")
}
};
let r = matcher.find_from(&input, last_byte_index).next();
@ -1046,9 +1041,8 @@ impl RegExp {
let rx = if let Some(rx) = this.as_object() {
rx
} else {
return Err(context.construct_type_error(
"RegExp.prototype.match method called on incompatible value",
));
return context
.throw_type_error("RegExp.prototype.match method called on incompatible value");
};
// 3. Let S be ? ToString(string).
@ -1495,9 +1489,9 @@ impl RegExp {
let rx = if let Some(rx) = this.as_object() {
rx
} else {
return Err(context.construct_type_error(
return context.throw_type_error(
"RegExp.prototype[Symbol.search] method called on incompatible value",
));
);
};
// 3. Let S be ? ToString(string).
@ -1557,9 +1551,8 @@ impl RegExp {
let rx = if let Some(rx) = this.as_object() {
rx
} else {
return Err(context.construct_type_error(
"RegExp.prototype.split method called on incompatible value",
));
return context
.throw_type_error("RegExp.prototype.split method called on incompatible value");
};
// 3. Let S be ? ToString(string).

113
boa/src/builtins/typed_array/mod.rs

@ -547,7 +547,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -682,7 +682,7 @@ impl TypedArray {
// 2. Perform ? ValidateTypedArray(O).
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -747,7 +747,7 @@ impl TypedArray {
// b. Let buffer be O.[[ViewedArrayBuffer]].
// c. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// d. Let typedArrayName be the String value of O.[[TypedArrayName]].
@ -848,7 +848,7 @@ impl TypedArray {
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?
.is_detached()
{
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Return CreateArrayIterator(O, key+value).
@ -876,7 +876,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -935,7 +935,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -980,7 +980,7 @@ impl TypedArray {
// 14. If IsDetachedBuffer(O.[[ViewedArrayBuffer]]) is true, throw a TypeError exception.
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 15. Repeat, while k < final,
@ -1015,7 +1015,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -1096,7 +1096,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -1154,7 +1154,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -1211,7 +1211,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -1263,7 +1263,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -1336,7 +1336,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -1418,7 +1418,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -1475,7 +1475,7 @@ impl TypedArray {
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?
.is_detached()
{
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Return CreateArrayIterator(O, key).
@ -1503,7 +1503,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -1606,7 +1606,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -1664,7 +1664,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -1741,7 +1741,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -1821,7 +1821,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -1933,7 +1933,7 @@ impl TypedArray {
// 1. Let targetBuffer be target.[[ViewedArrayBuffer]].
// 2. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
if target_array.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
let target_buffer_obj = target_array
.viewed_array_buffer()
@ -1945,7 +1945,7 @@ impl TypedArray {
// 4. Let srcBuffer be source.[[ViewedArrayBuffer]].
// 5. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception.
if source_array.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
let mut src_buffer_obj = source_array
.viewed_array_buffer()
@ -1979,23 +1979,23 @@ impl TypedArray {
let target_offset = match target_offset {
IntegerOrInfinity::Integer(i) if i >= 0 => i as usize,
IntegerOrInfinity::PositiveInfinity => {
return Err(context.construct_range_error("Target offset cannot be Infinity"))
return context.throw_range_error("Target offset cannot be Infinity");
}
_ => unreachable!(),
};
// 16. If srcLength + targetOffset > targetLength, throw a RangeError exception.
if src_length + target_offset > target_length {
return Err(context.construct_range_error(
return context.throw_range_error(
"Source typed array and target offset longer than target typed array",
));
);
}
// 17. If target.[[ContentType]] ≠ source.[[ContentType]], throw a TypeError exception.
if target_name.content_type() != src_name.content_type() {
return Err(context.construct_type_error(
return context.throw_type_error(
"Source typed array and target typed array have different content types",
));
);
}
// TODO: Shared Array Buffer
@ -2142,7 +2142,7 @@ impl TypedArray {
// 1. Let targetBuffer be target.[[ViewedArrayBuffer]].
// 2. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
if target_array.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let targetLength be target.[[ArrayLength]].
@ -2167,7 +2167,7 @@ impl TypedArray {
let target_offset = match target_offset {
// 10. If targetOffset is +∞, throw a RangeError exception.
IntegerOrInfinity::PositiveInfinity => {
return Err(context.construct_range_error("Target offset cannot be Infinity"))
return context.throw_range_error("Target offset cannot be Infinity")
}
IntegerOrInfinity::Integer(i) if i >= 0 => i as usize,
_ => unreachable!(),
@ -2175,9 +2175,9 @@ impl TypedArray {
// 11. If srcLength + targetOffset > targetLength, throw a RangeError exception.
if src_length + target_offset > target_length {
return Err(context.construct_range_error(
return context.throw_range_error(
"Source object and target offset longer than target typed array",
));
);
}
// 12. Let targetByteIndex be targetOffset × targetElementSize + targetByteOffset.
@ -2213,9 +2213,7 @@ impl TypedArray {
// e. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception.
if target_buffer.is_detached_buffer() {
return Err(
context.construct_type_error("Cannot set value on detached array buffer")
);
return context.throw_type_error("Cannot set value on detached array buffer");
}
// f. Perform SetValueInBuffer(targetBuffer, targetByteIndex, targetType, value, true, Unordered).
@ -2255,7 +2253,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -2304,7 +2302,7 @@ impl TypedArray {
if count > 0 {
// a. If IsDetachedBuffer(O.[[ViewedArrayBuffer]]) is true, throw a TypeError exception.
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// b. Let srcName be the String value of O.[[TypedArrayName]].
@ -2419,7 +2417,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Let len be O.[[ArrayLength]].
@ -2545,8 +2543,8 @@ impl TypedArray {
.expect("Must be array buffer")
.is_detached_buffer()
{
return Err(context
.construct_type_error("Cannot sort typed array with detached buffer"));
return context
.throw_type_error("Cannot sort typed array with detached buffer");
}
// c. If v is NaN, return +0𝔽.
@ -2770,7 +2768,7 @@ impl TypedArray {
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?
.is_detached()
{
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. Return CreateArrayIterator(O, value).
@ -2848,8 +2846,8 @@ impl TypedArray {
.content_type()
!= typed_array_name.content_type()
{
return Err(context
.construct_type_error("New typed array has different context type than exemplar"));
return context
.throw_type_error("New typed array has different context type than exemplar");
}
// 6. Return result.
@ -2879,7 +2877,7 @@ impl TypedArray {
.as_typed_array()
.ok_or_else(|| context.construct_type_error("Value is not a typed array object"))?;
if o.is_detached() {
return Err(context.construct_type_error("Buffer of the typed array is detached"));
return context.throw_type_error("Buffer of the typed array is detached");
}
// 3. If argumentList is a List of a single Number, then
@ -2887,8 +2885,8 @@ impl TypedArray {
if let Some(number) = args[0].as_number() {
// a. If newTypedArray.[[ArrayLength]] < ℝ(argumentList[0]), throw a TypeError exception.
if (o.array_length() as f64) < number {
return Err(context
.construct_type_error("New typed array length is smaller than expected"));
return context
.throw_type_error("New typed array length is smaller than expected");
}
}
}
@ -3035,9 +3033,7 @@ impl TypedArray {
// 1. Let srcData be srcArray.[[ViewedArrayBuffer]].
// 2. If IsDetachedBuffer(srcData) is true, throw a TypeError exception.
if src_array.is_detached() {
return Err(
context.construct_type_error("Cannot initialize typed array from detached buffer")
);
return context.throw_type_error("Cannot initialize typed array from detached buffer");
}
let src_data_obj = src_array
.viewed_array_buffer()
@ -3095,15 +3091,14 @@ impl TypedArray {
// b. If IsDetachedBuffer(srcData) is true, throw a TypeError exception.
if src_data.is_detached_buffer() {
return Err(context
.construct_type_error("Cannot initialize typed array from detached buffer"));
return context
.throw_type_error("Cannot initialize typed array from detached buffer");
}
// c. If srcArray.[[ContentType]] ≠ O.[[ContentType]], throw a TypeError exception.
if src_name.content_type() != constructor_name.content_type() {
return Err(context.construct_type_error(
"Cannot initialize typed array from different content type",
));
return context
.throw_type_error("Cannot initialize typed array from different content type");
}
// d. Let srcByteIndex be srcByteOffset.
@ -3188,7 +3183,7 @@ impl TypedArray {
// 4. If offset modulo elementSize ≠ 0, throw a RangeError exception.
if offset % constructor_name.element_size() != 0 {
return Err(context.construct_range_error("Invalid length for typed array"));
return context.throw_range_error("Invalid length for typed array");
}
let buffer_byte_length = {
@ -3199,8 +3194,8 @@ impl TypedArray {
// 6. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
if buffer_array.is_detached_buffer() {
return Err(context
.construct_type_error("Cannot construct typed array from detached buffer"));
return context
.throw_type_error("Cannot construct typed array from detached buffer");
}
// 7. Let bufferByteLength be buffer.[[ArrayBufferByteLength]].
@ -3211,7 +3206,7 @@ impl TypedArray {
let new_byte_length = if length.is_undefined() {
// a. If bufferByteLength modulo elementSize ≠ 0, throw a RangeError exception.
if buffer_byte_length % constructor_name.element_size() != 0 {
return Err(context.construct_range_error("Invalid length for typed array"));
return context.throw_range_error("Invalid length for typed array");
}
// b. Let newByteLength be bufferByteLength - offset.
@ -3219,7 +3214,7 @@ impl TypedArray {
// c. If newByteLength < 0, throw a RangeError exception.
if new_byte_length < 0 {
return Err(context.construct_range_error("Invalid length for typed array"));
return context.throw_range_error("Invalid length for typed array");
}
new_byte_length as usize
@ -3233,7 +3228,7 @@ impl TypedArray {
// b. If offset + newByteLength > bufferByteLength, throw a RangeError exception.
if offset + new_byte_length > buffer_byte_length {
return Err(context.construct_range_error("Invalid length for typed array"));
return context.throw_range_error("Invalid length for typed array");
}
new_byte_length

12
boa/src/context.rs

@ -555,7 +555,7 @@ impl Context {
/// Throws a `Error` with the specified message.
#[inline]
pub fn throw_error<M>(&mut self, message: M) -> JsResult<JsValue>
pub fn throw_error<M, R>(&mut self, message: M) -> JsResult<R>
where
M: Into<Box<str>>,
{
@ -582,7 +582,7 @@ impl Context {
/// Throws a `RangeError` with the specified message.
#[inline]
pub fn throw_range_error<M>(&mut self, message: M) -> JsResult<JsValue>
pub fn throw_range_error<M, R>(&mut self, message: M) -> JsResult<R>
where
M: Into<Box<str>>,
{
@ -609,7 +609,7 @@ impl Context {
/// Throws a `TypeError` with the specified message.
#[inline]
pub fn throw_type_error<M>(&mut self, message: M) -> JsResult<JsValue>
pub fn throw_type_error<M, R>(&mut self, message: M) -> JsResult<R>
where
M: Into<Box<str>>,
{
@ -636,7 +636,7 @@ impl Context {
/// Throws a `ReferenceError` with the specified message.
#[inline]
pub fn throw_reference_error<M>(&mut self, message: M) -> JsResult<JsValue>
pub fn throw_reference_error<M, R>(&mut self, message: M) -> JsResult<R>
where
M: Into<Box<str>>,
{
@ -663,7 +663,7 @@ impl Context {
/// Throws a `SyntaxError` with the specified message.
#[inline]
pub fn throw_syntax_error<M>(&mut self, message: M) -> JsResult<JsValue>
pub fn throw_syntax_error<M, R>(&mut self, message: M) -> JsResult<R>
where
M: Into<Box<str>>,
{
@ -705,7 +705,7 @@ impl Context {
}
/// Throws a `EvalError` with the specified message.
pub fn throw_eval_error<M>(&mut self, message: M) -> JsResult<JsValue>
pub fn throw_eval_error<M, R>(&mut self, message: M) -> JsResult<R>
where
M: Into<Box<str>>,
{

10
boa/src/environment/declarative_environment_record.rs

@ -179,7 +179,7 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord {
if self.env_rec.borrow().get(name).is_none() {
// a. If S is true, throw a ReferenceError exception.
if strict {
return Err(context.construct_reference_error(format!("{} not found", name)));
return context.throw_reference_error(format!("{} not found", name));
}
// b. Perform envRec.CreateMutableBinding(N, true).
@ -204,9 +204,7 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord {
// 3. If the binding for N in envRec has not yet been initialized, throw a ReferenceError exception.
if binding_value_is_none {
return Err(
context.construct_reference_error(format!("{} has not been initialized", name))
);
return context.throw_reference_error(format!("{} has not been initialized", name));
// 4. Else if the binding for N in envRec is a mutable binding, change its bound value to V.
} else if binding_mutable {
let mut env_rec = self.env_rec.borrow_mut();
@ -216,8 +214,8 @@ impl EnvironmentRecordTrait for DeclarativeEnvironmentRecord {
// a. Assert: This is an attempt to change the value of an immutable binding.
// b. If S is true, throw a TypeError exception.
} else if strict {
return Err(context
.construct_type_error(format!("Cannot mutate an immutable binding {}", name)));
return context
.throw_type_error(format!("Cannot mutate an immutable binding {}", name));
}
// 6. Return NormalCompletion(empty).

8
boa/src/environment/global_environment_record.rs

@ -300,9 +300,7 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord {
// 1. Let DclRec be envRec.[[DeclarativeRecord]].
// 2. If DclRec.HasBinding(N) is true, throw a TypeError exception.
if !allow_name_reuse && self.declarative_record.has_binding(name, context)? {
return Err(
context.construct_type_error(format!("Binding already exists for {}", name))
);
return context.throw_type_error(format!("Binding already exists for {}", name));
}
// 3. Return DclRec.CreateMutableBinding(N, D).
@ -325,9 +323,7 @@ impl EnvironmentRecordTrait for GlobalEnvironmentRecord {
// 1. Let DclRec be envRec.[[DeclarativeRecord]].
// 2. If DclRec.HasBinding(N) is true, throw a TypeError exception.
if self.declarative_record.has_binding(name, context)? {
return Err(
context.construct_type_error(format!("Binding already exists for {}", name))
);
return context.throw_type_error(format!("Binding already exists for {}", name));
}
// 3. Return DclRec.CreateImmutableBinding(N, S).

2
boa/src/environment/object_environment_record.rs

@ -157,7 +157,7 @@ impl EnvironmentRecordTrait for ObjectEnvironmentRecord {
// 3. If stillExists is false and S is true, throw a ReferenceError exception.
if !still_exists && strict {
return Err(context.construct_reference_error("Binding already exists"));
return context.throw_reference_error("Binding already exists");
}
// 4. Return ? Set(bindingObject, N, V, S).

11
boa/src/lib.rs

@ -108,10 +108,7 @@ pub(crate) fn forward<T: AsRef<[u8]>>(context: &mut Context, src: T) -> String {
Err(e) => {
return format!(
"Uncaught {}",
context
.throw_syntax_error(e.to_string())
.expect_err("interpreter.throw_syntax_error() did not return an error")
.display()
context.construct_syntax_error(e.to_string()).display()
);
}
};
@ -133,11 +130,7 @@ pub(crate) fn forward_val<T: AsRef<[u8]>>(context: &mut Context, src: T) -> JsRe
let src_bytes: &[u8] = src.as_ref();
// Setup executor
let result = parse(src_bytes, false)
.map_err(|e| {
context
.throw_syntax_error(e.to_string())
.expect_err("interpreter.throw_syntax_error() did not return an error")
})
.map_err(|e| context.construct_syntax_error(e.to_string()))
.and_then(|expr| expr.run(context));
// The main_timer needs to be dropped before the BoaProfiler is.

2
boa/src/object/internal_methods/array.rs

@ -62,7 +62,7 @@ pub(crate) fn array_exotic_define_own_property(
// 5. If SameValueZero(newLen, numberLen) is false, throw a RangeError exception.
#[allow(clippy::float_cmp)]
if new_len as f64 != number_len {
return Err(context.construct_range_error("bad length for array"));
return context.throw_range_error("bad length for array");
}
// 2. Let newLenDesc be a copy of Desc.

101
boa/src/object/internal_methods/proxy.rs

@ -100,9 +100,7 @@ pub(crate) fn proxy_exotic_get_prototype_of(
let handler_proto = match &handler_proto {
JsValue::Object(obj) => Some(obj.clone()),
JsValue::Null => None,
_ => {
return Err(context.construct_type_error("Proxy trap result is neither object nor null"))
}
_ => return context.throw_type_error("Proxy trap result is neither object nor null"),
};
// 9. Let extensibleTarget be ? IsExtensible(target).
@ -116,7 +114,7 @@ pub(crate) fn proxy_exotic_get_prototype_of(
// 12. If SameValue(handlerProto, targetProto) is false, throw a TypeError exception.
if handler_proto != target_proto {
return Err(context.construct_type_error("Proxy trap returned unexpected prototype"));
return context.throw_type_error("Proxy trap returned unexpected prototype");
}
// 13. Return handlerProto.
@ -181,7 +179,7 @@ pub(crate) fn proxy_exotic_set_prototype_of(
// 12. If SameValue(V, targetProto) is false, throw a TypeError exception.
if val != target_proto {
return Err(context.construct_type_error("Proxy trap failed to set prototype"));
return context.throw_type_error("Proxy trap failed to set prototype");
}
// 13. Return true.
@ -225,7 +223,7 @@ pub(crate) fn proxy_exotic_is_extensible(obj: &JsObject, context: &mut Context)
// 9. If SameValue(booleanTrapResult, targetResult) is false, throw a TypeError exception.
if boolean_trap_result != target_result {
return Err(context.construct_type_error("Proxy trap returned unexpected extensible value"));
return context.throw_type_error("Proxy trap returned unexpected extensible value");
}
// 10. Return booleanTrapResult.
@ -271,7 +269,7 @@ pub(crate) fn proxy_exotic_prevent_extensions(
if boolean_trap_result && target.is_extensible(context)? {
// a. Let extensibleTarget be ? IsExtensible(target).
// b. If extensibleTarget is true, throw a TypeError exception.
return Err(context.construct_type_error("Proxy trap failed to set extensible"));
return context.throw_type_error("Proxy trap failed to set extensible");
}
// 9. Return booleanTrapResult.
@ -318,9 +316,7 @@ pub(crate) fn proxy_exotic_get_own_property(
// 8. If Type(trapResultObj) is neither Object nor Undefined, throw a TypeError exception.
if !trap_result_obj.is_object() && !trap_result_obj.is_undefined() {
return Err(
context.construct_type_error("Proxy trap result is neither object nor undefined")
);
return context.throw_type_error("Proxy trap result is neither object nor undefined");
}
// 9. Let targetDesc be ? target.[[GetOwnProperty]](P).
@ -331,17 +327,17 @@ pub(crate) fn proxy_exotic_get_own_property(
if let Some(desc) = target_desc {
// b. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
if !desc.expect_configurable() {
return Err(context.construct_type_error(
return context.throw_type_error(
"Proxy trap result is undefined adn target result is not configurable",
));
);
}
// c. Let extensibleTarget be ? IsExtensible(target).
// d. If extensibleTarget is false, throw a TypeError exception.
if !target.is_extensible(context)? {
return Err(context.construct_type_error(
return context.throw_type_error(
"Proxy trap result is undefined and target is not extensible",
));
);
// e. Return undefined.
} else {
return Ok(None);
@ -368,7 +364,7 @@ pub(crate) fn proxy_exotic_get_own_property(
result_desc.clone(),
target_desc.clone(),
) {
return Err(context.construct_type_error("Proxy trap returned unexpected property"));
return context.throw_type_error("Proxy trap returned unexpected property");
}
// 16. If resultDesc.[[Configurable]] is false, then
@ -380,17 +376,17 @@ pub(crate) fn proxy_exotic_get_own_property(
if let Some(false) = result_desc.writable() {
// i. If targetDesc.[[Writable]] is true, throw a TypeError exception.
if desc.expect_writable() {
return Err(
context.construct_type_error("Proxy trap result is writable and not configurable while target result is not configurable")
);
return
context.throw_type_error("Proxy trap result is writable and not configurable while target result is not configurable")
;
}
}
}
// i. Throw a TypeError exception.
_ => {
return Err(context.construct_type_error(
return context.throw_type_error(
"Proxy trap result is not configurable and target result is undefined",
))
)
}
}
}
@ -461,12 +457,12 @@ pub(crate) fn proxy_exotic_define_own_property(
None => {
// a. If extensibleTarget is false, throw a TypeError exception.
if !extensible_target {
return Err(context.construct_type_error("Proxy trap failed to set property"));
return context.throw_type_error("Proxy trap failed to set property");
}
// b. If settingConfigFalse is true, throw a TypeError exception.
if setting_config_false {
return Err(context.construct_type_error("Proxy trap failed to set property"));
return context.throw_type_error("Proxy trap failed to set property");
}
}
// 15. Else,
@ -477,16 +473,14 @@ pub(crate) fn proxy_exotic_define_own_property(
desc.clone(),
Some(target_desc.clone()),
) {
return Err(
context.construct_type_error("Proxy trap set property to unexpected value")
);
return context.throw_type_error("Proxy trap set property to unexpected value");
}
// b. If settingConfigFalse is true and targetDesc.[[Configurable]] is true, throw a TypeError exception.
if setting_config_false && target_desc.expect_configurable() {
return Err(context.construct_type_error(
return context.throw_type_error(
"Proxy trap set property with unexpected configurable field",
));
);
}
// c. If IsDataDescriptor(targetDesc) is true, targetDesc.[[Configurable]] is false, and targetDesc.[[Writable]] is true, then
@ -497,9 +491,9 @@ pub(crate) fn proxy_exotic_define_own_property(
// i. If Desc has a [[Writable]] field and Desc.[[Writable]] is false, throw a TypeError exception.
if let Some(writable) = desc.writable() {
if !writable {
return Err(context.construct_type_error(
return context.throw_type_error(
"Proxy trap set property with unexpected writable field",
));
);
}
}
}
@ -559,13 +553,13 @@ pub(crate) fn proxy_exotic_has_property(
if let Some(target_desc) = target_desc {
// i. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
if !target_desc.expect_configurable() {
return Err(context.construct_type_error("Proxy trap returned unexpected property"));
return context.throw_type_error("Proxy trap returned unexpected property");
}
// ii. Let extensibleTarget be ? IsExtensible(target).
// iii. If extensibleTarget is false, throw a TypeError exception.
if !target.is_extensible(context)? {
return Err(context.construct_type_error("Proxy trap returned unexpected property"));
return context.throw_type_error("Proxy trap returned unexpected property");
}
}
}
@ -623,8 +617,8 @@ pub(crate) fn proxy_exotic_get(
if target_desc.is_data_descriptor() && !target_desc.expect_writable() {
// i. If SameValue(trapResult, targetDesc.[[Value]]) is false, throw a TypeError exception.
if !JsValue::same_value(&trap_result, target_desc.expect_value()) {
return Err(context
.construct_type_error("Proxy trap returned unexpected data descriptor"));
return context
.throw_type_error("Proxy trap returned unexpected data descriptor");
}
}
@ -632,9 +626,8 @@ pub(crate) fn proxy_exotic_get(
if target_desc.is_accessor_descriptor() && target_desc.expect_get().is_undefined() {
// i. If trapResult is not undefined, throw a TypeError exception.
if !trap_result.is_undefined() {
return Err(context.construct_type_error(
"Proxy trap returned unexpected accessor descriptor",
));
return context
.throw_type_error("Proxy trap returned unexpected accessor descriptor");
}
}
}
@ -700,9 +693,7 @@ pub(crate) fn proxy_exotic_set(
if target_desc.is_data_descriptor() && !target_desc.expect_writable() {
// i. If SameValue(V, targetDesc.[[Value]]) is false, throw a TypeError exception.
if !JsValue::same_value(&value, target_desc.expect_value()) {
return Err(
context.construct_type_error("Proxy trap set unexpected data descriptor")
);
return context.throw_type_error("Proxy trap set unexpected data descriptor");
}
}
@ -711,9 +702,8 @@ pub(crate) fn proxy_exotic_set(
// i. If targetDesc.[[Set]] is undefined, throw a TypeError exception.
match target_desc.set() {
None | Some(&JsValue::Undefined) => {
return Err(context.construct_type_error(
"Proxy trap set unexpected accessor descriptor",
));
return context
.throw_type_error("Proxy trap set unexpected accessor descriptor");
}
_ => {}
}
@ -776,7 +766,7 @@ pub(crate) fn proxy_exotic_delete(
// 11. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
Some(target_desc) => {
if !target_desc.expect_configurable() {
return Err(context.construct_type_error("Proxy trap failed to delete property"));
return context.throw_type_error("Proxy trap failed to delete property");
}
}
}
@ -784,7 +774,7 @@ pub(crate) fn proxy_exotic_delete(
// 12. Let extensibleTarget be ? IsExtensible(target).
// 13. If extensibleTarget is false, throw a TypeError exception.
if !target.is_extensible(context)? {
return Err(context.construct_type_error("Proxy trap failed to delete property"));
return context.throw_type_error("Proxy trap failed to delete property");
}
// 14. Return true.
@ -835,17 +825,17 @@ pub(crate) fn proxy_exotic_own_property_keys(
match value {
JsValue::String(s) => {
if !unchecked_result_keys.insert(s.clone().into()) {
return Err(context.construct_type_error(
return context.throw_type_error(
"Proxy trap result contains duplicate string property keys",
));
);
}
trap_result.push(s.clone().into())
}
JsValue::Symbol(s) => {
if !unchecked_result_keys.insert(s.clone().into()) {
return Err(context.construct_type_error(
return context.throw_type_error(
"Proxy trap result contains duplicate symbol property keys",
));
);
}
trap_result.push(s.clone().into())
}
@ -895,9 +885,9 @@ pub(crate) fn proxy_exotic_own_property_keys(
// a. If key is not an element of uncheckedResultKeys, throw a TypeError exception.
// b. Remove key from uncheckedResultKeys.
if !unchecked_result_keys.remove(&key) {
return Err(context.construct_type_error(
return context.throw_type_error(
"Proxy trap failed to return all non-configurable property keys",
));
);
}
}
@ -911,15 +901,14 @@ pub(crate) fn proxy_exotic_own_property_keys(
// a. If key is not an element of uncheckedResultKeys, throw a TypeError exception.
// b. Remove key from uncheckedResultKeys.
if !unchecked_result_keys.remove(&key) {
return Err(context.construct_type_error(
"Proxy trap failed to return all configurable property keys",
));
return context
.throw_type_error("Proxy trap failed to return all configurable property keys");
}
}
// 22. If uncheckedResultKeys is not empty, throw a TypeError exception.
if !unchecked_result_keys.is_empty() {
return Err(context.construct_type_error("Proxy trap failed to return all property keys"));
return context.throw_type_error("Proxy trap failed to return all property keys");
}
// 23. Return trapResult.
@ -1014,9 +1003,7 @@ fn proxy_exotic_construct(
// 10. If Type(newObj) is not Object, throw a TypeError exception.
if !new_obj.is_object() {
return Err(
context.construct_type_error("Proxy trap constructor returned non-object value")
);
return context.throw_type_error("Proxy trap constructor returned non-object value");
}
// 11. Return newObj.

14
boa/src/object/jsobject.rs

@ -480,9 +480,7 @@ impl JsObject {
// b. If IsCallable(getter) is false and getter is not undefined, throw a TypeError exception.
// todo: extract IsCallable to be callable from Value
if !getter.is_undefined() && getter.as_object().map_or(true, |o| !o.is_callable()) {
return Err(
context.construct_type_error("Property descriptor getter must be callable")
);
return context.throw_type_error("Property descriptor getter must be callable");
}
// c. Set desc.[[Get]] to getter.
Some(getter)
@ -498,9 +496,7 @@ impl JsObject {
// 14.b. If IsCallable(setter) is false and setter is not undefined, throw a TypeError exception.
// todo: extract IsCallable to be callable from Value
if !setter.is_undefined() && setter.as_object().map_or(true, |o| !o.is_callable()) {
return Err(
context.construct_type_error("Property descriptor setter must be callable")
);
return context.throw_type_error("Property descriptor setter must be callable");
}
// 14.c. Set desc.[[Set]] to setter.
Some(setter)
@ -511,10 +507,10 @@ impl JsObject {
// 15. If desc.[[Get]] is present or desc.[[Set]] is present, then ...
// a. If desc.[[Value]] is present or desc.[[Writable]] is present, throw a TypeError exception.
if get.as_ref().or_else(|| set.as_ref()).is_some() && desc.inner().is_data_descriptor() {
return Err(context.construct_type_error(
return context.throw_type_error(
"Invalid property descriptor.\
Cannot both specify accessors and a value or writable attribute",
));
Cannot both specify accessors and a value or writable attribute",
);
}
desc = desc.maybe_get(get).maybe_set(set);

25
boa/src/object/operations.rs

@ -91,9 +91,7 @@ impl JsObject {
let success = self.__set__(key.clone(), value.into(), self.clone().into(), context)?;
// 5. If success is false and Throw is true, throw a TypeError exception.
if !success && throw {
return Err(
context.construct_type_error(format!("cannot set non-writable property: {}", key))
);
return context.throw_type_error(format!("cannot set non-writable property: {}", key));
}
// 6. Return success.
Ok(success)
@ -152,7 +150,7 @@ impl JsObject {
let success = self.create_data_property(key.clone(), value, context)?;
// 4. If success is false, throw a TypeError exception.
if !success {
return Err(context.construct_type_error(format!("cannot redefine property: {}", key)));
return context.throw_type_error(format!("cannot redefine property: {}", key));
}
// 5. Return success.
Ok(success)
@ -182,7 +180,7 @@ impl JsObject {
let success = self.__define_own_property__(key.clone(), desc.into(), context)?;
// 4. If success is false, throw a TypeError exception.
if !success {
return Err(context.construct_type_error(format!("cannot redefine property: {}", key)));
return context.throw_type_error(format!("cannot redefine property: {}", key));
}
// 5. Return success.
Ok(success)
@ -206,7 +204,7 @@ impl JsObject {
let success = self.__delete__(&key, context)?;
// 4. If success is false, throw a TypeError exception.
if !success {
return Err(context.construct_type_error(format!("cannot delete property: {}", key)));
return context.throw_type_error(format!("cannot delete property: {}", key));
}
// 5. Return success.
Ok(success)
@ -451,7 +449,7 @@ impl JsObject {
// 4. If Type(C) is not Object, throw a TypeError exception.
if !c.is_object() {
return Err(context.construct_type_error("property 'constructor' is not an object"));
return context.throw_type_error("property 'constructor' is not an object");
}
// 5. Let S be ? Get(C, @@species).
@ -466,7 +464,7 @@ impl JsObject {
// 8. Throw a TypeError exception.
match s.as_object() {
Some(obj) if obj.is_constructor() => Ok(obj.clone()),
_ => Err(context.construct_type_error("property 'constructor' is not a constructor")),
_ => context.throw_type_error("property 'constructor' is not a constructor"),
}
}
@ -555,8 +553,9 @@ impl JsObject {
// 5. Return func.
JsValue::Object(obj) if obj.is_callable() => Ok(Some(obj.clone())),
// 4. If IsCallable(func) is false, throw a TypeError exception.
_ => Err(context
.construct_type_error("value returned for property of object is not a function")),
_ => {
context.throw_type_error("value returned for property of object is not a function")
}
}
}
@ -667,7 +666,7 @@ impl JsValue {
let next = obj.get(index, context)?;
// c. If Type(next) is not an element of elementTypes, throw a TypeError exception.
if !types.contains(&next.get_type()) {
return Err(context.construct_type_error("bad type"));
return context.throw_type_error("bad type");
}
// d. Append next as the last element of list.
list.push(next.clone());
@ -746,8 +745,8 @@ impl JsValue {
obj
} else {
// 5. If Type(P) is not Object, throw a TypeError exception.
return Err(context
.construct_type_error("function has non-object prototype in instanceof check"));
return context
.throw_type_error("function has non-object prototype in instanceof check");
};
// 6. Repeat,

8
boa/src/syntax/ast/node/declaration/mod.rs

@ -472,10 +472,10 @@ impl DeclarationPatternObject {
};
if value.is_null() {
return Err(context.construct_type_error("Cannot destructure 'null' value"));
return context.throw_type_error("Cannot destructure 'null' value");
}
if value.is_undefined() {
return Err(context.construct_type_error("Cannot destructure 'undefined' value"));
return context.throw_type_error("Cannot destructure 'undefined' value");
}
// 1. Perform ? RequireObjectCoercible(value).
@ -685,10 +685,10 @@ impl DeclarationPatternArray {
};
if value.is_null() {
return Err(context.construct_type_error("Cannot destructure 'null' value"));
return context.throw_type_error("Cannot destructure 'null' value");
}
if value.is_undefined() {
return Err(context.construct_type_error("Cannot destructure 'undefined' value"));
return context.throw_type_error("Cannot destructure 'undefined' value");
}
// 1. Let iteratorRecord be ? GetIterator(value).

42
boa/src/value/mod.rs

@ -374,7 +374,7 @@ impl JsValue {
// 5. If success is false and Throw is true, throw a TypeError exception.
// 6. Return success.
if !success && throw {
return Err(context.construct_type_error("Cannot assign value to property"));
return context.throw_type_error("Cannot assign value to property");
} else {
return Ok(value);
}
@ -435,7 +435,7 @@ impl JsValue {
// v. If Type(result) is not Object, return result.
// vi. Throw a TypeError exception.
return if result.is_object() {
Err(context.construct_type_error("Symbol.toPrimitive cannot return an object"))
context.throw_type_error("Symbol.toPrimitive cannot return an object")
} else {
Ok(result)
};
@ -465,33 +465,29 @@ impl JsValue {
/// [spec]: https://tc39.es/ecma262/#sec-tobigint
pub fn to_bigint(&self, context: &mut Context) -> JsResult<JsBigInt> {
match self {
JsValue::Null => Err(context.construct_type_error("cannot convert null to a BigInt")),
JsValue::Undefined => {
Err(context.construct_type_error("cannot convert undefined to a BigInt"))
}
JsValue::Null => context.throw_type_error("cannot convert null to a BigInt"),
JsValue::Undefined => context.throw_type_error("cannot convert undefined to a BigInt"),
JsValue::String(ref string) => {
if let Some(value) = JsBigInt::from_string(string) {
Ok(value)
} else {
Err(context.construct_syntax_error(format!(
context.throw_syntax_error(format!(
"cannot convert string '{}' to bigint primitive",
string
)))
))
}
}
JsValue::Boolean(true) => Ok(JsBigInt::one()),
JsValue::Boolean(false) => Ok(JsBigInt::zero()),
JsValue::Integer(_) | JsValue::Rational(_) => {
Err(context.construct_type_error("cannot convert Number to a BigInt"))
context.throw_type_error("cannot convert Number to a BigInt")
}
JsValue::BigInt(b) => Ok(b.clone()),
JsValue::Object(_) => {
let primitive = self.to_primitive(context, PreferredType::Number)?;
primitive.to_bigint(context)
}
JsValue::Symbol(_) => {
Err(context.construct_type_error("cannot convert Symbol to a BigInt"))
}
JsValue::Symbol(_) => context.throw_type_error("cannot convert Symbol to a BigInt"),
}
}
@ -522,9 +518,7 @@ impl JsValue {
JsValue::Rational(rational) => Ok(Number::to_native_string(*rational).into()),
JsValue::Integer(integer) => Ok(integer.to_string().into()),
JsValue::String(string) => Ok(string.clone()),
JsValue::Symbol(_) => {
Err(context.construct_type_error("can't convert symbol to string"))
}
JsValue::Symbol(_) => context.throw_type_error("can't convert symbol to string"),
JsValue::BigInt(ref bigint) => Ok(bigint.to_string().into()),
JsValue::Object(_) => {
let primitive = self.to_primitive(context, PreferredType::String)?;
@ -541,7 +535,7 @@ impl JsValue {
pub fn to_object(&self, context: &mut Context) -> JsResult<JsObject> {
match self {
JsValue::Undefined | JsValue::Null => {
Err(context.construct_type_error("cannot convert 'null' or 'undefined' to object"))
context.throw_type_error("cannot convert 'null' or 'undefined' to object")
}
JsValue::Boolean(boolean) => {
let prototype = context.standard_objects().boolean_object().prototype();
@ -859,13 +853,11 @@ impl JsValue {
let integer_index = self.to_integer(context)?;
if integer_index < 0.0 {
return Err(context.construct_range_error("Integer index must be >= 0"));
return context.throw_range_error("Integer index must be >= 0");
}
if integer_index > Number::MAX_SAFE_INTEGER {
return Err(
context.construct_range_error("Integer index must be less than 2**(53) - 1")
);
return context.throw_range_error("Integer index must be less than 2**(53) - 1");
}
Ok(integer_index as usize)
@ -922,12 +914,8 @@ impl JsValue {
JsValue::String(ref string) => Ok(string.string_to_number()),
JsValue::Rational(number) => Ok(number),
JsValue::Integer(integer) => Ok(f64::from(integer)),
JsValue::Symbol(_) => {
Err(context.construct_type_error("argument must not be a symbol"))
}
JsValue::BigInt(_) => {
Err(context.construct_type_error("argument must not be a bigint"))
}
JsValue::Symbol(_) => context.throw_type_error("argument must not be a symbol"),
JsValue::BigInt(_) => context.throw_type_error("argument must not be a bigint"),
JsValue::Object(_) => {
let primitive = self.to_primitive(context, PreferredType::Number)?;
primitive.to_number(context)
@ -962,7 +950,7 @@ impl JsValue {
#[inline]
pub fn require_object_coercible(&self, context: &mut Context) -> JsResult<&JsValue> {
if self.is_null_or_undefined() {
Err(context.construct_type_error("cannot convert null or undefined to Object"))
context.throw_type_error("cannot convert null or undefined to Object")
} else {
Ok(self)
}

6
boa/src/value/operations.rs

@ -398,10 +398,10 @@ impl JsValue {
pub fn instance_of(&self, target: &JsValue, context: &mut Context) -> JsResult<bool> {
// 1. If Type(target) is not Object, throw a TypeError exception.
if !target.is_object() {
return Err(context.construct_type_error(format!(
return context.throw_type_error(format!(
"right-hand side of 'instanceof' should be an object, got {}",
target.type_of()
)));
));
}
// 2. Let instOfHandler be ? GetMethod(target, @@hasInstance).
@ -419,7 +419,7 @@ impl JsValue {
}
None => {
// 4. If IsCallable(target) is false, throw a TypeError exception.
Err(context.construct_type_error("right-hand side of 'instanceof' is not callable"))
context.throw_type_error("right-hand side of 'instanceof' is not callable")
}
}
}

20
boa/src/vm/mod.rs

@ -225,10 +225,10 @@ impl Context {
let lhs = self.vm.pop();
if !rhs.is_object() {
return Err(self.construct_type_error(format!(
return self.throw_type_error(format!(
"right-hand side of 'in' should be an object, got {}",
rhs.type_of()
)));
));
}
let key = lhs.to_property_key(self)?;
let value = self.has_property(&rhs, &key)?;
@ -634,7 +634,7 @@ impl Context {
}
Opcode::Call => {
if self.vm.stack_size_limit <= self.vm.stack.len() {
return Err(self.construct_range_error("Maximum call stack size exceeded"));
return self.throw_range_error("Maximum call stack size exceeded");
}
let argc = self.vm.read::<u32>();
let mut args = Vec::with_capacity(argc as usize);
@ -647,7 +647,7 @@ impl Context {
let object = match func {
JsValue::Object(ref object) if object.is_callable() => object.clone(),
_ => return Err(self.construct_type_error("not a callable function")),
_ => return self.throw_type_error("not a callable function"),
};
let result = object.__call__(&this, &args, self)?;
@ -656,7 +656,7 @@ impl Context {
}
Opcode::CallWithRest => {
if self.vm.stack_size_limit <= self.vm.stack.len() {
return Err(self.construct_range_error("Maximum call stack size exceeded"));
return self.throw_range_error("Maximum call stack size exceeded");
}
let argc = self.vm.read::<u32>();
let mut args = Vec::with_capacity(argc as usize);
@ -680,7 +680,7 @@ impl Context {
let object = match func {
JsValue::Object(ref object) if object.is_callable() => object.clone(),
_ => return Err(self.construct_type_error("not a callable function")),
_ => return self.throw_type_error("not a callable function"),
};
let result = object.__call__(&this, &args, self)?;
@ -689,7 +689,7 @@ impl Context {
}
Opcode::New => {
if self.vm.stack_size_limit <= self.vm.stack.len() {
return Err(self.construct_range_error("Maximum call stack size exceeded"));
return self.throw_range_error("Maximum call stack size exceeded");
}
let argc = self.vm.read::<u32>();
let mut args = Vec::with_capacity(argc as usize);
@ -707,7 +707,7 @@ impl Context {
}
Opcode::NewWithRest => {
if self.vm.stack_size_limit <= self.vm.stack.len() {
return Err(self.construct_range_error("Maximum call stack size exceeded"));
return self.throw_range_error("Maximum call stack size exceeded");
}
let argc = self.vm.read::<u32>();
let mut args = Vec::with_capacity(argc as usize);
@ -854,10 +854,10 @@ impl Context {
Opcode::ValueNotNullOrUndefined => {
let value = self.vm.pop();
if value.is_null() {
return Err(self.construct_type_error("Cannot destructure 'null' value"));
return self.throw_type_error("Cannot destructure 'null' value");
}
if value.is_undefined() {
return Err(self.construct_type_error("Cannot destructure 'undefined' value"));
return self.throw_type_error("Cannot destructure 'undefined' value");
}
self.vm.push(value);
}

2
boa_tester/src/exec/js262.rs

@ -67,7 +67,7 @@ fn detach_array_buffer(
// 3. If SameValue(arrayBuffer.[[ArrayBufferDetachKey]], key) is false, throw a TypeError exception.
if !JsValue::same_value(&array_buffer.array_buffer_detach_key, key) {
return Err(context.construct_type_error("Cannot detach array buffer with different key"));
return context.throw_type_error("Cannot detach array buffer with different key");
}
// 4. Set arrayBuffer.[[ArrayBufferData]] to null.

5
boa_wasm/src/lib.rs

@ -11,10 +11,7 @@ pub fn evaluate(src: &str) -> Result<String, JsValue> {
Err(e) => {
return Err(format!(
"Uncaught {}",
context
.throw_syntax_error(e.to_string())
.expect_err("interpreter.throw_syntax_error() did not return an error")
.display()
context.construct_syntax_error(e.to_string()).display()
)
.into());
}

Loading…
Cancel
Save