Version 3.11.0-272.0.dev

Merge 89250d64b93e1c0c278f7768e502f18144c4596f into dev
diff --git a/pkg/analyzer/lib/src/error/annotation_verifier.dart b/pkg/analyzer/lib/src/error/annotation_verifier.dart
index c82c5d6..4ae4282 100644
--- a/pkg/analyzer/lib/src/error/annotation_verifier.dart
+++ b/pkg/analyzer/lib/src/error/annotation_verifier.dart
@@ -408,25 +408,13 @@
   /// `@nonVirtual` annotation.
   void _checkNonVirtual(Annotation node) {
     var parent = node.parent;
-    if (parent is FieldDeclaration) {
-      if (parent.isStatic) {
-        _diagnosticReporter.report(
-          diag.invalidNonVirtualAnnotation.at(node.name),
-        );
-      }
-    } else if (parent is MethodDeclaration) {
-      if (parent.parent?.parent is ExtensionDeclaration ||
-          parent.parent?.parent is ExtensionTypeDeclaration ||
-          parent.isStatic ||
+    if (parent is MethodDeclaration) {
+      if (parent.parent?.parent is ExtensionTypeDeclaration ||
           parent.isAbstract) {
         _diagnosticReporter.report(
           diag.invalidNonVirtualAnnotation.at(node.name),
         );
       }
-    } else {
-      _diagnosticReporter.report(
-        diag.invalidNonVirtualAnnotation.at(node.name),
-      );
     }
   }
 
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index c0daae5..1abfc2d 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -27114,16 +27114,6 @@
 
       #### Examples
 
-      The following code produces this diagnostic because the annotation is on a
-      class declaration rather than a member inside the class:
-
-      ```dart
-      import 'package:meta/meta.dart';
-
-      @[!nonVirtual!]
-      class C {}
-      ```
-
       The following code produces this diagnostic because the method `m` is an
       abstract method:
 
@@ -27136,27 +27126,8 @@
       }
       ```
 
-      The following code produces this diagnostic because the method `m` is a
-      static method:
-
-      ```dart
-      import 'package:meta/meta.dart';
-
-      abstract class C {
-        @[!nonVirtual!]
-        static void m() {}
-      }
-      ```
-
       #### Common fixes
 
-      If the declaration isn't a member of a class, mixin, or enum, then remove
-      the annotation:
-
-      ```dart
-      class C {}
-      ```
-
       If the member is intended to be a concrete instance member, then make it
       so:
 
@@ -27168,15 +27139,6 @@
         void m() {}
       }
       ```
-
-      If the member is not intended to be a concrete instance member, then
-      remove the annotation:
-
-      ```dart
-      abstract class C {
-        static void m() {}
-      }
-      ```
   invalidOverrideOfNonVirtualMember:
     type: staticWarning
     parameters:
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart
index af1b480..3593e4d 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_annotation_target_test.dart
@@ -1213,7 +1213,7 @@
     );
   }
 
-  void test_overridableMember_class_visibleForOverride() async {
+  void test_overridableMember_class_visibleForOverriding() async {
     await assertErrorsInCode(
       '''
 import 'package:meta/meta.dart';
@@ -1243,6 +1243,20 @@
     );
   }
 
+  void test_overridableMember_enumConstant() async {
+    await assertErrorsInCode(
+      '''
+import 'package:meta/meta.dart';
+enum E {
+  @nonVirtual
+  a,
+  b, c
+}
+''',
+      [error(diag.invalidAnnotationTarget, 45, 10)],
+    );
+  }
+
   void test_overridableMember_extensionType_visibleForOverride() async {
     await assertErrorsInCode(
       '''
@@ -1373,6 +1387,25 @@
 ''');
   }
 
+  void test_overridableMember_staticField() async {
+    await assertErrorsInCode(
+      '''
+import 'package:meta/meta_meta.dart';
+
+@Target({TargetKind.overridableMember})
+class A {
+  const A();
+}
+
+class C {
+  @A()
+  static int x = 0;
+}
+''',
+      [error(diag.invalidAnnotationTarget, 118, 1)],
+    );
+  }
+
   void test_overridableMember_staticMethod() async {
     await assertErrorsInCode(
       '''
@@ -1412,6 +1445,41 @@
     );
   }
 
+  void test_overridableMember_topLevelGetter_nonVirtual() async {
+    await assertErrorsInCode(
+      r'''
+import 'package:meta/meta.dart';
+
+@nonVirtual
+int get a => 1;
+''',
+      [error(diag.invalidAnnotationTarget, 35, 10)],
+    );
+  }
+
+  void test_overridableMember_topLevelSetter_nonVirtual() async {
+    await assertErrorsInCode(
+      r'''
+import 'package:meta/meta.dart';
+
+@nonVirtual
+set a(int value) {}
+''',
+      [error(diag.invalidAnnotationTarget, 35, 10)],
+    );
+  }
+
+  void test_overridableMember_typedef() async {
+    await assertErrorsInCode(
+      r'''
+import 'package:meta/meta.dart';
+@nonVirtual
+typedef bool predicate(Object o);
+''',
+      [error(diag.invalidAnnotationTarget, 34, 10)],
+    );
+  }
+
   void test_parameter_function() async {
     await assertErrorsInCode(
       '''
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_non_virtual_annotation_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_non_virtual_annotation_test.dart
index c798eae..3d4b233 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_non_virtual_annotation_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_non_virtual_annotation_test.dart
@@ -21,19 +21,18 @@
     writeTestPackageConfigWithMeta();
   }
 
-  test_class() async {
-    await assertErrorsInCode(
-      r'''
+  test_instanceMethod() async {
+    await assertNoErrorsInCode(r'''
 import 'package:meta/meta.dart';
 
-@nonVirtual
-class C {}
-''',
-      [error(diag.invalidNonVirtualAnnotation, 35, 10)],
-    );
+abstract class C {
+  @nonVirtual
+  void m() {}
+}
+''');
   }
 
-  test_class_abstract_member() async {
+  test_instanceMethod_abstract() async {
     await assertErrorsInCode(
       r'''
 import 'package:meta/meta.dart';
@@ -47,135 +46,7 @@
     );
   }
 
-  test_class_getter() async {
-    await assertNoErrorsInCode(r'''
-import 'package:meta/meta.dart';
-
-class C {
-  @nonVirtual
-  int get g => 0;
-}
-''');
-  }
-
-  test_class_instance_field() async {
-    await assertNoErrorsInCode(r'''
-import 'package:meta/meta.dart';
-
-class C {
-  @nonVirtual
-  int f = 0;
-}
-''');
-  }
-
-  test_class_instance_member() async {
-    await assertNoErrorsInCode(r'''
-import 'package:meta/meta.dart';
-
-class C {
-  @nonVirtual
-  void m() {
-  }
-}
-''');
-  }
-
-  test_class_setter() async {
-    await assertNoErrorsInCode(r'''
-import 'package:meta/meta.dart';
-
-class C {
-  @nonVirtual
-  set s(int v) {}
-}
-''');
-  }
-
-  test_class_static_field() async {
-    await assertErrorsInCode(
-      r'''
-import 'package:meta/meta.dart';
-
-class C {
-   @nonVirtual
-   static int f = 0;
-}
-''',
-      [error(diag.invalidNonVirtualAnnotation, 48, 10)],
-    );
-  }
-
-  test_class_static_method() async {
-    await assertErrorsInCode(
-      r'''
-import 'package:meta/meta.dart';
-
-class C {
-   @nonVirtual
-   static void m() {}
-}
-''',
-      [error(diag.invalidNonVirtualAnnotation, 48, 10)],
-    );
-  }
-
-  test_enum() async {
-    await assertErrorsInCode(
-      r'''
-import 'package:meta/meta.dart';
-
-@nonVirtual
-enum E {
-  a, b, c
-}
-''',
-      [error(diag.invalidNonVirtualAnnotation, 35, 10)],
-    );
-  }
-
-  test_enum_constant() async {
-    await assertErrorsInCode(
-      r'''
-import 'package:meta/meta.dart';
-
-enum E {
-  @nonVirtual
-  a,
-  b, c
-}
-''',
-      [error(diag.invalidNonVirtualAnnotation, 46, 10)],
-    );
-  }
-
-  test_extension() async {
-    await assertErrorsInCode(
-      r'''
-import 'package:meta/meta.dart';
-
-@nonVirtual
-extension E on Object {}
-''',
-      [error(diag.invalidNonVirtualAnnotation, 35, 10)],
-    );
-  }
-
-  test_extension_member() async {
-    await assertErrorsInCode(
-      r'''
-import 'package:meta/meta.dart';
-
-extension E on Object {
-   @nonVirtual
-   void m() {}
-}
-''',
-      [error(diag.invalidNonVirtualAnnotation, 62, 10)],
-    );
-  }
-
-  test_extensionType_instance_method() async {
+  test_instanceMethod_onExtensionType() async {
     await assertErrorsInCode(
       r'''
 import 'package:meta/meta.dart';
@@ -188,125 +59,4 @@
       [error(diag.invalidNonVirtualAnnotation, 63, 10)],
     );
   }
-
-  test_import() async {
-    await assertErrorsInCode(
-      r'''
-@nonVirtual
-import 'package:meta/meta.dart';
-''',
-      [error(diag.invalidNonVirtualAnnotation, 1, 10)],
-    );
-  }
-
-  test_mixin() async {
-    await assertErrorsInCode(
-      r'''
-import 'package:meta/meta.dart';
-
-@nonVirtual
-mixin M {}
-''',
-      [error(diag.invalidNonVirtualAnnotation, 35, 10)],
-    );
-  }
-
-  test_mixin_instance_member() async {
-    await assertNoErrorsInCode(r'''
-import 'package:meta/meta.dart';
-
-mixin M {
-  @nonVirtual
-  void m() {}
-}
-''');
-  }
-
-  test_mixin_static_field() async {
-    await assertErrorsInCode(
-      r'''
-import 'package:meta/meta.dart';
-
-mixin M {
-  @nonVirtual
-  static int f = 0;
-}
-''',
-      [error(diag.invalidNonVirtualAnnotation, 47, 10)],
-    );
-  }
-
-  test_mixin_static_method() async {
-    await assertErrorsInCode(
-      r'''
-import 'package:meta/meta.dart';
-
-mixin M {
-  @nonVirtual
-  static void m() {}
-}
-''',
-      [error(diag.invalidNonVirtualAnnotation, 47, 10)],
-    );
-  }
-
-  test_top_level_function() async {
-    await assertErrorsInCode(
-      r'''
-import 'package:meta/meta.dart';
-
-@nonVirtual
-m() {}
-''',
-      [error(diag.invalidNonVirtualAnnotation, 35, 10)],
-    );
-  }
-
-  test_top_level_getter() async {
-    await assertErrorsInCode(
-      r'''
-import 'package:meta/meta.dart';
-
-@nonVirtual
-int get g =>  0;
-''',
-      [error(diag.invalidNonVirtualAnnotation, 35, 10)],
-    );
-  }
-
-  test_top_level_setter() async {
-    await assertErrorsInCode(
-      r'''
-import 'package:meta/meta.dart';
-
-@nonVirtual
-set s(int v) {}
-''',
-      [error(diag.invalidNonVirtualAnnotation, 35, 10)],
-    );
-  }
-
-  test_top_level_var() async {
-    await assertErrorsInCode(
-      r'''
-import 'package:meta/meta.dart';
-
-@nonVirtual
-int x = 0;
-''',
-      [error(diag.invalidNonVirtualAnnotation, 35, 10)],
-    );
-  }
-
-  test_typedef() async {
-    await assertErrorsInCode(
-      r'''
-import 'package:meta/meta.dart';
-
-@nonVirtual
-typedef bool predicate(Object o);
-''',
-      [error(diag.invalidNonVirtualAnnotation, 35, 10)],
-    );
-  }
 }
diff --git a/pkg/analyzer_testing/lib/src/mock_packages/meta/meta.dart b/pkg/analyzer_testing/lib/src/mock_packages/meta/meta.dart
index 21dbb9e..b4478245 100644
--- a/pkg/analyzer_testing/lib/src/mock_packages/meta/meta.dart
+++ b/pkg/analyzer_testing/lib/src/mock_packages/meta/meta.dart
@@ -199,6 +199,7 @@
   const _MustCallSuper();
 }
 
+@Target({TargetKind.overridableMember})
 class _NonVirtual {
   const _NonVirtual();
 }
diff --git a/pkg/compiler/test/record_use/record_use_test.dart b/pkg/compiler/test/record_use/record_use_test.dart
index 1c206eb..6c6a744 100644
--- a/pkg/compiler/test/record_use/record_use_test.dart
+++ b/pkg/compiler/test/record_use/record_use_test.dart
@@ -2,6 +2,7 @@
 // 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.
 
+import 'dart:convert';
 import 'dart:io' show File, Directory, Platform;
 
 import 'package:compiler/compiler_api.dart' as api show OutputType;
@@ -10,6 +11,7 @@
 import 'package:compiler/src/util/memory_compiler.dart';
 import 'package:expect/expect.dart' show Expect;
 import 'package:path/path.dart' as path;
+import 'package:record_use/record_use.dart';
 
 /// Options to pass to the compiler such as
 /// `Flags.disableTypeInference` or `Flags.disableInlining`
@@ -18,24 +20,19 @@
 /// Run `dart --define=updateExpectations=true pkg/compiler/test/record_use/record_use_test.dart`
 /// to update.
 Future<void> main() async {
-  final directory = Directory.fromUri(Platform.script.resolve('data'));
-  final testFiles =
-      [
-            ...directory.listSync(),
-            ...Directory(
-              'pkg/vm/testcases/transformations/record_use',
-            ).listSync(),
-          ]
-          .whereType<File>()
-          .where((file) => file.path.endsWith('.dart'))
-          .map(
-            (file) => TestFile(
-              file: file,
-              basename: path.basename(file.path),
-              contents: file.readAsStringSync(),
-              uri: _createUri(path.basename(file.path)),
-            ),
-          );
+  final dataDirectory = Directory.fromUri(Platform.script.resolve('data'));
+  final vmTestCases = Directory('pkg/vm/testcases/transformations/record_use');
+  final testFiles = [...dataDirectory.listSync(), ...vmTestCases.listSync()]
+      .whereType<File>()
+      .where((file) => file.path.endsWith('.dart'))
+      .map(
+        (file) => TestFile(
+          file: file,
+          basename: path.basename(file.path),
+          contents: file.readAsStringSync(),
+          uri: _createUri(path.basename(file.path)),
+        ),
+      );
 
   final allFiles = {for (final file in testFiles) file.uri.path: file.contents};
   for (final testFile in testFiles.where((element) => element.hasMain)) {
@@ -45,6 +42,8 @@
     );
     final goldenFile = File(
       path.join(
+        // TODO(https://github.com/dart-lang/native/issues/2885): Share test
+        // expectations with the VM.
         Platform.script.resolve('golden').path,
         path.setExtension(testFile.basename, '.json.expect'),
       ),
@@ -54,11 +53,18 @@
       await goldenFile.create();
       await goldenFile.writeAsString(recordedUsages);
     } else {
-      Expect.stringEquals(
-        recordedUsages.trim(),
-        (await goldenFile.readAsString()).trim(),
-        'Recorded usages for ${testFile.uri} do not match golden file.',
-      );
+      final actual = RecordedUsages.fromJson(jsonDecode(recordedUsages));
+      final goldenContents = await goldenFile.readAsString();
+      final golden = RecordedUsages.fromJson(jsonDecode(goldenContents));
+      final semanticEquals = actual == golden;
+      if (!semanticEquals) {
+        // Print the error message based on string representation.
+        Expect.stringEquals(
+          recordedUsages.trim(),
+          goldenContents.trim(),
+          'Recorded usages for ${testFile.uri} do not match golden file.',
+        );
+      }
     }
   }
 }
diff --git a/pkg/dart2wasm/tool/compile_benchmark b/pkg/dart2wasm/tool/compile_benchmark
index fe16bec..2d13743 100755
--- a/pkg/dart2wasm/tool/compile_benchmark
+++ b/pkg/dart2wasm/tool/compile_benchmark
@@ -99,6 +99,12 @@
       shift
       ;;
 
+    -O* | --optimization-level=*)
+      DART2WASM_ARGS+=("$1")
+      RUN_BINARYEN=1
+      shift
+      ;;
+
     --phases=*)
       PHASES="${1#--phases=}"
       shift
diff --git a/pkg/dartdev/pubspec.yaml b/pkg/dartdev/pubspec.yaml
index aa02b8a..51da439 100644
--- a/pkg/dartdev/pubspec.yaml
+++ b/pkg/dartdev/pubspec.yaml
@@ -51,5 +51,6 @@
   expect: any
   lints: any
   pub_semver: any
+  record_use: any
   test: any
   yaml_edit: any
diff --git a/pkg/dartdev/test/native_assets/compile_test.dart b/pkg/dartdev/test/native_assets/compile_test.dart
index a4236cb1..52918bc 100644
--- a/pkg/dartdev/test/native_assets/compile_test.dart
+++ b/pkg/dartdev/test/native_assets/compile_test.dart
@@ -4,8 +4,10 @@
 
 // @dart=2.18
 
+import 'dart:convert';
 import 'dart:io';
 
+import 'package:record_use/record_use.dart';
 import 'package:test/test.dart';
 
 import '../utils.dart';
@@ -38,8 +40,7 @@
     });
   });
 
-  test('Golden test for recorded usages in dart2js', timeout: longTimeout,
-      () async {
+  test('Recorded usages in dart2js', timeout: longTimeout, () async {
     await recordUseTest('drop_data_asset', (dartAppUri) async {
       await runDart(
         arguments: ['pub', 'get'],
@@ -68,63 +69,21 @@
       expect(recordedUsages.existsSync(), true);
 
       final actualRecordedUsages = recordedUsages.readAsStringSync();
-      final expectedRecordedUsages = '''{
-  "constants": [
-    {
-      "type": "int",
-      "value": 3
-    },
-    {
-      "type": "int",
-      "value": 4
-    }
-  ],
-  "locations": [
-    {
-      "uri": "bin/drop_data_asset_calls.dart"
-    }
-  ],
-  "metadata": {
-    "comment": "Resources referenced by annotated resource identifiers",
-    "AppTag": "TBD",
-    "environment": {
-      "dart.web.assertions_enabled": "false",
-      "dart.tool.dart2js": "true",
-      "dart.tool.dart2js.minify": "false",
-      "dart.tool.dart2js.disable_rti_optimization": "false",
-      "dart.tool.dart2js.primitives:trust": "false",
-      "dart.tool.dart2js.types:trust": "false"
-    },
-    "version": "0.4.0"
-  },
-  "recordings": [
-    {
-      "calls": [
-        {
-          "@": 0,
-          "loading_unit": "out.js",
-          "positional": [
-            0,
-            1
-          ],
-          "type": "with_arguments"
-        }
-      ],
-      "definition": {
-        "identifier": {
-          "name": "add",
-          "scope": "MyMath",
-          "uri": "package:drop_data_asset/src/drop_data_asset.dart"
-        }
-      }
-    }
-  ]
-}''';
-      expect(actualRecordedUsages, expectedRecordedUsages);
+      final u = RecordedUsages.fromJson(jsonDecode(actualRecordedUsages));
+      final constArguments = u.constArgumentsFor(Identifier(
+        importUri: 'package:drop_data_asset/src/drop_data_asset.dart',
+        scope: 'MyMath',
+        name: 'add',
+      ));
+      expect(constArguments.length, 1);
+      expect(constArguments.first.named.isEmpty, true);
+      expect(constArguments.first.positional, [3, 4]);
     });
   });
 
-  test('Golden test for recorded usages in dart2js - no instance support yet',
+  // TODO(https://github.com/dart-lang/native/issues/2893): Implement instance
+  // support.
+  test('Recorded usages in dart2js - no instance support yet',
       timeout: longTimeout, () async {
     await recordUseTest('drop_data_asset', (dartAppUri) async {
       await runDart(
@@ -153,22 +112,12 @@
       expect(recordedUsages.existsSync(), true);
 
       final actualRecordedUsages = recordedUsages.readAsStringSync();
-      final expectedRecordedUsages = '''{
-  "metadata": {
-    "comment": "Resources referenced by annotated resource identifiers",
-    "AppTag": "TBD",
-    "environment": {
-      "dart.web.assertions_enabled": "false",
-      "dart.tool.dart2js": "true",
-      "dart.tool.dart2js.minify": "false",
-      "dart.tool.dart2js.disable_rti_optimization": "false",
-      "dart.tool.dart2js.primitives:trust": "false",
-      "dart.tool.dart2js.types:trust": "false"
-    },
-    "version": "0.4.0"
-  }
-}''';
-      expect(actualRecordedUsages, expectedRecordedUsages);
+      final u = RecordedUsages.fromJson(jsonDecode(actualRecordedUsages));
+      final constantsOf = u.constantsOf(Identifier(
+        importUri: 'package:drop_data_asset/src/drop_data_asset.dart',
+        name: 'RecordCallToC',
+      ));
+      expect(constantsOf.length, 0);
     });
   });
 }
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index a954039..be966ed 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -762,8 +762,7 @@
   const _MustCallSuper();
 }
 
-// TODO(srawlins): Enforce with `TargetKind.method`, `TargetKind.getter`,
-// `TargetKind.setter`, `TargetKind.field`.
+@Target({TargetKind.overridableMember})
 class _NonVirtual {
   const _NonVirtual();
 }
diff --git a/pkg/vm/test/transformations/record_use_test.dart b/pkg/vm/test/transformations/record_use_test.dart
index c597316..28fb03a 100644
--- a/pkg/vm/test/transformations/record_use_test.dart
+++ b/pkg/vm/test/transformations/record_use_test.dart
@@ -2,12 +2,14 @@
 // 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.
 
+import 'dart:convert';
 import 'dart:io';
 
 import 'package:kernel/ast.dart';
 import 'package:kernel/kernel.dart';
 import 'package:kernel/target/targets.dart';
 import 'package:kernel/verifier.dart';
+import 'package:record_use/record_use_internal.dart';
 import 'package:test/test.dart';
 import 'package:vm/kernel_front_end.dart'
     show runGlobalTransformations, ErrorDetector, KernelCompilationArguments;
@@ -65,11 +67,24 @@
   ).replaceAll(_pkgVmDir.toString(), 'org-dartlang-test:///');
 
   compareResultWithExpectationsFile(source, actual, expectFilePostfix: '.aot');
-  compareResultWithExpectationsFile(
-    source,
-    File.fromUri(recordedUsagesFile).readAsStringSync(),
-    expectFilePostfix: '.json',
+
+  final actualSemantic = RecordedUsages.fromJson(
+    jsonDecode(File.fromUri(recordedUsagesFile).readAsStringSync()),
   );
+  final goldenFile = File('${source.toFilePath()}.json.expect');
+  final goldenContents = await goldenFile.readAsString();
+  final golden = RecordedUsages.fromJson(jsonDecode(goldenContents));
+  final semanticEquals = actualSemantic == golden;
+  final update =
+      bool.fromEnvironment('updateExpectations') ||
+      Platform.environment['UPDATE_EXPECTATIONS'] != null;
+  if (!semanticEquals || update) {
+    compareResultWithExpectationsFile(
+      source,
+      File.fromUri(recordedUsagesFile).readAsStringSync(),
+      expectFilePostfix: '.json',
+    );
+  }
 }
 
 void main(List<String> args) {
diff --git a/tools/VERSION b/tools/VERSION
index d1a29d2..3adc47b 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 3
 MINOR 11
 PATCH 0
-PRERELEASE 271
+PRERELEASE 272
 PRERELEASE_PATCH 0