LibWeb: Use WebIDL::invoke_promise_callback in Streams where appropriate
Some checks are pending
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (arm64, macos-15, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (x86_64, ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run

This avoids an issue where rejected JS::Promise types were converted to
a resolved WebIDL::Promise type.
This commit is contained in:
Timothy Flynn 2025-04-15 13:45:00 -04:00 committed by Tim Flynn
commit b1a189acfa
Notes: github-actions[bot] 2025-04-16 08:06:22 +00:00
2 changed files with 36 additions and 52 deletions

View file

@ -3141,29 +3141,28 @@ WebIDL::ExceptionOr<void> set_up_readable_stream_default_controller_from_underly
return WebIDL::create_resolved_promise(realm, JS::js_undefined()); return WebIDL::create_resolved_promise(realm, JS::js_undefined());
}); });
// 5. If underlyingSourceDict["start"] exists, then set startAlgorithm to an algorithm which returns the result of invoking underlyingSourceDict["start"] with argument list « controller » and callback this value underlyingSource. // 5. If underlyingSourceDict["start"] exists, then set startAlgorithm to an algorithm which returns the result of
// invoking underlyingSourceDict["start"] with argument list « controller » and callback this value underlyingSource.
if (underlying_source.start) { if (underlying_source.start) {
start_algorithm = GC::create_function(realm.heap(), [controller, underlying_source_value, callback = underlying_source.start]() -> WebIDL::ExceptionOr<JS::Value> { start_algorithm = GC::create_function(realm.heap(), [controller, underlying_source_value, callback = underlying_source.start]() -> WebIDL::ExceptionOr<JS::Value> {
// Note: callback does not return a promise, so invoke_callback may return an abrupt completion
return TRY(WebIDL::invoke_callback(*callback, underlying_source_value, controller)); return TRY(WebIDL::invoke_callback(*callback, underlying_source_value, controller));
}); });
} }
// 6. If underlyingSourceDict["pull"] exists, then set pullAlgorithm to an algorithm which returns the result of invoking underlyingSourceDict["pull"] with argument list « controller » and callback this value underlyingSource. // 6. If underlyingSourceDict["pull"] exists, then set pullAlgorithm to an algorithm which returns the result of
// invoking underlyingSourceDict["pull"] with argument list « controller » and callback this value underlyingSource.
if (underlying_source.pull) { if (underlying_source.pull) {
pull_algorithm = GC::create_function(realm.heap(), [&realm, controller, underlying_source_value, callback = underlying_source.pull]() { pull_algorithm = GC::create_function(realm.heap(), [controller, underlying_source_value, callback = underlying_source.pull]() {
// Note: callback returns a promise, so invoke_callback will never return an abrupt completion return WebIDL::invoke_promise_callback(*callback, underlying_source_value, controller);
auto result = MUST(WebIDL::invoke_callback(*callback, underlying_source_value, controller));
return WebIDL::create_resolved_promise(realm, result);
}); });
} }
// 7. If underlyingSourceDict["cancel"] exists, then set cancelAlgorithm to an algorithm which takes an argument reason and returns the result of invoking underlyingSourceDict["cancel"] with argument list « reason » and callback this value underlyingSource. // 7. If underlyingSourceDict["cancel"] exists, then set cancelAlgorithm to an algorithm which takes an argument
// reason and returns the result of invoking underlyingSourceDict["cancel"] with argument list « reason » and
// callback this value underlyingSource.
if (underlying_source.cancel) { if (underlying_source.cancel) {
cancel_algorithm = GC::create_function(realm.heap(), [&realm, underlying_source_value, callback = underlying_source.cancel](JS::Value reason) { cancel_algorithm = GC::create_function(realm.heap(), [underlying_source_value, callback = underlying_source.cancel](JS::Value reason) {
// Note: callback returns a promise, so invoke_callback will never return an abrupt completion return WebIDL::invoke_promise_callback(*callback, underlying_source_value, reason);
auto result = MUST(WebIDL::invoke_callback(*callback, underlying_source_value, reason));
return WebIDL::create_resolved_promise(realm, result);
}); });
} }
@ -4847,7 +4846,6 @@ WebIDL::ExceptionOr<void> set_up_writable_stream_default_controller_from_underly
// callback this value underlyingSink. // callback this value underlyingSink.
if (underlying_sink.start) { if (underlying_sink.start) {
start_algorithm = GC::create_function(realm.heap(), [controller, underlying_sink_value, callback = underlying_sink.start]() -> WebIDL::ExceptionOr<JS::Value> { start_algorithm = GC::create_function(realm.heap(), [controller, underlying_sink_value, callback = underlying_sink.start]() -> WebIDL::ExceptionOr<JS::Value> {
// Note: callback does not return a promise, so invoke_callback may return an abrupt completion
return TRY(WebIDL::invoke_callback(*callback, underlying_sink_value, WebIDL::ExceptionBehavior::Rethrow, controller)); return TRY(WebIDL::invoke_callback(*callback, underlying_sink_value, WebIDL::ExceptionBehavior::Rethrow, controller));
}); });
} }
@ -4856,20 +4854,16 @@ WebIDL::ExceptionOr<void> set_up_writable_stream_default_controller_from_underly
// and returns the result of invoking underlyingSinkDict["write"] with argument list « chunk, controller » and // and returns the result of invoking underlyingSinkDict["write"] with argument list « chunk, controller » and
// callback this value underlyingSink. // callback this value underlyingSink.
if (underlying_sink.write) { if (underlying_sink.write) {
write_algorithm = GC::create_function(realm.heap(), [&realm, controller, underlying_sink_value, callback = underlying_sink.write](JS::Value chunk) { write_algorithm = GC::create_function(realm.heap(), [controller, underlying_sink_value, callback = underlying_sink.write](JS::Value chunk) {
// Note: callback returns a promise, so invoke_callback will never return an abrupt completion return WebIDL::invoke_promise_callback(*callback, underlying_sink_value, chunk, controller);
auto result = MUST(WebIDL::invoke_callback(*callback, underlying_sink_value, chunk, controller));
return WebIDL::create_resolved_promise(realm, result);
}); });
} }
// 8. If underlyingSinkDict["close"] exists, then set closeAlgorithm to an algorithm which returns the result of // 8. If underlyingSinkDict["close"] exists, then set closeAlgorithm to an algorithm which returns the result of
// invoking underlyingSinkDict["close"] with argument list «» and callback this value underlyingSink. // invoking underlyingSinkDict["close"] with argument list «» and callback this value underlyingSink.
if (underlying_sink.close) { if (underlying_sink.close) {
close_algorithm = GC::create_function(realm.heap(), [&realm, underlying_sink_value, callback = underlying_sink.close]() { close_algorithm = GC::create_function(realm.heap(), [underlying_sink_value, callback = underlying_sink.close]() {
// Note: callback returns a promise, so invoke_callback will never return an abrupt completion return WebIDL::invoke_promise_callback(*callback, underlying_sink_value);
auto result = MUST(WebIDL::invoke_callback(*callback, underlying_sink_value));
return WebIDL::create_resolved_promise(realm, result);
}); });
} }
@ -4877,10 +4871,8 @@ WebIDL::ExceptionOr<void> set_up_writable_stream_default_controller_from_underly
// and returns the result of invoking underlyingSinkDict["abort"] with argument list « reason » and callback this // and returns the result of invoking underlyingSinkDict["abort"] with argument list « reason » and callback this
// value underlyingSink. // value underlyingSink.
if (underlying_sink.abort) { if (underlying_sink.abort) {
abort_algorithm = GC::create_function(realm.heap(), [&realm, underlying_sink_value, callback = underlying_sink.abort](JS::Value reason) { abort_algorithm = GC::create_function(realm.heap(), [underlying_sink_value, callback = underlying_sink.abort](JS::Value reason) {
// Note: callback returns a promise, so invoke_callback will never return an abrupt completion return WebIDL::invoke_promise_callback(*callback, underlying_sink_value, reason);
auto result = MUST(WebIDL::invoke_callback(*callback, underlying_sink_value, reason));
return WebIDL::create_resolved_promise(realm, result);
}); });
} }
@ -5282,30 +5274,24 @@ void set_up_transform_stream_default_controller_from_transformer(TransformStream
// and returns the result of invoking transformerDict["transform"] with argument list « chunk, controller » and // and returns the result of invoking transformerDict["transform"] with argument list « chunk, controller » and
// callback this value transformer. // callback this value transformer.
if (transformer_dict.transform) { if (transformer_dict.transform) {
transform_algorithm = GC::create_function(realm.heap(), [controller, &realm, transformer, callback = transformer_dict.transform](JS::Value chunk) { transform_algorithm = GC::create_function(realm.heap(), [controller, transformer, callback = transformer_dict.transform](JS::Value chunk) {
// Note: callback returns a promise, so invoke_callback will never return an abrupt completion return WebIDL::invoke_promise_callback(*callback, transformer, chunk, controller);
auto result = MUST(WebIDL::invoke_callback(*callback, transformer, chunk, controller));
return WebIDL::create_resolved_promise(realm, result);
}); });
} }
// 6. If transformerDict["flush"] exists, set flushAlgorithm to an algorithm which returns the result of invoking // 6. If transformerDict["flush"] exists, set flushAlgorithm to an algorithm which returns the result of invoking
// transformerDict["flush"] with argument list « controller » and callback this value transformer. // transformerDict["flush"] with argument list « controller » and callback this value transformer.
if (transformer_dict.flush) { if (transformer_dict.flush) {
flush_algorithm = GC::create_function(realm.heap(), [&realm, transformer, callback = transformer_dict.flush, controller]() { flush_algorithm = GC::create_function(realm.heap(), [transformer, callback = transformer_dict.flush, controller]() {
// Note: callback returns a promise, so invoke_callback will never return an abrupt completion return WebIDL::invoke_promise_callback(*callback, transformer, controller);
auto result = MUST(WebIDL::invoke_callback(*callback, transformer, controller));
return WebIDL::create_resolved_promise(realm, result);
}); });
} }
// 7. If transformerDict["cancel"] exists, set cancelAlgorithm to an algorithm which takes an argument reason and returns // 7. If transformerDict["cancel"] exists, set cancelAlgorithm to an algorithm which takes an argument reason and returns
// the result of invoking transformerDict["cancel"] with argument list « reason » and callback this value transformer. // the result of invoking transformerDict["cancel"] with argument list « reason » and callback this value transformer.
if (transformer_dict.cancel) { if (transformer_dict.cancel) {
cancel_algorithm = GC::create_function(realm.heap(), [&realm, transformer, callback = transformer_dict.cancel](JS::Value reason) { cancel_algorithm = GC::create_function(realm.heap(), [transformer, callback = transformer_dict.cancel](JS::Value reason) {
// Note: callback returns a promise, so invoke_callback will never return an abrupt completion return WebIDL::invoke_promise_callback(*callback, transformer, reason);
auto result = MUST(WebIDL::invoke_callback(*callback, transformer, reason));
return WebIDL::create_resolved_promise(realm, result);
}); });
} }
@ -5826,29 +5812,28 @@ WebIDL::ExceptionOr<void> set_up_readable_byte_stream_controller_from_underlying
return WebIDL::create_resolved_promise(realm, JS::js_undefined()); return WebIDL::create_resolved_promise(realm, JS::js_undefined());
}); });
// 5. If underlyingSourceDict["start"] exists, then set startAlgorithm to an algorithm which returns the result of invoking underlyingSourceDict["start"] with argument list « controller » and callback this value underlyingSource. // 5. If underlyingSourceDict["start"] exists, then set startAlgorithm to an algorithm which returns the result of
// invoking underlyingSourceDict["start"] with argument list « controller » and callback this value underlyingSource.
if (underlying_source_dict.start) { if (underlying_source_dict.start) {
start_algorithm = GC::create_function(realm.heap(), [controller, underlying_source, callback = underlying_source_dict.start]() -> WebIDL::ExceptionOr<JS::Value> { start_algorithm = GC::create_function(realm.heap(), [controller, underlying_source, callback = underlying_source_dict.start]() -> WebIDL::ExceptionOr<JS::Value> {
// Note: callback does not return a promise, so invoke_callback may return an abrupt completion
return TRY(WebIDL::invoke_callback(*callback, underlying_source, controller)); return TRY(WebIDL::invoke_callback(*callback, underlying_source, controller));
}); });
} }
// 6. If underlyingSourceDict["pull"] exists, then set pullAlgorithm to an algorithm which returns the result of invoking underlyingSourceDict["pull"] with argument list « controller » and callback this value underlyingSource. // 6. If underlyingSourceDict["pull"] exists, then set pullAlgorithm to an algorithm which returns the result of
// invoking underlyingSourceDict["pull"] with argument list « controller » and callback this value underlyingSource.
if (underlying_source_dict.pull) { if (underlying_source_dict.pull) {
pull_algorithm = GC::create_function(realm.heap(), [&realm, controller, underlying_source, callback = underlying_source_dict.pull]() { pull_algorithm = GC::create_function(realm.heap(), [controller, underlying_source, callback = underlying_source_dict.pull]() {
// Note: callback returns a promise, so invoke_callback will never return an abrupt completion return WebIDL::invoke_promise_callback(*callback, underlying_source, controller);
auto result = MUST(WebIDL::invoke_callback(*callback, underlying_source, controller));
return WebIDL::create_resolved_promise(realm, result);
}); });
} }
// 7. If underlyingSourceDict["cancel"] exists, then set cancelAlgorithm to an algorithm which takes an argument reason and returns the result of invoking underlyingSourceDict["cancel"] with argument list « reason » and callback this value underlyingSource. // 7. If underlyingSourceDict["cancel"] exists, then set cancelAlgorithm to an algorithm which takes an argument
// reason and returns the result of invoking underlyingSourceDict["cancel"] with argument list « reason » and
// callback this value underlyingSource.
if (underlying_source_dict.cancel) { if (underlying_source_dict.cancel) {
cancel_algorithm = GC::create_function(realm.heap(), [&realm, underlying_source, callback = underlying_source_dict.cancel](JS::Value reason) { cancel_algorithm = GC::create_function(realm.heap(), [underlying_source, callback = underlying_source_dict.cancel](JS::Value reason) {
// Note: callback returns a promise, so invoke_callback will never return an abrupt completion return WebIDL::invoke_promise_callback(*callback, underlying_source, reason);
auto result = MUST(WebIDL::invoke_callback(*callback, underlying_source, reason));
return WebIDL::create_resolved_promise(realm, result);
}); });
} }

View file

@ -2,12 +2,11 @@ Harness status: OK
Found 26 tests Found 26 tests
25 Pass 26 Pass
1 Fail
Pass ReadableStream teeing: rs.tee() returns an array of two ReadableStreams Pass ReadableStream teeing: rs.tee() returns an array of two ReadableStreams
Pass ReadableStream teeing: should be able to read one branch to the end without affecting the other Pass ReadableStream teeing: should be able to read one branch to the end without affecting the other
Pass ReadableStream teeing: values should be equal across each branch Pass ReadableStream teeing: values should be equal across each branch
Fail ReadableStream teeing: errors in the source should propagate to both branches Pass ReadableStream teeing: errors in the source should propagate to both branches
Pass ReadableStream teeing: canceling branch1 should not impact branch2 Pass ReadableStream teeing: canceling branch1 should not impact branch2
Pass ReadableStream teeing: canceling branch2 should not impact branch1 Pass ReadableStream teeing: canceling branch2 should not impact branch1
Pass Running templatedRSTeeCancel with ReadableStream teeing Pass Running templatedRSTeeCancel with ReadableStream teeing