Version 2.17.0-81.0.dev

Merge commit '5e8e68c2c86983f8f4bc856e3ad5092db4d65f6c' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8ea983b..db965d7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,14 @@
 - Add `ref=` and `[]=` methods to the `StructPointer` and `UnionPointer`
   extensions. They copy a compound instance into a native memory region.
 
+#### `dart:html`
+
+- Add `scrollIntoViewIfNeeded` to `Element`. Previously, this method was nested
+  within `scrollIntoView` based on the `ScrollAlignment` value. `scrollIntoView`
+  is unchanged for now, but users who intend to use the native
+  `Element.scrollIntoViewIfNeeded` should use the new `scrollIntoViewIfNeeded`
+  definition instead.
+
 #### `dart:indexed_db`
 
 - `IdbFactory.supportsDatabaseNames` has been deprecated. It will always return
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 79182f9..14a910c 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -159,6 +159,7 @@
   CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT,
   CompileTimeErrorCode.DUPLICATE_PART,
   CompileTimeErrorCode.ENUM_CONSTANT_SAME_NAME_AS_ENCLOSING,
+  CompileTimeErrorCode.ENUM_MIXIN_WITH_INSTANCE_VARIABLE,
   CompileTimeErrorCode.EQUAL_ELEMENTS_IN_CONST_SET,
   CompileTimeErrorCode.EQUAL_KEYS_IN_CONST_MAP,
   CompileTimeErrorCode.EXPECTED_ONE_LIST_TYPE_ARGUMENTS,
diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart
index e3bf80e..88d2afe 100644
--- a/pkg/analyzer/lib/src/error/codes.g.dart
+++ b/pkg/analyzer/lib/src/error/codes.g.dart
@@ -3636,6 +3636,13 @@
     correctionMessage: "Try renaming the constant.",
   );
 
+  static const CompileTimeErrorCode ENUM_MIXIN_WITH_INSTANCE_VARIABLE =
+      CompileTimeErrorCode(
+    'ENUM_MIXIN_WITH_INSTANCE_VARIABLE',
+    "Mixins applied to enums can't have instance variables.",
+    correctionMessage: "Try replacing the instance variables with getters.",
+  );
+
   /**
    * No parameters.
    */
diff --git a/pkg/analyzer/lib/src/error/inheritance_override.dart b/pkg/analyzer/lib/src/error/inheritance_override.dart
index fec81ec..aa1f7c1 100644
--- a/pkg/analyzer/lib/src/error/inheritance_override.dart
+++ b/pkg/analyzer/lib/src/error/inheritance_override.dart
@@ -61,6 +61,18 @@
           superclass: declaration.superclass2,
           withClause: declaration.withClause,
         ).verify();
+      } else if (declaration is EnumDeclaration) {
+        _ClassVerifier(
+          typeSystem: _typeSystem,
+          typeProvider: _typeProvider,
+          inheritance: _inheritance,
+          reporter: _reporter,
+          featureSet: unit.featureSet,
+          library: library,
+          classNameNode: declaration.name,
+          implementsClause: declaration.implementsClause,
+          withClause: declaration.withClause,
+        ).verify();
       } else if (declaration is MixinDeclaration) {
         _ClassVerifier(
           typeSystem: _typeSystem,
@@ -94,7 +106,7 @@
   final FeatureSet featureSet;
   final LibraryElementImpl library;
   final Uri libraryUri;
-  final ClassElementImpl classElement;
+  final AbstractClassElementImpl classElement;
 
   final SimpleIdentifier classNameNode;
   final List<ClassMember> members;
@@ -119,7 +131,7 @@
     this.superclass,
     this.withClause,
   })  : libraryUri = library.source.uri,
-        classElement = classNameNode.staticElement as ClassElementImpl;
+        classElement = classNameNode.staticElement as AbstractClassElementImpl;
 
   bool get _isNonNullableByDefault => typeSystem.isNonNullableByDefault;
 
@@ -128,7 +140,8 @@
       return;
     }
 
-    if (!classElement.isAbstract &&
+    if (!classElement.isEnum &&
+        !classElement.isAbstract &&
         classElement.allSupertypes.any((e) => e.isDartCoreEnum)) {
       reporter.reportErrorForNode(
         CompileTimeErrorCode.NON_ABSTRACT_CLASS_HAS_ENUM_SUPERINTERFACE,
@@ -402,11 +415,36 @@
         )) {
           hasError = true;
         }
+        if (classElement.isEnum && _checkEnumMixin(namedType)) {
+          hasError = true;
+        }
       }
     }
     return hasError;
   }
 
+  bool _checkEnumMixin(NamedType namedType) {
+    DartType type = namedType.typeOrThrow;
+    if (type is! InterfaceType) {
+      return false;
+    }
+
+    var interfaceElement = type.element;
+    if (interfaceElement.isEnum) {
+      return false;
+    }
+
+    if (interfaceElement.fields.every((e) => e.isStatic || e.isSynthetic)) {
+      return false;
+    }
+
+    reporter.reportErrorForNode(
+      CompileTimeErrorCode.ENUM_MIXIN_WITH_INSTANCE_VARIABLE,
+      namedType,
+    );
+    return true;
+  }
+
   void _checkForOptionalParametersDifferentDefaultValues(
     MethodElement baseExecutable,
     MethodElement derivedExecutable,
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index 50014bb..41e3bc3 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -3335,6 +3335,9 @@
   ENUM_CONSTANT_SAME_NAME_AS_ENCLOSING:
     problemMessage: "The name of the enum constant can't be the same as the enum's name."
     correctionMessage: Try renaming the constant.
+  ENUM_MIXIN_WITH_INSTANCE_VARIABLE:
+    problemMessage: Mixins applied to enums can't have instance variables.
+    correctionMessage: Try replacing the instance variables with getters.
   EQUAL_ELEMENTS_IN_CONST_SET:
     problemMessage: "Two elements in a constant set literal can't be equal."
     correctionMessage: Change or remove the duplicate element.
diff --git a/pkg/analyzer/test/src/diagnostics/enum_mixin_with_instance_variable_test.dart b/pkg/analyzer/test/src/diagnostics/enum_mixin_with_instance_variable_test.dart
new file mode 100644
index 0000000..756833d
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/enum_mixin_with_instance_variable_test.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2022, 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.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(EnumMixinWithInstanceVariableTest);
+  });
+}
+
+@reflectiveTest
+class EnumMixinWithInstanceVariableTest extends PubPackageResolutionTest {
+  test_field_instance() async {
+    await assertErrorsInCode(r'''
+mixin M {
+  var foo = 0;
+}
+
+enum E with M {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.ENUM_MIXIN_WITH_INSTANCE_VARIABLE, 40, 1),
+    ]);
+  }
+
+  test_field_instance_final() async {
+    await assertErrorsInCode(r'''
+mixin M {
+  final foo = 0;
+}
+
+enum E with M {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.ENUM_MIXIN_WITH_INSTANCE_VARIABLE, 42, 1),
+    ]);
+  }
+
+  test_field_static() async {
+    await assertNoErrorsInCode(r'''
+mixin M {
+  static var foo = 0;
+}
+
+enum E with M {
+  v
+}
+''');
+  }
+
+  test_getter_instance() async {
+    await assertNoErrorsInCode(r'''
+mixin M {
+  int get foo => 0;
+}
+
+enum E with M {
+  v
+}
+''');
+  }
+
+  test_setter_instance() async {
+    await assertNoErrorsInCode(r'''
+mixin M {
+  set foo(int _) {}
+}
+
+enum E with M {
+  v
+}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/implements_disallowed_class_test.dart b/pkg/analyzer/test/src/diagnostics/implements_disallowed_class_test.dart
index 37f5e9e..e06cd12 100644
--- a/pkg/analyzer/test/src/diagnostics/implements_disallowed_class_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/implements_disallowed_class_test.dart
@@ -259,6 +259,26 @@
     ]);
   }
 
+  test_enum_dartCoreEnum() async {
+    await assertErrorsInCode('''
+enum E implements Enum {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 18, 4),
+    ]);
+  }
+
+  test_enum_int() async {
+    await assertErrorsInCode('''
+enum E implements int {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS, 18, 3),
+    ]);
+  }
+
   test_mixin_dartCoreEnum() async {
     await assertNoErrorsInCode('''
 mixin M implements Enum {}
diff --git a/pkg/analyzer/test/src/diagnostics/mixin_of_disallowed_class_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_of_disallowed_class_test.dart
index b72300b..8b32940 100644
--- a/pkg/analyzer/test/src/diagnostics/mixin_of_disallowed_class_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/mixin_of_disallowed_class_test.dart
@@ -163,4 +163,14 @@
       error(CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS, 36, 3),
     ]);
   }
+
+  test_enum_int() async {
+    await assertErrorsInCode('''
+enum E with int {
+  v
+}
+''', [
+      error(CompileTimeErrorCode.MIXIN_OF_DISALLOWED_CLASS, 12, 3),
+    ]);
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index d8504b1..5ca7e69 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -147,6 +147,8 @@
 import 'duplicate_shown_name_test.dart' as duplicate_shown_name;
 import 'enum_constant_same_name_as_enclosing_test.dart'
     as enum_constant_same_name_as_enclosing;
+import 'enum_mixin_with_instance_variable_test.dart'
+    as enum_mixin_with_instance_variable;
 import 'equal_elements_in_const_set_test.dart' as equal_elements_in_const_set;
 import 'equal_elements_in_set_test.dart' as equal_elements_in_set;
 import 'equal_keys_in_const_map_test.dart' as equal_keys_in_const_map;
@@ -854,6 +856,7 @@
     duplicate_part.main();
     duplicate_shown_name.main();
     enum_constant_same_name_as_enclosing.main();
+    enum_mixin_with_instance_variable.main();
     equal_elements_in_const_set.main();
     equal_elements_in_set.main();
     equal_keys_in_const_map.main();
diff --git a/pkg/dartdev/lib/src/commands/doc.dart b/pkg/dartdev/lib/src/commands/doc.dart
index 907bba6..f3cdccf 100644
--- a/pkg/dartdev/lib/src/commands/doc.dart
+++ b/pkg/dartdev/lib/src/commands/doc.dart
@@ -54,7 +54,7 @@
   }
 
   @override
-  String get invocation => '${super.invocation} <input directory>';
+  String get invocation => '${super.invocation} [<directory>]';
 
   @override
   FutureOr<int> run() async {
@@ -64,18 +64,19 @@
     if (args['sdk-docs']) {
       options.add('--sdk-docs');
     } else {
-      // At least one argument, the input directory, is required,
-      // when we're not generating docs for the Dart SDK.
-      if (args.rest.isEmpty) {
-        usageException('Error: Input directory not specified');
+      if (args.rest.length > 1) {
+        usageException("'dart doc' only supports one input directory.'");
       }
 
-      // Determine input directory.
-      final dir = io.Directory(args.rest[0]);
-      if (!dir.existsSync()) {
-        usageException('Error: Input directory doesn\'t exist: ${dir.path}');
+      // Determine input directory; default to the cwd if no explicit input dir
+      // is passed in.
+      final directory = args.rest.isEmpty
+          ? io.Directory.current
+          : io.Directory(args.rest.first);
+      if (!directory.existsSync()) {
+        usageException('Input directory doesn\'t exist: ${directory.path}');
       }
-      options.add('--input=${dir.path}');
+      options.add('--input=${directory.path}');
     }
 
     // Specify where dartdoc resources are located.
diff --git a/pkg/dartdev/test/commands/doc_test.dart b/pkg/dartdev/test/commands/doc_test.dart
index 42ee01b..b6f80ff 100644
--- a/pkg/dartdev/test/commands/doc_test.dart
+++ b/pkg/dartdev/test/commands/doc_test.dart
@@ -6,30 +6,49 @@
 
 import '../utils.dart';
 
-const int compileErrorExitCode = 64;
+const int errorExitCode = 64;
 
 void main() {
   group('doc', defineDocTests, timeout: longTimeout);
 }
 
 void defineDocTests() {
-  test('Passing no args fails', () async {
-    final p = project();
-    final result = await p.run(['doc']);
-    expect(result.stderr, contains('Input directory not specified'));
-    expect(result.exitCode, compileErrorExitCode);
-  });
-
   test('--help', () async {
     final p = project();
     final result = await p.run(['doc', '--help']);
     expect(
       result.stdout,
-      contains('Usage: dart doc [arguments] <input directory>'),
+      contains('Usage: dart doc [arguments] [<directory>]'),
     );
     expect(result.exitCode, 0);
   });
 
+  test('Passing multiple directories fails', () async {
+    final p = project();
+    final result = await p.run(['doc', 'foo', 'bar']);
+    expect(result.stderr,
+        contains("'dart doc' only supports one input directory.'"));
+    expect(result.exitCode, errorExitCode);
+  });
+
+  test('defaults to documenting cwd', () async {
+    final p = project(mainSrc: 'void main() { print("Hello, World"); }');
+    p.file('lib/foo.dart', '''
+/// This is Foo. It uses [Bar].
+class Foo {
+  Bar bar;
+}
+
+/// Bar is very nice.
+class Bar {
+  _i = 42;
+}
+''');
+    final result = await p.run(['doc'], workingDir: p.dirPath);
+    expect(result.stdout, contains('Documenting dartdev_temp'));
+    expect(result.exitCode, 0);
+  });
+
   test('Document a library', () async {
     final p = project(mainSrc: 'void main() { print("Hello, World"); }');
     p.file('lib/foo.dart', '''
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 9b9fd08..e0a610a 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -837,11 +837,11 @@
 
 final defaultLibrarySpecPath = p.join(getSdkPath(), 'lib', 'libraries.json');
 
-/// Returns the absolute path to the default `.packages` file, or `null` if one
-/// could not be found.
+/// Returns the absolute path to the default `package_config.json` file, or
+/// `null` if one could not be found.
 ///
-/// Checks for a `.packages` file in the current working directory, or in any
-/// parent directory.
+/// Checks for a `.dart_tool/package_config.json` file in the current working
+/// directory, or in any parent directory.
 String _findPackagesFilePath() {
   // TODO(jmesserly): this was copied from package:package_config/discovery.dart
   // Unfortunately the relevant function is not public. CFE APIs require a URI
@@ -850,9 +850,9 @@
   if (!dir.isAbsolute) dir = dir.absolute;
   if (!dir.existsSync()) return null;
 
-  // Check for $cwd/.packages
+  // Check for $cwd/.dart_tool/package_config.json
   while (true) {
-    var file = File(p.join(dir.path, '.packages'));
+    var file = File.fromUri(dir.uri.resolve('.dart_tool/package_config.json'));
     if (file.existsSync()) return file.path;
 
     // If we didn't find it, search the parent directory.
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 9e8ab9a..b421ddc 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1114,9 +1114,10 @@
 
 DART_EXPORT void Dart_UpdateExternalSize(Dart_WeakPersistentHandle object,
                                          intptr_t external_size) {
-  IsolateGroup* isolate_group = IsolateGroup::Current();
+  Thread* T = Thread::Current();
+  IsolateGroup* isolate_group = T->isolate_group();
   CHECK_ISOLATE_GROUP(isolate_group);
-  NoSafepointScope no_safepoint_scope;
+  TransitionToVM transition(T);
   ApiState* state = isolate_group->api_state();
   ASSERT(state != NULL);
   ASSERT(state->IsActiveWeakPersistentHandle(object));
@@ -1140,9 +1141,10 @@
 }
 
 DART_EXPORT void Dart_DeletePersistentHandle(Dart_PersistentHandle object) {
-  IsolateGroup* isolate_group = IsolateGroup::Current();
+  Thread* T = Thread::Current();
+  IsolateGroup* isolate_group = T->isolate_group();
   CHECK_ISOLATE_GROUP(isolate_group);
-  NoSafepointScope no_safepoint_scope;
+  TransitionToVM transition(T);
   ApiState* state = isolate_group->api_state();
   ASSERT(state != NULL);
   ASSERT(state->IsActivePersistentHandle(object));
@@ -1155,9 +1157,10 @@
 
 DART_EXPORT void Dart_DeleteWeakPersistentHandle(
     Dart_WeakPersistentHandle object) {
-  IsolateGroup* isolate_group = IsolateGroup::Current();
+  Thread* T = Thread::Current();
+  IsolateGroup* isolate_group = T->isolate_group();
   CHECK_ISOLATE_GROUP(isolate_group);
-  NoSafepointScope no_safepoint_scope;
+  TransitionToVM transition(T);
   ApiState* state = isolate_group->api_state();
   ASSERT(state != NULL);
   ASSERT(state->IsActiveWeakPersistentHandle(object));
diff --git a/tests/ffi/regress_flutter97301_test.dart b/tests/ffi/regress_flutter97301_test.dart
index c330d70..e0f844d 100644
--- a/tests/ffi/regress_flutter97301_test.dart
+++ b/tests/ffi/regress_flutter97301_test.dart
@@ -18,4 +18,6 @@
   for (var i = 0; i < 2; i++) {
     print(offsetsPtr.asTypedList(1));
   }
+
+  calloc.free(offsetsPtr);
 }
diff --git a/tests/ffi_2/regress_flutter97301_test.dart b/tests/ffi_2/regress_flutter97301_test.dart
index 1417a7a..83f97c7 100644
--- a/tests/ffi_2/regress_flutter97301_test.dart
+++ b/tests/ffi_2/regress_flutter97301_test.dart
@@ -20,4 +20,6 @@
   for (var i = 0; i < 2; i++) {
     print(offsetsPtr.asTypedList(1));
   }
+
+  calloc.free(offsetsPtr);
 }
diff --git a/tools/VERSION b/tools/VERSION
index 551b152..ff3bbc2 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 80
+PRERELEASE 81
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index a3d9215..740881b 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -278,6 +278,8 @@
       "out/DebugSIMARM64/",
       "out/DebugSIMARM64C/",
       "out/DebugSIMARM_X64/",
+      "out/DebugSIMRISCV32/",
+      "out/DebugSIMRISCV64/",
       "out/DebugAndroidARM/",
       "out/DebugAndroidARM_X64/",
       "out/DebugAndroidARM64/",
@@ -289,6 +291,8 @@
       "out/ReleaseSIMARM64/",
       "out/ReleaseSIMARM64C/",
       "out/ReleaseSIMARM_X64/",
+      "out/ReleaseSIMRISCV32/",
+      "out/ReleaseSIMRISCV64/",
       "out/ReleaseAndroidARM/",
       "out/ReleaseAndroidARM_X64/",
       "out/ReleaseAndroidARM64/",
@@ -306,6 +310,8 @@
       "out/ProductSIMARM64/",
       "out/ProductSIMARM64C/",
       "out/ProductSIMARM_X64/",
+      "out/ProductSIMRISCV32/",
+      "out/ProductSIMRISCV64/",
       "out/ProductAndroidARM/",
       "out/ProductAndroidARM64/",
       "out/ProductAndroidARM64C/",
diff --git a/utils/application_snapshot.gni b/utils/application_snapshot.gni
index bd07d3a..19cbb45 100644
--- a/utils/application_snapshot.gni
+++ b/utils/application_snapshot.gni
@@ -72,7 +72,7 @@
   if (defined(invoker.dot_packages)) {
     dot_packages = invoker.dot_packages
   } else {
-    dot_packages = rebase_path("$_dart_root/.packages")
+    dot_packages = rebase_path("$_dart_root/.dart_tool/package_config.json")
   }
   output = "$root_gen_dir/$name.dart.snapshot"
   if (defined(invoker.output)) {
@@ -197,7 +197,8 @@
 #    Any build dependencies.
 #
 #  dot_packages (optional):
-#    The .packages file for the app. Defaults to the $_dart_root/.packages.
+#    The package config file for the app. Defaults to
+#    $_dart_root/.dart_tool/package_config.json.
 #
 #  output (optional):
 #    Overrides the full output path.
@@ -230,7 +231,8 @@
 #    Any build dependencies.
 #
 #  dot_packages (optional):
-#    The .packages file for the app. Defaults to the $_dart_root/.packages.
+#    The packages config file for the app. Defaults to
+#    $_dart_root/.dart_tool/package_config.json.
 #
 #  output (optional):
 #    Overrides the full output path.