From f526513d74d34ac254aa40ef9b73238cb21c395b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Mon, 28 Nov 2022 23:07:23 +0100 Subject: feat(core): show unresolved promise origin (#16650) This commit updates unhelpful messages that are raised when event loop stalls on unresolved top-level promises. Instead of "Module evaluation is still pending but there are no pending ops or dynamic imports. This situation is often caused by unresolved promises." and "Dynamically imported module evaluation is still pending but there are no pending ops. This situation is often caused by unresolved promises." we are now printing a message like: error: Top-level await promise never resolved [SOURCE LINE] ^ at [FUNCTION NAME] ([FILENAME]) eg: error: Top-level await promise never resolved await new Promise((_resolve, _reject) => {}); ^ at (file:///Users/ib/dev/deno/cli/tests/testdata/test/unresolved_promise.ts:1:1) Co-authored-by: David Sherret --- core/error.rs | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) (limited to 'core/error.rs') diff --git a/core/error.rs b/core/error.rs index d71da3164..fb9bdf8e4 100644 --- a/core/error.rs +++ b/core/error.rs @@ -207,6 +207,84 @@ impl JsError { Self::inner_from_v8_exception(scope, exception, Default::default()) } + pub fn from_v8_message<'a>( + scope: &'a mut v8::HandleScope, + msg: v8::Local<'a, v8::Message>, + ) -> Self { + // Create a new HandleScope because we're creating a lot of new local + // handles below. + let scope = &mut v8::HandleScope::new(scope); + + let exception_message = msg.get(scope).to_rust_string_lossy(scope); + let state_rc = JsRuntime::state(scope); + + // Convert them into Vec + let mut frames: Vec = vec![]; + + let mut source_line = None; + let mut source_line_frame_index = None; + { + let state = &mut *state_rc.borrow_mut(); + + let script_resource_name = msg + .get_script_resource_name(scope) + .and_then(|v| v8::Local::::try_from(v).ok()) + .map(|v| v.to_rust_string_lossy(scope)); + let line_number: Option = + msg.get_line_number(scope).and_then(|v| v.try_into().ok()); + let column_number: Option = msg.get_start_column().try_into().ok(); + if let (Some(f), Some(l), Some(c)) = + (script_resource_name, line_number, column_number) + { + // V8's column numbers are 0-based, we want 1-based. + let c = c + 1; + if let Some(source_map_getter) = &state.source_map_getter { + let (f, l, c) = apply_source_map( + f, + l, + c, + &mut state.source_map_cache, + source_map_getter.as_ref(), + ); + frames = vec![JsStackFrame::from_location(Some(f), Some(l), Some(c))]; + } else { + frames = vec![JsStackFrame::from_location(Some(f), Some(l), Some(c))]; + } + } + + if let Some(source_map_getter) = &state.source_map_getter { + for (i, frame) in frames.iter().enumerate() { + if let (Some(file_name), Some(line_number)) = + (&frame.file_name, frame.line_number) + { + if !file_name.trim_start_matches('[').starts_with("deno:") { + source_line = get_source_line( + file_name, + line_number, + &mut state.source_map_cache, + source_map_getter.as_ref(), + ); + source_line_frame_index = Some(i); + break; + } + } + } + } + } + + Self { + name: None, + message: None, + exception_message, + cause: None, + source_line, + source_line_frame_index, + frames, + stack: None, + aggregated: None, + } + } + fn inner_from_v8_exception<'a>( scope: &'a mut v8::HandleScope, exception: v8::Local<'a, v8::Value>, @@ -330,7 +408,6 @@ impl JsError { (&frame.file_name, frame.line_number) { if !file_name.trim_start_matches('[').starts_with("deno:") { - // Source lookup expects a 0-based line number, ours are 1-based. source_line = get_source_line( file_name, line_number, -- cgit v1.2.3