[vm] Fix access to parameters in async closure body inside field initializer
For async closure parsed_function_ could be an outer function
which is unrelated to the closure. So, ScopeBuilder should not
attempt to mark parameters of parsed_function_ with
set_is_forced_stack() if it sees kSyncYielding FunctionNode.
Parameter variables might not be even allocated if
async closure is used inside an instance field initializer
and parsed_function_ is a constructor.
TEST=runtime/tests/vm/dart/regress_45306_test.dart
Fixes https://github.com/dart-lang/sdk/issues/45306
Change-Id: I1b0082cb0e217039c43f19b35d77190493069edc
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/191325
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/tests/vm/dart/regress_45306_test.dart b/runtime/tests/vm/dart/regress_45306_test.dart
new file mode 100644
index 0000000..2b5e3c0
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_45306_test.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2021, 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.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/45306.
+// Verifies that ScopeBuilder doesn't crash on an async closure inside
+// instance field initializer.
+
+class X {
+ late final Y y = Y(
+ () async {},
+ );
+
+ final double? a;
+ final double? b;
+ final String? c;
+
+ X({
+ this.a,
+ this.b,
+ this.c,
+ });
+}
+
+typedef Callback = Future<void> Function();
+
+class Y {
+ Y(Callback? f);
+}
+
+void main() {
+ X();
+}
diff --git a/runtime/tests/vm/dart_2/regress_45306_test.dart b/runtime/tests/vm/dart_2/regress_45306_test.dart
new file mode 100644
index 0000000..36af440
--- /dev/null
+++ b/runtime/tests/vm/dart_2/regress_45306_test.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2021, 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.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/45306.
+// Verifies that ScopeBuilder doesn't crash on an async closure inside
+// instance field initializer.
+
+class X {
+ final Y y = Y(
+ () async {},
+ );
+
+ final double a;
+ final double b;
+ final String c;
+
+ X({
+ this.a,
+ this.b,
+ this.c,
+ });
+}
+
+typedef Callback = Future<void> Function();
+
+class Y {
+ Y(Callback f);
+}
+
+void main() {
+ X();
+}
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index 11f7de3..ce41bb4 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -546,15 +546,6 @@
}
function_node_helper.SetJustRead(FunctionNodeHelper::kTypeParameters);
- // 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) {
- for (intptr_t i = 0; i < function.NumParameters(); i++) {
- parsed_function_->ParameterVariable(i)->set_is_forced_stack();
- }
- }
-
// Read (but don't visit) the positional and named parameters, because they've
// already been added to the scope.
function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kBody);
@@ -1537,7 +1528,11 @@
if (helper.IsCovariant()) {
variable->set_is_explicit_covariant_parameter();
}
- if (variable->name().ptr() == Symbols::IteratorParameter().ptr()) {
+
+ // 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 (current_function_async_marker_ == FunctionNodeHelper::kSyncYielding) {
variable->set_is_forced_stack();
}