[VM] Fixes yield* exception handling in sync*.

This adds a mechanism similar to that used in async functions where
exceptions are caught in the synthetic code and passed into the
generated body to be rethrow'n.
This ensures the exception is throw'n from the same place as the
original yield*, as per the spec.

Bug: https://github.com/dart-lang/sdk/issues/42466
Change-Id: I054b9db568a49b046b6bb49f3e775bf093f83950
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/160221
Commit-Queue: Clement Skau <cskau@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
This commit is contained in:
Clement Skau
2020-10-27 06:46:27 +00:00
committed by commit-bot@chromium.org
parent b71477a2a6
commit c486a07b02
26 changed files with 518 additions and 196 deletions
@@ -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<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
}
@@ -62,10 +62,10 @@ static method asyncString2() → asy::Future<core::String*>* /* originally async
return :async_completer.{asy::Completer::future};
}
static method syncStarString() → core::Iterable<core::String*>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = "foo";
@@ -81,15 +81,16 @@ static method syncStarString() → core::Iterable<core::String*>* /* originally
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<core::String*>(:sync_op_gen);
}
static method syncStarString2() → core::Iterable<core::String*>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = "foo";
@@ -97,7 +98,8 @@ static method syncStarString2() → core::Iterable<core::String*>* /* originally
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<core::String*>(:sync_op_gen);
}
@@ -62,10 +62,10 @@ static method asyncString2() → asy::Future<core::String*>* /* originally async
return :async_completer.{asy::Completer::future};
}
static method syncStarString() → core::Iterable<core::String*>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = "foo";
@@ -81,15 +81,16 @@ static method syncStarString() → core::Iterable<core::String*>* /* originally
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<core::String*>(:sync_op_gen);
}
static method syncStarString2() → core::Iterable<core::String*>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = "foo";
@@ -97,7 +98,8 @@ static method syncStarString2() → core::Iterable<core::String*>* /* originally
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<core::String*>(:sync_op_gen);
}
@@ -4,10 +4,10 @@ import "dart:core" as core;
static method main() → dynamic {
() →* core::Iterable<core::Null?>* f = () → core::Iterable<core::Null?>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :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::•<core::Null?>(:sync_op_gen);
};
@@ -4,10 +4,10 @@ import "dart:core" as core;
static method test() → dynamic {
() →* core::Iterable<core::num*>* f = () → core::Iterable<core::num*>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :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::•<core::num*>(:sync_op_gen);
};
@@ -139,10 +139,10 @@ static method foo() → asy::Stream<core::List<core::int*>*>* /* originally asyn
return :controller_stream;
}
static method bar() → core::Iterable<core::Map<core::int*, core::int*>*>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = core::Map::•<core::int*, core::int*>();
@@ -170,7 +170,8 @@ static method bar() → core::Iterable<core::Map<core::int*, core::int*>*>* /* o
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<core::Map<core::int*, core::int*>*>(:sync_op_gen);
}
@@ -64,10 +64,10 @@ static method test() → dynamic {
return :async_completer.{asy::Completer::future};
}
function f4() → core::Iterable<core::int*>* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :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::•<core::int*>(:sync_op_gen);
}
@@ -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<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :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<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :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);
}
@@ -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<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :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<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :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);
}
@@ -44,10 +44,10 @@ import "dart:async" as asy;
static method getNull() → dynamic
return null;
static method getIterableNull() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = null;
@@ -55,15 +55,16 @@ static method getIterableNull() → core::Iterable<dynamic> /* originally sync*
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
}
static method getIterableBool() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = true;
@@ -71,15 +72,16 @@ static method getIterableBool() → core::Iterable<core::bool> /* originally syn
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
}
static method test1() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :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<core::bool> /* originally sync* */ {
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
}
@@ -96,10 +99,10 @@ static method test2() → core::Iterable<core::bool>
static method test3() → core::bool
return self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
static method test4() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:21:10: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
@@ -110,7 +113,8 @@ static method test4() → core::Iterable<core::bool> /* originally sync* */ {
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
}
@@ -122,10 +126,10 @@ Iterable<bool> test5() => getIterableNull(); // error
static method test6() → core::Iterable<core::bool>
return self::getIterableBool();
static method test7() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableBool();
@@ -133,7 +137,8 @@ static method test7() → core::Iterable<core::bool> /* originally sync* */ {
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
}
@@ -150,10 +155,10 @@ static method test() → dynamic /* originally async */ {
#L1:
{
function test1() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :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::•<core::bool>(: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<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:38:12: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
@@ -184,7 +190,8 @@ static method test() → dynamic /* originally async */ {
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
}
@@ -196,10 +203,10 @@ static method test() → dynamic /* originally async */ {
function test6() → core::Iterable<core::bool>
return self::getIterableBool();
function test7() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :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::•<core::bool>(:sync_op_gen);
}
@@ -215,10 +223,10 @@ static method test() → dynamic /* originally async */ {
- 'Iterable' is from 'dart:core'.
})(); // error
^" in (() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :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::•<dynamic>(:sync_op_gen);
}).call() as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
@@ -236,10 +245,10 @@ static method test() → dynamic /* originally async */ {
- 'Iterable' is from 'dart:core'.
})(); // error
^" in (() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :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::•<dynamic>(:sync_op_gen);
}).call() as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
@@ -257,10 +267,10 @@ static method test() → dynamic /* originally async */ {
^" in (() → core::Iterable<dynamic> => self::getIterableNull()).call() as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
core::Iterable<core::bool> var6 = (() → core::Iterable<core::bool> => self::getIterableBool()).call();
core::Iterable<core::bool> var7 = (() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :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::•<core::bool>(:sync_op_gen);
}).call();
@@ -44,10 +44,10 @@ import "dart:async" as asy;
static method getNull() → dynamic
return null;
static method getIterableNull() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = null;
@@ -55,15 +55,16 @@ static method getIterableNull() → core::Iterable<dynamic> /* originally sync*
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
}
static method getIterableBool() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_current} = true;
@@ -71,15 +72,16 @@ static method getIterableBool() → core::Iterable<core::bool> /* originally syn
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
}
static method test1() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :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<core::bool> /* originally sync* */ {
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
}
@@ -96,10 +99,10 @@ static method test2() → core::Iterable<core::bool>
static method test3() → core::bool
return self::getNull() as{TypeError,ForDynamic,ForNonNullableByDefault} core::bool;
static method test4() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:21:10: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
@@ -110,7 +113,8 @@ static method test4() → core::Iterable<core::bool> /* originally sync* */ {
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
}
@@ -122,10 +126,10 @@ Iterable<bool> test5() => getIterableNull(); // error
static method test6() → core::Iterable<core::bool>
return self::getIterableBool();
static method test7() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = self::getIterableBool();
@@ -133,7 +137,8 @@ static method test7() → core::Iterable<core::bool> /* originally sync* */ {
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
}
@@ -150,10 +155,10 @@ static method test() → dynamic /* originally async */ {
#L1:
{
function test1() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :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::•<core::bool>(: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<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
{
:iterator.{core::_SyncIterator::_yieldEachIterable} = let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/issue41437b.dart:38:12: Error: A value of type 'Iterable<dynamic>' can't be assigned to a variable of type 'Iterable<bool>'.
@@ -184,7 +190,8 @@ static method test() → dynamic /* originally async */ {
}
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<core::bool>(:sync_op_gen);
}
@@ -196,10 +203,10 @@ static method test() → dynamic /* originally async */ {
function test6() → core::Iterable<core::bool>
return self::getIterableBool();
function test7() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :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::•<core::bool>(:sync_op_gen);
}
@@ -215,10 +223,10 @@ static method test() → dynamic /* originally async */ {
- 'Iterable' is from 'dart:core'.
})(); // error
^" in (() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :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::•<dynamic>(:sync_op_gen);
}).call() as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
@@ -236,10 +245,10 @@ static method test() → dynamic /* originally async */ {
- 'Iterable' is from 'dart:core'.
})(); // error
^" in (() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :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::•<dynamic>(:sync_op_gen);
}).call() as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
@@ -257,10 +267,10 @@ static method test() → dynamic /* originally async */ {
^" in (() → core::Iterable<dynamic> => self::getIterableNull()).call() as{TypeError,ForNonNullableByDefault} core::Iterable<core::bool>;
core::Iterable<core::bool> var6 = (() → core::Iterable<core::bool> => self::getIterableBool()).call();
core::Iterable<core::bool> var7 = (() → core::Iterable<core::bool> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :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::•<core::bool>(:sync_op_gen);
}).call();
@@ -270,13 +270,14 @@ static method returnAsync7() → asy::Future<core::int?> /* originally async */
return :async_completer.{asy::Completer::future};
}
static method yieldSync() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
}
@@ -539,13 +540,14 @@ static method localFunctions() → dynamic {
return :async_completer.{asy::Completer::future};
}
function yieldSync() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
}
@@ -271,13 +271,14 @@ static method returnAsync7() → asy::Future<core::int?> /* originally async */
return :async_completer.{asy::Completer::future};
}
static method yieldSync() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
}
@@ -543,13 +544,14 @@ static method localFunctions() → dynamic {
return :async_completer.{asy::Completer::future};
}
function yieldSync() → core::Iterable<dynamic> /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?) → core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>?, dynamic, dynamic) → core::bool* {
core::int :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>? :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>? :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
}
@@ -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<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :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::•<dynamic>(:sync_op_gen);
}
static method g() → dynamic /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :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::•<dynamic>(:sync_op_gen);
}
static method h() → dynamic /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :iterator, dynamic :exception, dynamic :stack_trace) → core::bool* yielding {
{
(() → core::String* => "return").call();
}
return false;
};
}
return :sync_op;
}
return new core::_SyncIterable::•<dynamic>(:sync_op_gen);
}
@@ -123,10 +123,10 @@ static method main() → dynamic /* originally async */ {
}
}
function f_sync_star() → core::int* /* originally sync* */ {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*) →* core::bool* {
function :sync_op_gen() → (core::_SyncIterator<dynamic>*, dynamic, dynamic) →* core::bool* {
core::int* :await_jump_var = 0;
dynamic :await_ctx_var;
return (core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
function :sync_op(core::_SyncIterator<dynamic>* :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::•<dynamic>(:sync_op_gen);
}
@@ -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<TreeNode>(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 <node.body> ...
// };
// 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)),
@@ -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<index>:
// 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);
@@ -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();
}
}
-4
View File
@@ -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 "
+1 -1
View File
@@ -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.
+35 -15
View File
@@ -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 {
+50 -20
View File
@@ -103,7 +103,8 @@ class num {
// implement sync* generator functions. A sync* generator allocates
// and returns a new _SyncIterable object.
typedef _SyncGeneratorCallback<T> = bool Function(_SyncIterator<T>);
typedef _SyncGeneratorCallback<T> = bool Function(
_SyncIterator<T>, Object?, StackTrace?);
typedef _SyncGeneratorCallbackCallback<T> = _SyncGeneratorCallback<T>
Function();
@@ -123,7 +124,7 @@ class _SyncIterator<T> implements Iterator<T> {
_SyncGeneratorCallback<T>? _moveNextFn;
Iterator<T>? _yieldEachIterator;
// Stack of suspended _moveNextFn.
// Stack of suspended _moveNextFn (sync_op).
List<_SyncGeneratorCallback<T>>? _stack;
// These two fields are set by generated code for the yield and yield*
@@ -133,57 +134,85 @@ class _SyncIterator<T> implements Iterator<T> {
@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<T>>(iterable);
_moveNextFn = typedIterable._moveNextFnMaker();
} else {
_yieldEachIterator = iterable.iterator;
@@ -195,6 +224,7 @@ class _SyncIterator<T> implements Iterator<T> {
continue;
}
// We've successfully found the next `current` value.
return true;
}
}
@@ -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);
}
@@ -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<int> {
bool moveNext() => throw 'moveNext';
int get current => throw 'current';
}
class AlwaysThrowing extends IterableBase<int> {
Iterator<int> get iterator => AlwaysThrowingIterator();
}
Iterable<int> 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);
}
@@ -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);
}
@@ -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<int> {
bool moveNext() => throw 'moveNext';
int get current => throw 'current';
}
class AlwaysThrowing extends IterableBase<int> {
Iterator<int> get iterator => AlwaysThrowingIterator();
}
Iterable<int> 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);
}