mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 23:34:47 -05:00
fix(core): fix top-level-await error handling (#4911)
This commit is contained in:
parent
dd0b25e313
commit
7a94ea08e9
2 changed files with 29 additions and 4 deletions
|
@ -1341,7 +1341,6 @@ itest!(error_013_missing_script {
|
||||||
itest!(error_014_catch_dynamic_import_error {
|
itest!(error_014_catch_dynamic_import_error {
|
||||||
args: "run --reload --allow-read error_014_catch_dynamic_import_error.js",
|
args: "run --reload --allow-read error_014_catch_dynamic_import_error.js",
|
||||||
output: "error_014_catch_dynamic_import_error.js.out",
|
output: "error_014_catch_dynamic_import_error.js.out",
|
||||||
exit_code: 1,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
itest!(error_015_dynamic_import_permissions {
|
itest!(error_015_dynamic_import_permissions {
|
||||||
|
|
|
@ -18,6 +18,7 @@ use futures::task::AtomicWaker;
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::option::Option;
|
use std::option::Option;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
|
@ -233,16 +234,41 @@ impl EsIsolate {
|
||||||
let info = self.modules.get_info(id).expect("ModuleInfo not found");
|
let info = self.modules.get_info(id).expect("ModuleInfo not found");
|
||||||
let module = info.handle.get(scope).expect("Empty module handle");
|
let module = info.handle.get(scope).expect("Empty module handle");
|
||||||
let mut status = module.get_status();
|
let mut status = module.get_status();
|
||||||
|
|
||||||
if status == v8::ModuleStatus::Instantiated {
|
if status == v8::ModuleStatus::Instantiated {
|
||||||
let ok = module.evaluate(scope, context).is_some();
|
// IMPORTANT: Top-level-await is enabled, which means that return value
|
||||||
|
// of module evaluation is a promise.
|
||||||
|
//
|
||||||
|
// Because that promise is created internally by V8, when error occurs during
|
||||||
|
// module evaluation the promise is rejected, and since the promise has no rejection
|
||||||
|
// handler it will result in call to `bindings::promise_reject_callback` adding
|
||||||
|
// the promise to pending promise rejection table - meaning Isolate will return
|
||||||
|
// error on next poll().
|
||||||
|
//
|
||||||
|
// This situation is not desirable as we want to manually return error at the
|
||||||
|
// end of this function to handle it further. It means we need to manually
|
||||||
|
// remove this promise from pending promise rejection table.
|
||||||
|
//
|
||||||
|
// For more details see:
|
||||||
|
// https://github.com/denoland/deno/issues/4908
|
||||||
|
// https://v8.dev/features/top-level-await#module-execution-order
|
||||||
|
let maybe_value = module.evaluate(scope, context);
|
||||||
|
|
||||||
// Update status after evaluating.
|
// Update status after evaluating.
|
||||||
status = module.get_status();
|
status = module.get_status();
|
||||||
if ok {
|
|
||||||
|
if let Some(value) = maybe_value {
|
||||||
assert!(
|
assert!(
|
||||||
status == v8::ModuleStatus::Evaluated
|
status == v8::ModuleStatus::Evaluated
|
||||||
|| status == v8::ModuleStatus::Errored
|
|| status == v8::ModuleStatus::Errored
|
||||||
);
|
);
|
||||||
|
let promise = v8::Local::<v8::Promise>::try_from(value)
|
||||||
|
.expect("Expected to get promise as module evaluation result");
|
||||||
|
let promise_id = promise.get_identity_hash();
|
||||||
|
if let Some(mut handle) =
|
||||||
|
core_isolate.pending_promise_exceptions.remove(&promise_id)
|
||||||
|
{
|
||||||
|
handle.reset(scope);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
assert!(status == v8::ModuleStatus::Errored);
|
assert!(status == v8::ModuleStatus::Errored);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue