Skip to content

Commit

Permalink
Implement Error cause.
Browse files Browse the repository at this point in the history
Summary:
https://tc39.es/proposal-error-cause/

This is a stage 3 proposal to add a `cause` property to JSErrors
when the option is provided in the constructor.

Add a check in the Error constructor which checks for the property
and defines it if it exists.

Reviewed By: dulinriley

Differential Revision: D27102691

fbshipit-source-id: 45c02c9ed009961a0442bd5c7534fc509310d26c
  • Loading branch information
avp authored and facebook-github-bot committed Mar 22, 2021
1 parent 06b4381 commit 56e7cda
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/hermes/VM/PredefinedStrings.def
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ STR(gc, "gc")
STR(name, "name")
STR(displayName, "displayName")
STR(message, "message")
STR(cause, "cause")
STR(stack, "stack")
STR(stacktraceTooLong, "Stacktrace too long")
#define ALL_ERROR_TYPE(name) STR(name, "" #name)
Expand Down
32 changes: 32 additions & 0 deletions lib/VM/JSLib/Error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,38 @@ static CallResult<HermesValue> constructErrorObject(
}
}

// https://tc39.es/proposal-error-cause/
// InstallErrorCause(O, options).
// If Type(options) is Object and ? HasProperty(options, "cause") is true
if (Handle<JSObject> options = args.dyncastArg<JSObject>(1)) {
GCScopeMarkerRAII marker{runtime};
NamedPropertyDescriptor desc;
Handle<JSObject> propObj =
runtime->makeHandle(JSObject::getNamedDescriptorPredefined(
options, runtime, Predefined::cause, desc));
if (propObj) {
// a. Let cause be ? Get(options, "cause").
auto causeRes = JSObject::getNamedPropertyValue_RJS(
selfHandle, runtime, std::move(propObj), desc);
if (LLVM_UNLIKELY(causeRes == ExecutionStatus::EXCEPTION)) {
return ExecutionStatus::EXCEPTION;
}
Handle<> cause = runtime->makeHandle(std::move(*causeRes));
// b. Perform ! CreateNonEnumerableDataPropertyOrThrow(O, "cause", cause).
if (LLVM_UNLIKELY(
JSObject::defineOwnProperty(
selfHandle,
runtime,
Predefined::getSymbolID(Predefined::cause),
DefinePropertyFlags::getNewNonEnumerableFlags(),
cause,
PropOpFlags().plusThrowOnError()) ==
ExecutionStatus::EXCEPTION)) {
return ExecutionStatus::EXCEPTION;
}
}
}

return selfHandle.getHermesValue();
}

Expand Down
47 changes: 47 additions & 0 deletions test/hermes/error-cause.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

// RUN: %hermes -O %s | %FileCheck --match-full-lines %s
// RUN: %hermes -O -emit-binary -out %t.hbc %s && %hermes %t.hbc | %FileCheck --match-full-lines %s

print('error cause');
// CHECK-LABEL: error cause

try {
try {
throw Error("err1");
} catch (e1) {
throw Error("err2", { cause: e1 });
}
} catch (e2) {
print(e2.message);
// CHECK-NEXT: err2
print(e2.cause.message);
// CHECK-NEXT: err1
}

try {
throw Error("err", {get cause() {
print('getter');
return 'foo';
}});
// CHECK-NEXT: getter
} catch (e) {
print(e.message);
// CHECK-NEXT: err
print(e.cause);
// CHECK-NEXT: foo
}

try {
throw Error("err", {});
} catch (e) {
print(e.message);
// CHECK-NEXT: err
print(Object.hasOwnProperty(e, 'cause'));
// CHECK-NEXT: false
}

0 comments on commit 56e7cda

Please sign in to comment.