diff --git a/pkg/front_end/testcases/extensions/async_extensions.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/async_extensions.dart.strong.transformed.expect index 1ef6cf1c6b0..f4de67a6276 100644 --- a/pkg/front_end/testcases/extensions/async_extensions.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/extensions/async_extensions.dart.strong.transformed.expect @@ -12,13 +12,14 @@ extension Extension on core::int* { tearoff asyncStarMethod = self::Extension|get#asyncStarMethod; } static method Extension|syncStarMethod(final core::int* #this) → dynamic /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { {} return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } diff --git a/pkg/front_end/testcases/general/async_function.dart.strong.transformed.expect b/pkg/front_end/testcases/general/async_function.dart.strong.transformed.expect index d341b2a688d..056a35a872d 100644 --- a/pkg/front_end/testcases/general/async_function.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/general/async_function.dart.strong.transformed.expect @@ -62,10 +62,10 @@ static method asyncString2() → asy::Future* /* originally async return :async_completer.{asy::Completer::future}; } static method syncStarString() → core::Iterable* /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = "foo"; @@ -81,15 +81,16 @@ static method syncStarString() → core::Iterable* /* originally } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } static method syncStarString2() → core::Iterable* /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = "foo"; @@ -97,7 +98,8 @@ static method syncStarString2() → core::Iterable* /* originally } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/async_function.dart.weak.transformed.expect b/pkg/front_end/testcases/general_nnbd_opt_out/async_function.dart.weak.transformed.expect index d341b2a688d..056a35a872d 100644 --- a/pkg/front_end/testcases/general_nnbd_opt_out/async_function.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/general_nnbd_opt_out/async_function.dart.weak.transformed.expect @@ -62,10 +62,10 @@ static method asyncString2() → asy::Future* /* originally async return :async_completer.{asy::Completer::future}; } static method syncStarString() → core::Iterable* /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = "foo"; @@ -81,15 +81,16 @@ static method syncStarString() → core::Iterable* /* originally } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } static method syncStarString2() → core::Iterable* /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = "foo"; @@ -97,7 +98,8 @@ static method syncStarString2() → core::Iterable* /* originally } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } diff --git a/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_sync_star.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_sync_star.dart.strong.transformed.expect index 8ef54ea79ae..ad5d5f072a1 100644 --- a/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_sync_star.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_sync_star.dart.strong.transformed.expect @@ -4,10 +4,10 @@ import "dart:core" as core; static method main() → dynamic { () →* core::Iterable* f = () → core::Iterable* /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = null; @@ -15,7 +15,8 @@ static method main() → dynamic { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); }; diff --git a/pkg/front_end/testcases/inference/block_bodied_lambdas_sync_star.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/block_bodied_lambdas_sync_star.dart.strong.transformed.expect index 8ba245d984a..6dba5536460 100644 --- a/pkg/front_end/testcases/inference/block_bodied_lambdas_sync_star.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/inference/block_bodied_lambdas_sync_star.dart.strong.transformed.expect @@ -4,10 +4,10 @@ import "dart:core" as core; static method test() → dynamic { () →* core::Iterable* f = () → core::Iterable* /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = 1; @@ -19,7 +19,8 @@ static method test() → dynamic { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); }; diff --git a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.transformed.expect index 2cef8c56be6..91c81029ed8 100644 --- a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.transformed.expect @@ -139,10 +139,10 @@ static method foo() → asy::Stream*>* /* originally asyn return :controller_stream; } static method bar() → core::Iterable*>* /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = core::Map::•(); @@ -170,7 +170,8 @@ static method bar() → core::Iterable*>* /* o } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•*>(:sync_op_gen); } diff --git a/pkg/front_end/testcases/inference/infer_local_function_return_type.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/infer_local_function_return_type.dart.strong.transformed.expect index f330a82559c..ef727eb188c 100644 --- a/pkg/front_end/testcases/inference/infer_local_function_return_type.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/inference/infer_local_function_return_type.dart.strong.transformed.expect @@ -64,10 +64,10 @@ static method test() → dynamic { return :async_completer.{asy::Completer::future}; } function f4() → core::Iterable* /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = 42; @@ -75,7 +75,8 @@ static method test() → dynamic { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } diff --git a/pkg/front_end/testcases/inference/local_return_and_yield.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/local_return_and_yield.dart.strong.transformed.expect index 61d7ab70b8d..392e13e31ec 100644 --- a/pkg/front_end/testcases/inference/local_return_and_yield.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/inference/local_return_and_yield.dart.strong.transformed.expect @@ -49,10 +49,10 @@ static method main() → dynamic { return :async_completer.{asy::Completer::future}; } function c() → core::Iterable<(core::int*) →* core::int*>* /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = (core::int* x) → core::int* => x; @@ -60,15 +60,16 @@ static method main() → dynamic { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•<(core::int*) →* core::int*>(:sync_op_gen); } function d() → core::Iterable<(core::int*) →* core::int*>* /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_yieldEachIterable} = <(core::int*) →* core::int*>[(core::int* x) → core::int* => x]; @@ -76,7 +77,8 @@ static method main() → dynamic { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•<(core::int*) →* core::int*>(:sync_op_gen); } diff --git a/pkg/front_end/testcases/inference/top_level_return_and_yield.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/top_level_return_and_yield.dart.strong.transformed.expect index e58866d0885..e9c085d853a 100644 --- a/pkg/front_end/testcases/inference/top_level_return_and_yield.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/inference/top_level_return_and_yield.dart.strong.transformed.expect @@ -48,10 +48,10 @@ static method b() → asy::Future<(core::int*) →* core::int*>* /* originally a return :async_completer.{asy::Completer::future}; } static method c() → core::Iterable<(core::int*) →* core::int*>* /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = (core::int* x) → core::int* => x; @@ -59,15 +59,16 @@ static method c() → core::Iterable<(core::int*) →* core::int*>* /* originall } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•<(core::int*) →* core::int*>(:sync_op_gen); } static method d() → core::Iterable<(core::int*) →* core::int*>* /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_yieldEachIterable} = <(core::int*) →* core::int*>[(core::int* x) → core::int* => x]; @@ -75,7 +76,8 @@ static method d() → core::Iterable<(core::int*) →* core::int*>* /* originall } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•<(core::int*) →* core::int*>(:sync_op_gen); } diff --git a/pkg/front_end/testcases/nnbd/issue41437b.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue41437b.dart.strong.transformed.expect index bc6171e00b9..89e8bd511f5 100644 --- a/pkg/front_end/testcases/nnbd/issue41437b.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/nnbd/issue41437b.dart.strong.transformed.expect @@ -44,10 +44,10 @@ import "dart:async" as asy; static method getNull() → dynamic return null; static method getIterableNull() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = null; @@ -55,15 +55,16 @@ static method getIterableNull() → core::Iterable /* originally sync* } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } static method getIterableBool() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = true; @@ -71,15 +72,16 @@ static method getIterableBool() → core::Iterable /* originally syn } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } static method test1() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool; @@ -87,7 +89,8 @@ static method test1() → core::Iterable /* originally sync* */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } @@ -96,10 +99,10 @@ static method test2() → core::Iterable static method test3() → core::bool return self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool; static method test4() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_yieldEachIterable} = let final #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:21:10: Error: A value of type 'Iterable' can't be assigned to a variable of type 'Iterable'. @@ -110,7 +113,8 @@ static method test4() → core::Iterable /* originally sync* */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } @@ -122,10 +126,10 @@ Iterable test5() => getIterableNull(); // error static method test6() → core::Iterable return self::getIterableBool(); static method test7() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableBool(); @@ -133,7 +137,8 @@ static method test7() → core::Iterable /* originally sync* */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } @@ -150,10 +155,10 @@ static method test() → dynamic /* originally async */ { #L1: { function test1() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool; @@ -161,7 +166,8 @@ static method test() → dynamic /* originally async */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } @@ -170,10 +176,10 @@ static method test() → dynamic /* originally async */ { function test3() → core::bool return self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool; function test4() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_yieldEachIterable} = let final #t3 = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:38:12: Error: A value of type 'Iterable' can't be assigned to a variable of type 'Iterable'. @@ -184,7 +190,8 @@ static method test() → dynamic /* originally async */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } @@ -196,10 +203,10 @@ static method test() → dynamic /* originally async */ { function test6() → core::Iterable return self::getIterableBool(); function test7() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableBool(); @@ -207,7 +214,8 @@ static method test() → dynamic /* originally async */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } @@ -215,10 +223,10 @@ static method test() → dynamic /* originally async */ { - 'Iterable' is from 'dart:core'. })(); // error ^" in (() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = self::getNull(); @@ -226,7 +234,8 @@ static method test() → dynamic /* originally async */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); }).call() as{TypeError,ForNonNullableByDefault} core::Iterable; @@ -236,10 +245,10 @@ static method test() → dynamic /* originally async */ { - 'Iterable' is from 'dart:core'. })(); // error ^" in (() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableNull(); @@ -247,7 +256,8 @@ static method test() → dynamic /* originally async */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); }).call() as{TypeError,ForNonNullableByDefault} core::Iterable; @@ -257,10 +267,10 @@ static method test() → dynamic /* originally async */ { ^" in (() → core::Iterable => self::getIterableNull()).call() as{TypeError,ForNonNullableByDefault} core::Iterable; core::Iterable var6 = (() → core::Iterable => self::getIterableBool()).call(); core::Iterable var7 = (() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableBool(); @@ -268,7 +278,8 @@ static method test() → dynamic /* originally async */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); }).call(); diff --git a/pkg/front_end/testcases/nnbd/issue41437b.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue41437b.dart.weak.transformed.expect index bc6171e00b9..89e8bd511f5 100644 --- a/pkg/front_end/testcases/nnbd/issue41437b.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/nnbd/issue41437b.dart.weak.transformed.expect @@ -44,10 +44,10 @@ import "dart:async" as asy; static method getNull() → dynamic return null; static method getIterableNull() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = null; @@ -55,15 +55,16 @@ static method getIterableNull() → core::Iterable /* originally sync* } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } static method getIterableBool() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = true; @@ -71,15 +72,16 @@ static method getIterableBool() → core::Iterable /* originally syn } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } static method test1() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool; @@ -87,7 +89,8 @@ static method test1() → core::Iterable /* originally sync* */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } @@ -96,10 +99,10 @@ static method test2() → core::Iterable static method test3() → core::bool return self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool; static method test4() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_yieldEachIterable} = let final #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:21:10: Error: A value of type 'Iterable' can't be assigned to a variable of type 'Iterable'. @@ -110,7 +113,8 @@ static method test4() → core::Iterable /* originally sync* */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } @@ -122,10 +126,10 @@ Iterable test5() => getIterableNull(); // error static method test6() → core::Iterable return self::getIterableBool(); static method test7() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableBool(); @@ -133,7 +137,8 @@ static method test7() → core::Iterable /* originally sync* */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } @@ -150,10 +155,10 @@ static method test() → dynamic /* originally async */ { #L1: { function test1() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool; @@ -161,7 +166,8 @@ static method test() → dynamic /* originally async */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } @@ -170,10 +176,10 @@ static method test() → dynamic /* originally async */ { function test3() → core::bool return self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool; function test4() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_yieldEachIterable} = let final #t3 = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:38:12: Error: A value of type 'Iterable' can't be assigned to a variable of type 'Iterable'. @@ -184,7 +190,8 @@ static method test() → dynamic /* originally async */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } @@ -196,10 +203,10 @@ static method test() → dynamic /* originally async */ { function test6() → core::Iterable return self::getIterableBool(); function test7() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableBool(); @@ -207,7 +214,8 @@ static method test() → dynamic /* originally async */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } @@ -215,10 +223,10 @@ static method test() → dynamic /* originally async */ { - 'Iterable' is from 'dart:core'. })(); // error ^" in (() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = self::getNull(); @@ -226,7 +234,8 @@ static method test() → dynamic /* originally async */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); }).call() as{TypeError,ForNonNullableByDefault} core::Iterable; @@ -236,10 +245,10 @@ static method test() → dynamic /* originally async */ { - 'Iterable' is from 'dart:core'. })(); // error ^" in (() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableNull(); @@ -247,7 +256,8 @@ static method test() → dynamic /* originally async */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); }).call() as{TypeError,ForNonNullableByDefault} core::Iterable; @@ -257,10 +267,10 @@ static method test() → dynamic /* originally async */ { ^" in (() → core::Iterable => self::getIterableNull()).call() as{TypeError,ForNonNullableByDefault} core::Iterable; core::Iterable var6 = (() → core::Iterable => self::getIterableBool()).call(); core::Iterable var7 = (() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableBool(); @@ -268,7 +278,8 @@ static method test() → dynamic /* originally async */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); }).call(); diff --git a/pkg/front_end/testcases/nnbd/return_null.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/return_null.dart.strong.transformed.expect index 3d6ecf630c4..68cae46e9a8 100644 --- a/pkg/front_end/testcases/nnbd/return_null.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/nnbd/return_null.dart.strong.transformed.expect @@ -270,13 +270,14 @@ static method returnAsync7() → asy::Future /* originally async */ return :async_completer.{asy::Completer::future}; } static method yieldSync() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { {} return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } @@ -539,13 +540,14 @@ static method localFunctions() → dynamic { return :async_completer.{asy::Completer::future}; } function yieldSync() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { {} return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } diff --git a/pkg/front_end/testcases/nnbd/return_null.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/return_null.dart.weak.transformed.expect index 91bc7b37733..eb7d09f5b3a 100644 --- a/pkg/front_end/testcases/nnbd/return_null.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/nnbd/return_null.dart.weak.transformed.expect @@ -271,13 +271,14 @@ static method returnAsync7() → asy::Future /* originally async */ return :async_completer.{asy::Completer::future}; } static method yieldSync() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { {} return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } @@ -543,13 +544,14 @@ static method localFunctions() → dynamic { return :async_completer.{asy::Completer::future}; } function yieldSync() → core::Iterable /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator?) → core::bool* { + function :sync_op_gen() → (core::_SyncIterator?, dynamic, dynamic) → core::bool* { core::int :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator? :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { {} return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } diff --git a/pkg/front_end/testcases/regress/issue_29983.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_29983.dart.strong.transformed.expect index 63808a80957..aeb1e8658d5 100644 --- a/pkg/front_end/testcases/regress/issue_29983.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/regress/issue_29983.dart.strong.transformed.expect @@ -22,43 +22,46 @@ import self as self; import "dart:core" as core; static method f() → dynamic /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { invalid-expression "pkg/front_end/testcases/regress/issue_29983.dart:7:3: Error: 'sync*' and 'async*' can't return a value. return missing; ^"; } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } static method g() → dynamic /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { invalid-expression "pkg/front_end/testcases/regress/issue_29983.dart:11:14: Error: 'sync*' and 'async*' can't return a value. g() sync* => dummy; ^"; return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } static method h() → dynamic /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { (() → core::String* => "return").call(); } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } diff --git a/pkg/front_end/testcases/regress/issue_37681.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_37681.dart.strong.transformed.expect index c07e7994386..5797f908cef 100644 --- a/pkg/front_end/testcases/regress/issue_37681.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/regress/issue_37681.dart.strong.transformed.expect @@ -123,10 +123,10 @@ static method main() → dynamic /* originally async */ { } } function f_sync_star() → core::int* /* originally sync* */ { - function :sync_op_gen() → (core::_SyncIterator*) →* core::bool* { + function :sync_op_gen() → (core::_SyncIterator*, dynamic, dynamic) →* core::bool* { core::int* :await_jump_var = 0; dynamic :await_ctx_var; - return (core::_SyncIterator* :iterator) → core::bool* yielding { + function :sync_op(core::_SyncIterator* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding { { { :iterator.{core::_SyncIterator::_current} = 42; @@ -134,7 +134,8 @@ static method main() → dynamic /* originally async */ { } } return false; - }; + } + return :sync_op; } return new core::_SyncIterable::•(:sync_op_gen); } diff --git a/pkg/kernel/lib/transformations/continuation.dart b/pkg/kernel/lib/transformations/continuation.dart index d04c4657299..13942d4fcde 100644 --- a/pkg/kernel/lib/transformations/continuation.dart +++ b/pkg/kernel/lib/transformations/continuation.dart @@ -28,9 +28,10 @@ class ContinuationVariables { static const stream = ':stream'; static const syncForIterator = ':sync-for-iterator'; static const syncOpGen = ':sync_op_gen'; + static const syncOp = ':sync_op'; // sync_op(..) parameter. static const iteratorParam = ':iterator'; - // async_op(..) parameters. + // (a)sync_op(..) parameters. static const exceptionParam = ':exception'; static const stackTraceParam = ':stack_trace'; @@ -409,35 +410,42 @@ class SyncStarFunctionRewriter extends ContinuationRewriterBase { enclosingFunction.body = enclosingFunction.body.accept(shadowRewriter); - final syncOpType = FunctionType([iteratorParameter.type], - helper.coreTypes.boolLegacyRawType, staticTypeContext.nonNullable); - - final syncOpGenVariable = VariableDeclaration( - ContinuationVariables.syncOpGen, - type: FunctionType([], syncOpType, staticTypeContext.nonNullable)); - // TODO(cskau): Figure out why inlining this below causes segfaults. // Maybe related to http://dartbug.com/41596 ? final syncOpFN = FunctionNode(buildClosureBody(), - positionalParameters: [iteratorParameter], - requiredParameterCount: 1, + positionalParameters: [ + iteratorParameter, + new VariableDeclaration(ContinuationVariables.exceptionParam), + new VariableDeclaration(ContinuationVariables.stackTraceParam), + ], + requiredParameterCount: 3, + // Note: SyncYielding functions have no Dart equivalent. Since they are + // synchronous, we use Sync. (Note also that the Dart VM backend uses + // the Dart async marker to decide if functions are debuggable.) asyncMarker: AsyncMarker.SyncYielding, dartAsyncMarker: AsyncMarker.Sync, returnType: helper.coreTypes.boolLegacyRawType) ..fileOffset = enclosingFunction.fileOffset ..fileEndOffset = enclosingFunction.fileEndOffset; + final syncOpType = + syncOpFN.computeThisFunctionType(staticTypeContext.nonNullable); + + final syncOpGenVariable = VariableDeclaration( + ContinuationVariables.syncOpGen, + type: FunctionType([], syncOpType, staticTypeContext.nonNullable)); + + final syncOpVariable = VariableDeclaration(ContinuationVariables.syncOp); + final syncOpDecl = FunctionDeclaration(syncOpVariable, syncOpFN); enclosingFunction.body = Block([ // :sync_op_gen() { // :await_jump_var; // :await_ctx_var; - // return bool (:iterator) yielding { + // bool sync_op(:iterator, e, st) yielding { // modified ... // }; + // return sync_op; // } - // Note: SyncYielding functions have no Dart equivalent. Since they are - // synchronous, we use Sync. (Note also that the Dart VM backend uses - // the Dart async marker to decide if functions are debuggable.) FunctionDeclaration( syncOpGenVariable, FunctionNode( @@ -446,7 +454,10 @@ class SyncStarFunctionRewriter extends ContinuationRewriterBase { ...variableDeclarations(), // Shadow any used function parameters with local copies. ...shadowRewriter.shadowedParameters, - ReturnStatement(FunctionExpression(syncOpFN)), + // :sync_op(..) { .. } + syncOpDecl, + // return sync_op; + ReturnStatement(VariableGet(syncOpVariable)), ]), returnType: syncOpType)), diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc index efc2994418d..b118c2bfc8b 100644 --- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc +++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc @@ -4843,13 +4843,19 @@ Fragment StreamingFlowGraphBuilder::BuildYieldStatement() { Fragment continuation(instructions.entry, anchor); - if (parsed_function()->function().IsAsyncClosure() || - parsed_function()->function().IsAsyncGenClosure()) { - // If function is async closure or async gen closure it takes three + RELEASE_ASSERT(parsed_function()->function().IsAsyncClosure() || + parsed_function()->function().IsAsyncGenClosure() || + parsed_function()->function().IsSyncGenClosure()); + + // TODO(43900): Only emit this when needed. + { + // If function is {async, async gen, sync yielding} closure it takes three // parameters where the second and the third are exception and stack_trace. // Check if exception is non-null and rethrow it. // - // :async_op([:result, :exception, :stack_trace]) { + // :sync_op(:iterator, [:exception, :stack_trace]) { + // or: + // :async_op(:result, [:exception, :stack_trace]) { // ... // Continuation: // if (:exception != null) rethrow(:exception, :stack_trace); @@ -4868,13 +4874,15 @@ Fragment StreamingFlowGraphBuilder::BuildYieldStatement() { continuation += LoadLocal(exception_var); continuation += BranchIfNull(&no_error, &error); - Fragment rethrow(error); + Fragment rethrow(/*instruction=*/error); rethrow += LoadLocal(exception_var); rethrow += LoadLocal(stack_trace_var); + rethrow += RethrowException(position, kInvalidTryIndex); Drop(); - continuation = Fragment(continuation.entry, no_error); + // Set current to the end of the no_error branch. + continuation = Fragment(/*entry=*/continuation.entry, /*current=*/no_error); } return continuation; @@ -5005,6 +5013,16 @@ Fragment StreamingFlowGraphBuilder::BuildFunctionNode( } function.set_is_generated_body(function_node_helper.async_marker_ == FunctionNodeHelper::kSyncYielding); + // sync* functions contain two nested synthetic functions, the first of + // which (sync_op_gen) is a regular sync function so we need to manually + // label it generated: + if (function.parent_function() != Function::null()) { + const auto& parent = Function::Handle(function.parent_function()); + if (parent.IsSyncGenerator()) { + function.set_is_generated_body(true); + } + } + // Note: Is..() methods use the modifiers set above, so order matters. if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) { function.set_is_inlinable(!FLAG_causal_async_stacks && !FLAG_lazy_async_stacks); diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc index c0ac9e9bfcd..c9a54fdb664 100644 --- a/runtime/vm/compiler/frontend/scope_builder.cc +++ b/runtime/vm/compiler/frontend/scope_builder.cc @@ -236,15 +236,15 @@ ScopeBuildingResult* ScopeBuilder::BuildScopes() { } ParameterTypeCheckMode type_check_mode = kTypeCheckAllParameters; - if (function.IsSyncYielding()) { + if (function.IsSyncGenClosure()) { // Don't type check the parameter of sync-yielding since these calls are // all synthetic and types should always match. ASSERT((function.NumParameters() - function.NumImplicitParameters()) == - 1); + 3); ASSERT( Class::Handle( AbstractType::Handle(function.ParameterTypeAt(1)).type_class()) - .Name() == Symbols::_SyncIterator().raw()); + .ScrubbedName() == Symbols::_SyncIterator().raw()); type_check_mode = kTypeCheckForStaticFunction; } else if (function.IsNonImplicitClosureFunction()) { type_check_mode = kTypeCheckAllParameters; @@ -613,10 +613,12 @@ void ScopeBuilder::VisitFunctionNode() { scope_->AddVariable(asyncStackTraceVar); } + // The :sync_op and :async_op continuations are called multiple times. So we + // don't want the parameters from the first invocation to get stored in the + // context and reused on later invocations with different parameters. if (function_node_helper.async_marker_ == FunctionNodeHelper::kSyncYielding) { - intptr_t offset = function.num_fixed_parameters(); - for (intptr_t i = 0; i < function.NumOptionalPositionalParameters(); i++) { - parsed_function_->ParameterVariable(offset + i)->set_is_forced_stack(); + for (intptr_t i = 0; i < function.NumParameters(); i++) { + parsed_function_->ParameterVariable(i)->set_is_forced_stack(); } } diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc index 8ad542d8d3c..ecbb6f9db15 100644 --- a/runtime/vm/debugger.cc +++ b/runtime/vm/debugger.cc @@ -4831,10 +4831,6 @@ void Debugger::HandleCodeChange(bool bytecode_loaded, const Function& func) { } continue; } else { - // func was just compiled. - // The local function of a function we just compiled cannot - // be compiled already. - ASSERT(!inner_function.HasCode()); if (FLAG_verbose_debug) { OS::PrintErr( "Pending breakpoint remains unresolved in " diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index de74fdbd3c7..175b1f0298d 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -9490,7 +9490,7 @@ void Function::PrintName(const NameFormattingParams& params, if (IsClosureFunction()) { if (fun.IsLocalFunction() && !fun.IsImplicitClosureFunction()) { Function& parent = Function::Handle(fun.parent_function()); - if (parent.IsAsyncClosure() || parent.IsSyncGenClosure() || + if (parent.IsAsyncClosure() || parent.IsSyncGenClosureMaker() || parent.IsAsyncGenClosure()) { // Skip the closure and use the real function name found in // the parent. diff --git a/runtime/vm/object.h b/runtime/vm/object.h index 71eeefd4379..ceffe2f6eeb 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -3582,35 +3582,56 @@ class Function : public Object { return kind == MethodRecognizer::kUtf8DecoderScan; } + // Recognise async functions like: + // user_func async { + // // ... + // } bool IsAsyncFunction() const { return modifier() == FunctionLayout::kAsync; } + // Recognise synthetic sync-yielding functions like the inner-most: + // user_func /* was async */ { + // :async_op(..) yielding { + // // ... + // } + // } bool IsAsyncClosure() const { return is_generated_body() && Function::Handle(parent_function()).IsAsyncFunction(); } - bool IsGenerator() const { - return (modifier() & FunctionLayout::kGeneratorBit) != 0; - } - + // Recognise sync* functions like: + // user_func sync* { + // // ... + // } bool IsSyncGenerator() const { return modifier() == FunctionLayout::kSyncGen; } - bool IsSyncGenClosure() const { + // Recognise synthetic :sync_op_gen()s like: + // user_func /* was sync* */ { + // :sync_op_gen() { + // // ... + // } + // } + bool IsSyncGenClosureMaker() const { return is_generated_body() && Function::Handle(parent_function()).IsSyncGenerator(); } - bool IsGeneratorClosure() const { - return is_generated_body() && - Function::Handle(parent_function()).IsGenerator(); - } - + // Recognise async* functions like: + // user_func async* { + // // ... + // } bool IsAsyncGenerator() const { return modifier() == FunctionLayout::kAsyncGen; } + // Recognise synthetic sync-yielding functions like the inner-most: + // user_func /* originally async* */ { + // :async_op(..) yielding { + // // ... + // } + // } bool IsAsyncGenClosure() const { return is_generated_body() && Function::Handle(parent_function()).IsAsyncGenerator(); @@ -3623,15 +3644,14 @@ class Function : public Object { // Recognise synthetic sync-yielding functions like the inner-most: // user_func /* was sync* */ { // :sync_op_gen() { - // :sync_op() yielding { + // :sync_op(..) yielding { // // ... // } // } // } - bool IsSyncYielding() const { - return (parent_function() != Function::null()) - ? Function::Handle(parent_function()).IsSyncGenClosure() - : false; + bool IsSyncGenClosure() const { + return (parent_function() != Function::null()) && + Function::Handle(parent_function()).IsSyncGenClosureMaker(); } bool IsTypedDataViewFactory() const { diff --git a/sdk/lib/_internal/vm/lib/core_patch.dart b/sdk/lib/_internal/vm/lib/core_patch.dart index b4bbd570aff..d138549596b 100644 --- a/sdk/lib/_internal/vm/lib/core_patch.dart +++ b/sdk/lib/_internal/vm/lib/core_patch.dart @@ -103,7 +103,8 @@ class num { // implement sync* generator functions. A sync* generator allocates // and returns a new _SyncIterable object. -typedef _SyncGeneratorCallback = bool Function(_SyncIterator); +typedef _SyncGeneratorCallback = bool Function( + _SyncIterator, Object?, StackTrace?); typedef _SyncGeneratorCallbackCallback = _SyncGeneratorCallback Function(); @@ -123,7 +124,7 @@ class _SyncIterator implements Iterator { _SyncGeneratorCallback? _moveNextFn; Iterator? _yieldEachIterator; - // Stack of suspended _moveNextFn. + // Stack of suspended _moveNextFn (sync_op). List<_SyncGeneratorCallback>? _stack; // These two fields are set by generated code for the yield and yield* @@ -133,57 +134,85 @@ class _SyncIterator implements Iterator { @override T get current { - final iterator = _yieldEachIterator; - if (iterator != null) { - return iterator.current; - } else { - final cur = _current; - return (cur != null) ? cur : cur as T; - } + final cur = _current; + return (cur != null) ? cur : cur as T; } _SyncIterator(this._moveNextFn); + @pragma('vm:prefer-inline') + bool _handleMoveNextFnCompletion() { + _moveNextFn = null; + _current = null; + final stack = _stack; + if (stack != null && stack.isNotEmpty) { + _moveNextFn = stack.removeLast(); + return true; + } + return false; + } + @override bool moveNext() { if (_moveNextFn == null) { return false; } + Object? pendingException; + StackTrace? pendingStackTrace; while (true) { // If the active iterator isn't a nested _SyncIterator, we have to // delegate downwards from the immediate iterator. final iterator = _yieldEachIterator; if (iterator != null) { - if (iterator.moveNext()) { - return true; + try { + if (iterator.moveNext()) { + _current = iterator.current; + return true; + } + } catch (e, st) { + pendingException = e; + pendingStackTrace = st; } _yieldEachIterator = null; } - final stack = _stack; - if (!_moveNextFn!.call(this)) { - _moveNextFn = null; - _current = null; - // If we have any suspended parent generators, continue next one up: - if (stack != null && stack.isNotEmpty) { - _moveNextFn = stack.removeLast(); + // Start by calling _moveNextFn (sync_op) to move to the next value (or + // nested iterator). + try { + final haveMore = + _moveNextFn!.call(this, pendingException, pendingStackTrace); + // Exception was handled. + pendingException = null; + pendingStackTrace = null; + if (!haveMore) { + if (_handleMoveNextFnCompletion()) { + continue; + } + return false; + } + } catch (e, st) { + pendingException = e; + pendingStackTrace = st; + if (_handleMoveNextFnCompletion()) { continue; } - return false; + rethrow; } + // Case: yield* some_iterator. final iterable = _yieldEachIterable; if (iterable != null) { if (iterable is _SyncIterable) { // We got a recursive yield* of sync* function. Instead of creating // a new iterator we replace our _moveNextFn (remembering the // current _moveNextFn for later resumption). - if (stack == null) { + if (_stack == null) { _stack = []; } _stack!.add(_moveNextFn!); final typedIterable = unsafeCast<_SyncIterable>(iterable); + _moveNextFn = typedIterable._moveNextFnMaker(); } else { _yieldEachIterator = iterable.iterator; @@ -195,6 +224,7 @@ class _SyncIterator implements Iterator { continue; } + // We've successfully found the next `current` value. return true; } } diff --git a/tests/language/sync_star/sync_star_exception_nested_test.dart b/tests/language/sync_star/sync_star_exception_nested_test.dart new file mode 100644 index 00000000000..ab10c658301 --- /dev/null +++ b/tests/language/sync_star/sync_star_exception_nested_test.dart @@ -0,0 +1,55 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// See: https://github.com/dart-lang/sdk/issues/42466 + +import 'dart:collection'; +import 'package:expect/expect.dart'; + +String? caughtString; + +a() sync* { + yield 3; + throw 'Throw from a()'; + yield 4; +} + +b() sync* { + yield 2; + yield* a(); + yield 5; +} + +c() sync* { + try { + yield 1; + yield* b(); + yield 6; + } catch (e, st) { + caughtString = 'Caught in c()'; + } +} + +d() sync* { + try { + yield 0; + yield* c(); + yield 7; + } catch (e, st) { + caughtString = 'Caught in d()'; + } +} + +main() { + List yields = []; + try { + for (final e in d()) { + yields.add(e); + } + } catch (e, st) { + caughtString = 'Caught in main()'; + } + Expect.equals('Caught in c()', caughtString); + Expect.listEquals([0, 1, 2, 3, 7], yields); +} diff --git a/tests/language/sync_star/sync_star_exception_test.dart b/tests/language/sync_star/sync_star_exception_test.dart new file mode 100644 index 00000000000..e1db95a9cca --- /dev/null +++ b/tests/language/sync_star/sync_star_exception_test.dart @@ -0,0 +1,46 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// See: https://github.com/dart-lang/sdk/issues/42466 + +import 'dart:collection'; +import 'package:expect/expect.dart'; + +var caughtString; + +class AlwaysThrowingIterator implements Iterator { + bool moveNext() => throw 'moveNext'; + int get current => throw 'current'; +} + +class AlwaysThrowing extends IterableBase { + Iterator get iterator => AlwaysThrowingIterator(); +} + +Iterable f() sync* { + try { + yield* AlwaysThrowing(); + } catch (e, st) { + caughtString = 'caught $e in f'; + } +} + +void g() { + try { + for (int x in f()) { + print(x); + } + } catch (e, st) { + caughtString = 'caught $e in g'; + } +} + +main() { + g(); + // The spec dictates that if `e` (moveNext, current) throws then `yield* e` + // should throw. + // I.e. even though the iteration is happening in `g`, the `yield*` is in `f` + // so its catch should trigger. + Expect.equals('caught moveNext in f', caughtString); +} diff --git a/tests/language_2/sync_star/sync_star_exception_nested_test.dart b/tests/language_2/sync_star/sync_star_exception_nested_test.dart new file mode 100644 index 00000000000..6c8b702bbf2 --- /dev/null +++ b/tests/language_2/sync_star/sync_star_exception_nested_test.dart @@ -0,0 +1,55 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// See: https://github.com/dart-lang/sdk/issues/42466 + +import 'dart:collection'; +import 'package:expect/expect.dart'; + +String caughtString; + +a() sync* { + yield 3; + throw 'Throw from a()'; + yield 4; +} + +b() sync* { + yield 2; + yield* a(); + yield 5; +} + +c() sync* { + try { + yield 1; + yield* b(); + yield 6; + } catch (e, st) { + caughtString = 'Caught in c()'; + } +} + +d() sync* { + try { + yield 0; + yield* c(); + yield 7; + } catch (e, st) { + caughtString = 'Caught in d()'; + } +} + +main() { + List yields = []; + try { + for (final e in d()) { + yields.add(e); + } + } catch (e, st) { + caughtString = 'Caught in main()'; + } + Expect.equals('Caught in c()', caughtString); + Expect.listEquals([0, 1, 2, 3, 7], yields); +} diff --git a/tests/language_2/sync_star/sync_star_exception_test.dart b/tests/language_2/sync_star/sync_star_exception_test.dart new file mode 100644 index 00000000000..e1db95a9cca --- /dev/null +++ b/tests/language_2/sync_star/sync_star_exception_test.dart @@ -0,0 +1,46 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// See: https://github.com/dart-lang/sdk/issues/42466 + +import 'dart:collection'; +import 'package:expect/expect.dart'; + +var caughtString; + +class AlwaysThrowingIterator implements Iterator { + bool moveNext() => throw 'moveNext'; + int get current => throw 'current'; +} + +class AlwaysThrowing extends IterableBase { + Iterator get iterator => AlwaysThrowingIterator(); +} + +Iterable f() sync* { + try { + yield* AlwaysThrowing(); + } catch (e, st) { + caughtString = 'caught $e in f'; + } +} + +void g() { + try { + for (int x in f()) { + print(x); + } + } catch (e, st) { + caughtString = 'caught $e in g'; + } +} + +main() { + g(); + // The spec dictates that if `e` (moveNext, current) throws then `yield* e` + // should throw. + // I.e. even though the iteration is happening in `g`, the `yield*` is in `f` + // so its catch should trigger. + Expect.equals('caught moveNext in f', caughtString); +}