Add test for #60409
Bug: #60409
Change-Id: I896d225f078e7a2f816d02c61c5050eb6affa470
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/418502
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Lasse Nielsen <lrn@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
diff --git a/tests/language/regress/regress60409_test.dart b/tests/language/regress/regress60409_test.dart
new file mode 100644
index 0000000..d12e307
--- /dev/null
+++ b/tests/language/regress/regress60409_test.dart
@@ -0,0 +1,151 @@
+// Copyright (c) 2025, 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 http://dartbug.com/60409.
+//
+// It appears that dart2js fails to correctly model scopes of for-loops in
+// control-flow collections in plain field initializer expressions.
+//
+// The `field` and `fieldFinal` cases failed at the time of reporting #60409,
+// the other variations passed.
+
+import 'package:expect/expect.dart';
+
+final List logField = [];
+final List logFinalField = [];
+final List logLateField = [];
+final List logLateFinalField = [];
+final List logConstructorInitializedField = [];
+final List logStaticField = [];
+final List logStaticFinalField = [];
+
+class A {
+ List<int> field = [
+ for (int i = 0; i < 9; ++i)
+ () {
+ logField.add(i);
+ i += 2;
+ return i;
+ }(),
+ ];
+
+ final List<int> finalField = [
+ for (int i = 0; i < 9; ++i)
+ () {
+ logFinalField.add(i);
+ i += 2;
+ return i;
+ }(),
+ ];
+
+ final List<int> constructorInitializedField;
+
+ late List<int> lateField = [
+ for (int i = 0; i < 9; ++i)
+ () {
+ logLateField.add(i);
+ i += 2;
+ return i;
+ }(),
+ ];
+
+ late final List<int> lateFinalField = [
+ for (int i = 0; i < 9; ++i)
+ () {
+ logLateFinalField.add(i);
+ i += 2;
+ return i;
+ }(),
+ ];
+
+ static List<int> staticField = [
+ for (int i = 0; i < 9; ++i)
+ () {
+ logStaticField.add(i);
+ i += 2;
+ return i;
+ }(),
+ ];
+
+ static final List<int> staticFinalField = [
+ for (int i = 0; i < 9; ++i)
+ () {
+ logStaticFinalField.add(i);
+ i += 2;
+ return i;
+ }(),
+ ];
+
+ int version = ++_version;
+ static int _version = 0;
+
+ A()
+ : constructorInitializedField = [
+ for (int i = 0; i < 9; ++i)
+ () {
+ logConstructorInitializedField.add(i);
+ i += 2;
+ return i;
+ }(),
+ ] {
+ print('A($version)');
+ logField.add('c');
+ logFinalField.add('c');
+ logLateField.add('c');
+ logLateFinalField.add('c');
+ logConstructorInitializedField.add('c');
+ logStaticField.add('c');
+ logStaticFinalField.add('c');
+ }
+
+ /// Use all the fields to ensure lazy initialization has happened.
+ void use() {
+ field;
+ finalField;
+ constructorInitializedField;
+ lateField;
+ lateFinalField;
+ staticField;
+ staticFinalField;
+ }
+
+ void check() {
+ void expect(String expected, List log) {
+ Expect.equals(expected, log.join(','));
+ }
+
+ expect('2,5,8', field);
+ expect('2,5,8', finalField);
+ expect('2,5,8', constructorInitializedField);
+ expect('2,5,8', lateField);
+ expect('2,5,8', lateFinalField);
+ expect('2,5,8', staticField);
+ expect('2,5,8', staticFinalField);
+
+ expect('0,3,6,c,x,0,3,6,c', logField);
+ expect('0,3,6,c,x,0,3,6,c', logFinalField);
+ expect('0,3,6,c,x,0,3,6,c', logConstructorInitializedField);
+ expect('c,0,3,6,x,c,0,3,6', logLateField);
+ expect('c,0,3,6,x,c,0,3,6', logLateFinalField);
+ expect('c,0,3,6,x,c', logStaticField);
+ expect('c,0,3,6,x,c', logStaticFinalField);
+ }
+}
+
+void main() {
+ final a1 = A();
+ a1.use();
+
+ logField.add('x');
+ logFinalField.add('x');
+ logLateField.add('x');
+ logLateFinalField.add('x');
+ logConstructorInitializedField.add('x');
+ logStaticField.add('x');
+ logStaticFinalField.add('x');
+
+ final a2 = A();
+ a2.use();
+ a2.check();
+}