Version 2.17.0-191.0.dev

Merge commit 'f8933dda8d925c1ee38440388dd574598e73dd36' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7e6f26f..6bf63c92 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -183,8 +183,20 @@
 
 #### Linter
 
-Updated the Linter to `1.18.0`, which includes changes that
+Updated the Linter to `1.19.2`, which includes changes that
 
+- adds new lint: `use_super_initializers`.
+- adds new lint: `use_enums`.
+- adds new lint: `use_colored_box`.
+- improves performance for `sort_constructors`.
+- improves docs for `always_use_package_imports`,
+  `avoid_print`, and `avoid_relative_lib_imports` .
+- updates `avoid_void_async` to skip `main` functions.
+- updates `prefer_final_parameters` to not super on super params.
+- updates lints for enhanced-enums and super-initializer language
+  features.
+- updates `unnecessary_late` to report on variable names.
+- marks `null_check_on_nullable_type_parameter` stable.
 - extends `camel_case_types` to cover enums.
 - fixes `no_leading_underscores_for_local_identifiers` to not
   mis-flag field formal parameters with default values.
diff --git a/DEPS b/DEPS
index bf5df69..da98049 100644
--- a/DEPS
+++ b/DEPS
@@ -124,7 +124,7 @@
   "intl_tag": "0.17.0-nullsafety",
   "jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_rev": "7e00f893440a72de0637970325e4ea44bd1e8c8e",
-  "linter_tag": "1.18.0",
+  "linter_tag": "1.19.2",
   "lints_tag": "f9670df2a66e0ec12eb51554e70c1cbf56c8f5d0",
   "logging_rev": "dfbe88b890c3b4f7bc06da5a7b3b43e9e263b688",
   "markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index a9ec81e..6035330 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -6569,17 +6569,6 @@
         r"""Try removing the 'external' keyword or adding a JS interop annotation.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Null> codeJsInteropIndexNotSupported =
-    messageJsInteropIndexNotSupported;
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const MessageCode messageJsInteropIndexNotSupported = const MessageCode(
-    "JsInteropIndexNotSupported",
-    problemMessage:
-        r"""JS interop classes do not support [] and []= operator methods.""",
-    correctionMessage: r"""Try replacing with a normal method.""");
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
     Message Function(
         String name,
@@ -6685,6 +6674,16 @@
     correctionMessage: r"""Try annotating the member with `external`.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeJsInteropOperatorsNotSupported =
+    messageJsInteropOperatorsNotSupported;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageJsInteropOperatorsNotSupported = const MessageCode(
+    "JsInteropOperatorsNotSupported",
+    problemMessage: r"""JS interop classes do not support operator methods.""",
+    correctionMessage: r"""Try replacing this with a normal method.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(String name)>
     templateJsInteropStaticInteropWithInstanceMembers =
     const Template<Message Function(String name)>(
diff --git a/pkg/_js_interop_checks/lib/js_interop_checks.dart b/pkg/_js_interop_checks/lib/js_interop_checks.dart
index 6dab119..26d8396 100644
--- a/pkg/_js_interop_checks/lib/js_interop_checks.dart
+++ b/pkg/_js_interop_checks/lib/js_interop_checks.dart
@@ -14,10 +14,10 @@
         messageJsInteropEnclosingClassJSAnnotationContext,
         messageJsInteropExternalExtensionMemberOnTypeInvalid,
         messageJsInteropExternalMemberNotJSAnnotated,
-        messageJsInteropIndexNotSupported,
         messageJsInteropNamedParameters,
         messageJsInteropNonExternalConstructor,
         messageJsInteropNonExternalMember,
+        messageJsInteropOperatorsNotSupported,
         templateJsInteropDartClassExtendsJSClass,
         templateJsInteropStaticInteropWithInstanceMembers,
         templateJsInteropStaticInteropWithNonStaticSupertype,
@@ -220,10 +220,9 @@
       _checkDisallowedExternal(procedure);
     } else {
       // Check JS interop indexing.
-      if (!procedure.isStatic &&
-          (procedure.name.text == '[]=' || procedure.name.text == '[]')) {
+      if (!procedure.isStatic && procedure.kind == ProcedureKind.Operator) {
         _diagnosticsReporter.report(
-            messageJsInteropIndexNotSupported,
+            messageJsInteropOperatorsNotSupported,
             procedure.fileOffset,
             procedure.name.text.length,
             procedure.fileUri);
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/remove_unnecessary_late.dart b/pkg/analysis_server/lib/src/services/correction/dart/remove_unnecessary_late.dart
index 08c09db..01f447a 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/remove_unnecessary_late.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/remove_unnecessary_late.dart
@@ -24,7 +24,7 @@
 
   @override
   Future<void> compute(ChangeBuilder builder) async {
-    final declaration = node;
+    final declaration = node.parent;
     if (declaration is! VariableDeclaration) {
       return;
     }
diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
index fa7be23..f818710 100644
--- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
+++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml
@@ -1814,8 +1814,12 @@
   status: needsEvaluation
 LintCode.use_build_context_synchronously:
   status: needsEvaluation
+LintCode.use_colored_box:
+  status: needsEvaluation
 LintCode.use_decorated_box:
   status: needsEvaluation
+LintCode.use_enums:
+    status: needsFix
 LintCode.use_full_hex_values_for_flutter_colors:
   status: hasFix
 LintCode.use_function_type_syntax_for_parameters:
@@ -1838,6 +1842,8 @@
   status: needsEvaluation
 LintCode.use_string_buffers:
   status: needsEvaluation
+LintCode.use_super_initializers:
+  status: needsFix
 LintCode.use_test_throws_matchers:
   status: needsEvaluation
 LintCode.use_to_and_as_if_applicable:
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_late_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_late_test.dart
index 171d193..abaa6f3a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_late_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_late_test.dart
@@ -71,7 +71,7 @@
       '''
 String s1 = '', s2 = '';
 ''',
-      errorFilter: (error) => error.toString().contains('test.dart(21..27)'),
+      errorFilter: (error) => error.toString().contains('test.dart(21..22)'),
     );
   }
 
@@ -83,7 +83,7 @@
       '''
 String s1 = '', s2 = '';
 ''',
-      errorFilter: (error) => error.toString().contains('test.dart(12..18)'),
+      errorFilter: (error) => error.toString().contains('test.dart(12..13)'),
     );
   }
 
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 6563de2..a4710b5 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -546,8 +546,6 @@
 JsInteropExternalExtensionMemberOnTypeInvalid/example: Fail # Web compiler specific
 JsInteropExternalMemberNotJSAnnotated/analyzerCode: Fail # Web compiler specific
 JsInteropExternalMemberNotJSAnnotated/example: Fail # Web compiler specific
-JsInteropIndexNotSupported/analyzerCode: Fail # Web compiler specific
-JsInteropIndexNotSupported/example: Fail # Web compiler specific
 JsInteropJSClassExtendsDartClass/analyzerCode: Fail # Web compiler specific
 JsInteropJSClassExtendsDartClass/example: Fail # Web compiler specific
 JsInteropNamedParameters/analyzerCode: Fail # Web compiler specific
@@ -558,6 +556,8 @@
 JsInteropNonExternalConstructor/example: Fail # Web compiler specific
 JsInteropNonExternalMember/analyzerCode: Fail # Web compiler specific
 JsInteropNonExternalMember/example: Fail # Web compiler specific
+JsInteropOperatorsNotSupported/analyzerCode: Fail # Web compiler specific
+JsInteropOperatorsNotSupported/example: Fail # Web compiler specific
 JsInteropStaticInteropWithInstanceMembers/analyzerCode: Fail # Web compiler specific
 JsInteropStaticInteropWithInstanceMembers/example: Fail # Web compiler specific
 JsInteropStaticInteropWithNonStaticSupertype/analyzerCode: Fail # Web compiler specific
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index d165d4c..21e529c 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -5096,18 +5096,6 @@
   problemMessage: "Only JS interop members may be 'external'."
   correctionMessage: "Try removing the 'external' keyword or adding a JS interop annotation."
 
-JsInteropIndexNotSupported:
-  problemMessage: "JS interop classes do not support [] and []= operator methods."
-  correctionMessage: "Try replacing with a normal method."
-
-JsInteropStaticInteropWithInstanceMembers:
-  problemMessage: "JS interop class '#name' with `@staticInterop` annotation cannot declare instance members."
-  correctionMessage: "Try moving the instance member to a static extension."
-
-JsInteropStaticInteropWithNonStaticSupertype:
-  problemMessage: "JS interop class '#name' has an `@staticInterop` annotation, but has supertype '#name2', which is non-static."
-  correctionMessage: "Try marking the supertype as a static interop class using `@staticInterop`."
-
 JsInteropJSClassExtendsDartClass:
   problemMessage: "JS interop class '#name' cannot extend Dart class '#name2'."
   correctionMessage: "Try removing the JS interop annotation or adding it to the parent class."
@@ -5128,6 +5116,18 @@
   problemMessage: "This JS interop member must be annotated with `external`. Only factories and static methods can be non-external."
   correctionMessage: "Try annotating the member with `external`."
 
+JsInteropOperatorsNotSupported:
+  problemMessage: "JS interop classes do not support operator methods."
+  correctionMessage: "Try replacing this with a normal method."
+
+JsInteropStaticInteropWithInstanceMembers:
+  problemMessage: "JS interop class '#name' with `@staticInterop` annotation cannot declare instance members."
+  correctionMessage: "Try moving the instance member to a static extension."
+
+JsInteropStaticInteropWithNonStaticSupertype:
+  problemMessage: "JS interop class '#name' has an `@staticInterop` annotation, but has supertype '#name2', which is non-static."
+  correctionMessage: "Try marking the supertype as a static interop class using `@staticInterop`."
+
 DefaultListConstructorError:
   problemMessage: "Can't use the default List constructor."
   correctionMessage: "Try using List.filled instead."
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index f3efce1..31d6f25 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -309,7 +309,7 @@
 }
 
 DEFINE_NATIVE_ENTRY(Internal_collectAllGarbage, 0, 0) {
-  isolate->group()->heap()->CollectAllGarbage();
+  isolate->group()->heap()->CollectAllGarbage(GCReason::kDebugging);
   return Object::null();
 }
 
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 9fbb7d0..6398852 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1812,7 +1812,16 @@
 
 DART_EXPORT void Dart_NotifyLowMemory() {
   API_TIMELINE_BEGIN_END(Thread::Current());
-  Isolate::NotifyLowMemory();
+  SemiSpace::ClearCache();
+  Zone::ClearCache();
+
+  // For each isolate's global variables, we might also clear:
+  //  - RegExp backtracking stack (both bytecode and compiled versions)
+  //  - String -> RegExp cache
+  //  - BigInt division/remainder cache
+  //  - double.toString cache
+  // But cache invalidation code might be larger than the expected size of some
+  // caches.
 }
 
 DART_EXPORT void Dart_ExitIsolate() {
@@ -1852,7 +1861,7 @@
   NoBackgroundCompilerScope no_bg_compiler(T);
 
 #if defined(DEBUG)
-  T->isolate_group()->heap()->CollectAllGarbage();
+  T->isolate_group()->heap()->CollectAllGarbage(GCReason::kDebugging);
   {
     HeapIterationScope iteration(T);
     CheckFunctionTypesVisitor check_canonical(T);
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index feed760..481bafe 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -109,7 +109,7 @@
     }
     // All GC tasks finished without allocating successfully. Collect both
     // generations.
-    CollectMostGarbage();
+    CollectMostGarbage(GCReason::kOldSpace, /*compact=*/ false);
     addr = old_space_.TryAllocate(size, type);
     if (addr != 0) {
       return addr;
@@ -126,7 +126,7 @@
       return addr;
     }
     // Before throwing an out-of-memory error try a synchronous GC.
-    CollectAllGarbage(GCReason::kLowMemory);
+    CollectAllGarbage(GCReason::kOldSpace, /*compact=*/ true);
     WaitForSweeperTasks(thread);
   }
   uword addr = old_space_.TryAllocate(size, type, PageSpace::kForceGrowth);
@@ -421,17 +421,11 @@
   old_space_.NotifyIdle(deadline);
 
   if (OS::GetCurrentMonotonicMicros() < deadline) {
-    SemiSpace::DrainCache();
+    SemiSpace::ClearCache();
   }
 }
 
-void Heap::NotifyLowMemory() {
-  TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "NotifyLowMemory");
-  CollectMostGarbage(GCReason::kLowMemory);
-}
-
 void Heap::EvacuateNewSpace(Thread* thread, GCReason reason) {
-  ASSERT(reason != GCReason::kOldSpace);
   ASSERT(reason != GCReason::kPromotion);
   ASSERT(reason != GCReason::kFinalize);
   if (thread->isolate_group() == Dart::vm_isolate_group()) {
@@ -460,7 +454,6 @@
 
 void Heap::CollectNewSpaceGarbage(Thread* thread, GCReason reason) {
   NoActiveIsolateScope no_active_isolate_scope;
-  ASSERT(reason != GCReason::kOldSpace);
   ASSERT(reason != GCReason::kPromotion);
   ASSERT(reason != GCReason::kFinalize);
   if (thread->isolate_group() == Dart::vm_isolate_group()) {
@@ -573,16 +566,14 @@
   }
 }
 
-void Heap::CollectMostGarbage(GCReason reason) {
+void Heap::CollectMostGarbage(GCReason reason, bool compact) {
   Thread* thread = Thread::Current();
   CollectNewSpaceGarbage(thread, reason);
-  CollectOldSpaceGarbage(thread,
-                         reason == GCReason::kLowMemory ? GCType::kMarkCompact
-                                                        : GCType::kMarkSweep,
-                         reason);
+  CollectOldSpaceGarbage(
+      thread, compact ? GCType::kMarkCompact : GCType::kMarkSweep, reason);
 }
 
-void Heap::CollectAllGarbage(GCReason reason) {
+void Heap::CollectAllGarbage(GCReason reason, bool compact) {
   Thread* thread = Thread::Current();
 
   // New space is evacuated so this GC will collect all dead objects
@@ -594,10 +585,8 @@
     // retained by the incremental barrier.
     CollectOldSpaceGarbage(thread, GCType::kMarkSweep, reason);
   }
-  CollectOldSpaceGarbage(thread,
-                         reason == GCReason::kLowMemory ? GCType::kMarkCompact
-                                                        : GCType::kMarkSweep,
-                         reason);
+  CollectOldSpaceGarbage(
+      thread, compact ? GCType::kMarkCompact : GCType::kMarkSweep, reason);
   WaitForSweeperTasks(thread);
 }
 
@@ -898,12 +887,8 @@
       return "external";
     case GCReason::kIdle:
       return "idle";
-    case GCReason::kLowMemory:
-      return "low memory";
     case GCReason::kDebugging:
       return "debugging";
-    case GCReason::kSendAndExit:
-      return "send_and_exit";
     default:
       UNREACHABLE();
       return "";
diff --git a/runtime/vm/heap/heap.h b/runtime/vm/heap/heap.h
index 59eae20..179122d 100644
--- a/runtime/vm/heap/heap.h
+++ b/runtime/vm/heap/heap.h
@@ -106,7 +106,6 @@
   ObjectPtr FindObject(FindObjectVisitor* visitor);
 
   void NotifyIdle(int64_t deadline);
-  void NotifyLowMemory();
 
   // Collect a single generation.
   void CollectGarbage(Space space);
@@ -117,13 +116,15 @@
   // mark-sweep treats new space as roots, a cycle between unreachable old and
   // new objects will not be collected until the new objects are promoted.
   // Verification based on heap iteration should instead use CollectAllGarbage.
-  void CollectMostGarbage(GCReason reason = GCReason::kFull);
+  void CollectMostGarbage(GCReason reason = GCReason::kFull,
+                          bool compact = false);
 
   // Collect both generations by performing an evacuation followed by a
   // mark-sweep. If incremental marking was in progress, perform another
   // mark-sweep. This function will collect all unreachable objects, including
   // those in inter-generational cycles or stored during incremental marking.
-  void CollectAllGarbage(GCReason reason = GCReason::kFull);
+  void CollectAllGarbage(GCReason reason = GCReason::kFull,
+                         bool compact = false);
 
   void CheckStartConcurrentMarking(Thread* thread, GCReason reason);
   void StartConcurrentMarking(Thread* thread, GCReason reason);
@@ -395,7 +396,6 @@
   friend class Become;       // VisitObjectPointers
   friend class GCCompactor;  // VisitObjectPointers
   friend class Precompiler;  // VisitObjects
-  friend class Unmarker;     // VisitObjects
   friend class ServiceEvent;
   friend class Scavenger;             // VerifyGC
   friend class PageSpace;             // VerifyGC
@@ -405,7 +405,7 @@
   friend class ProgramVisitor;        // VisitObjectsImagePages
   friend class Serializer;            // VisitObjectsImagePages
   friend class HeapTestHelper;
-  friend class MetricsTestHelper;
+  friend class GCTestHelper;
 
   DISALLOW_COPY_AND_ASSIGN(Heap);
 };
@@ -471,7 +471,7 @@
   static void CollectNewSpace() {
     Thread* thread = Thread::Current();
     ASSERT(thread->execution_state() == Thread::kThreadInVM);
-    thread->heap()->new_space()->Scavenge(GCReason::kDebugging);
+    thread->heap()->CollectNewSpaceGarbage(thread, GCReason::kDebugging);
   }
 
   // Fully collect old gen and wait for the sweeper to finish. The normal call
@@ -488,10 +488,10 @@
     WaitForGCTasks();
   }
 
-  static void CollectAllGarbage() {
+  static void CollectAllGarbage(bool compact = false) {
     Thread* thread = Thread::Current();
     ASSERT(thread->execution_state() == Thread::kThreadInVM);
-    thread->heap()->CollectAllGarbage(GCReason::kDebugging);
+    thread->heap()->CollectAllGarbage(GCReason::kDebugging, compact);
   }
 
   static void WaitForGCTasks() {
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index bed2610..e8b433a 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -678,7 +678,7 @@
   page_cache_mutex = new Mutex(NOT_IN_PRODUCT("page_cache_mutex"));
 }
 
-void SemiSpace::DrainCache() {
+void SemiSpace::ClearCache() {
   MutexLocker ml(page_cache_mutex);
   ASSERT(page_cache_size >= 0);
   ASSERT(page_cache_size <= kPageCacheCapacity);
@@ -688,7 +688,7 @@
 }
 
 void SemiSpace::Cleanup() {
-  DrainCache();
+  ClearCache();
   delete page_cache_mutex;
   page_cache_mutex = nullptr;
 }
diff --git a/runtime/vm/heap/scavenger.h b/runtime/vm/heap/scavenger.h
index bc626a5..38c2ed6 100644
--- a/runtime/vm/heap/scavenger.h
+++ b/runtime/vm/heap/scavenger.h
@@ -168,7 +168,7 @@
 class SemiSpace {
  public:
   static void Init();
-  static void DrainCache();
+  static void ClearCache();
   static void Cleanup();
   static intptr_t CachedSize();
 
diff --git a/runtime/vm/heap/spaces.h b/runtime/vm/heap/spaces.h
index f6827aa..c1c0663 100644
--- a/runtime/vm/heap/spaces.h
+++ b/runtime/vm/heap/spaces.h
@@ -40,14 +40,12 @@
   kNewSpace,     // New space is full.
   kStoreBuffer,  // Store buffer is too big.
   kPromotion,    // Old space limit crossed after a scavenge.
-  kOldSpace,     // Old space limit crossed.
+  kOldSpace,     // Old space limit crossed, or old space allocation failed.
   kFinalize,     // Concurrent marking finished.
   kFull,         // Heap::CollectAllGarbage
   kExternal,     // Dart_NewFinalizableHandle Dart_NewWeakPersistentHandle
   kIdle,         // Dart_NotifyIdle
-  kLowMemory,    // Dart_NotifyLowMemory
   kDebugging,    // service request, etc.
-  kSendAndExit,  // SendPort.sendAndExit
 };
 
 }  // namespace dart
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 260c293..2f8c8cc 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -1012,7 +1012,7 @@
   // Verify that all canonical instances are correctly setup in the
   // corresponding canonical tables.
   NoBackgroundCompilerScope no_bg_compiler(Thread::Current());
-  heap()->CollectAllGarbage();
+  heap()->CollectAllGarbage(GCReason::kDebugging);
   Thread* thread = Thread::Current();
   SafepointMutexLocker ml(
       thread->isolate_group()->constant_canonicalization_mutex());
@@ -1203,10 +1203,6 @@
 #endif
       break;
     }
-    case Isolate::kLowMemoryMsg: {
-      I->group()->heap()->NotifyLowMemory();
-      break;
-    }
     case Isolate::kDrainServiceExtensionsMsg: {
 #ifndef PRODUCT
       Object& obj = Object::Handle(zone, message.At(2));
@@ -2452,22 +2448,6 @@
 }
 #endif  // !defined(PRODUCT)
 
-// static
-void Isolate::NotifyLowMemory() {
-  IsolateGroup::ForEach([](IsolateGroup* group) { group->NotifyLowMemory(); });
-}
-
-void IsolateGroup::NotifyLowMemory() {
-  SafepointReadRwLocker ml(Thread::Current(), isolates_lock_.get());
-  MonitorLocker ml2(Isolate::isolate_creation_monitor_);
-  for (Isolate* isolate : isolates_) {
-    if (isolate->AcceptsMessagesLocked()) {
-      isolate->KillLocked(Isolate::kLowMemoryMsg);
-      return;  // Only wake up one member of the group.
-    }
-  }
-}
-
 void Isolate::LowLevelShutdown() {
   // Ensure we have a zone and handle scope so that we can call VM functions,
   // but we no longer allocate new heap objects.
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 7665ac1..e714838 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -604,8 +604,6 @@
     return deferred_marking_stack_;
   }
 
-  void NotifyLowMemory();
-
   // Runs the given [function] on every isolate in the isolate group.
   //
   // During the duration of this function, no new isolates can be added or
@@ -970,9 +968,8 @@
     // Internal message ids.
     kInterruptMsg = 10,     // Break in the debugger.
     kInternalKillMsg = 11,  // Like kill, but does not run exit listeners, etc.
-    kLowMemoryMsg = 12,     // Run compactor, etc.
-    kDrainServiceExtensionsMsg = 13,  // Invoke pending service extensions
-    kCheckForReload = 14,  // Participate in other isolate group reload.
+    kDrainServiceExtensionsMsg = 12,  // Invoke pending service extensions
+    kCheckForReload = 13,  // Participate in other isolate group reload.
   };
   // The different Isolate API message priorities for ping and kill messages.
   enum LibMsgPriority {
@@ -1446,8 +1443,6 @@
   WeakTable* forward_table_old() { return forward_table_old_.get(); }
   void set_forward_table_old(WeakTable* table);
 
-  static void NotifyLowMemory();
-
   void RememberLiveTemporaries();
   void DeferredMarkLiveTemporaries();
 
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index c61d766..a04ea6f 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -666,10 +666,9 @@
   modified_libs_transitive_ = nullptr;
 
   if (FLAG_gc_during_reload) {
-    // We use kLowMemory to force the GC to compact, which is more likely to
-    // discover untracked pointers (and other issues, like incorrect class
-    // table).
-    heap->CollectAllGarbage(GCReason::kLowMemory);
+    // We force the GC to compact, which is more likely to discover untracked
+    // pointers (and other issues, like incorrect class table).
+    heap->CollectAllGarbage(GCReason::kDebugging, /*compact=*/ true);
   }
 
   // Copy the size table for isolate group & class tables for each isolate.
@@ -680,10 +679,9 @@
   }
 
   if (FLAG_gc_during_reload) {
-    // We use kLowMemory to force the GC to compact, which is more likely to
-    // discover untracked pointers (and other issues, like incorrect class
-    // table).
-    heap->CollectAllGarbage(GCReason::kLowMemory);
+    // We force the GC to compact, which is more likely to discover untracked
+    // pointers (and other issues, like incorrect class table).
+    heap->CollectAllGarbage(GCReason::kDebugging, /*compact=*/ true);
   }
 
   // We synchronously load the hot-reload kernel diff (which includes changed
@@ -711,10 +709,9 @@
     IG->program_reload_context()->ReloadPhase3FinalizeLoading();
 
     if (FLAG_gc_during_reload) {
-      // We use kLowMemory to force the GC to compact, which is more likely to
-      // discover untracked pointers (and other issues, like incorrect class
-      // table).
-      heap->CollectAllGarbage(GCReason::kLowMemory);
+      // We force the GC to compact, which is more likely to discover untracked
+      // pointers (and other issues, like incorrect class table).
+      heap->CollectAllGarbage(GCReason::kDebugging, /*compact=*/ true);
     }
 
     // If we use the CFE and performed a compilation, we need to notify that
@@ -742,10 +739,9 @@
 
         // We are still using the old class table at this point.
         if (FLAG_gc_during_reload) {
-          // We use kLowMemory to force the GC to compact, which is more likely
-          // to discover untracked pointers (and other issues, like incorrect
-          // class table).
-          heap->CollectAllGarbage(GCReason::kLowMemory);
+          // We force the GC to compact, which is more likely to discover
+          // untracked pointers (and other issues, like incorrect class table).
+          heap->CollectAllGarbage(GCReason::kDebugging, /*compact=*/ true);
         }
         const intptr_t count = locator.count();
         if (count > 0) {
@@ -783,10 +779,9 @@
         }
         // We are using the new class table now.
         if (FLAG_gc_during_reload) {
-          // We use kLowMemory to force the GC to compact, which is more likely
-          // to discover untracked pointers (and other issues, like incorrect
-          // class table).
-          heap->CollectAllGarbage(GCReason::kLowMemory);
+          // We force the GC to compact, which is more likely to discover
+          // untracked pointers (and other issues, like incorrect class table).
+          heap->CollectAllGarbage(GCReason::kDebugging, /*compact=*/ true);
         }
       }
       if (discard_class_tables) {
diff --git a/runtime/vm/metrics_test.cc b/runtime/vm/metrics_test.cc
index 2be5b71..5a9ebf7 100644
--- a/runtime/vm/metrics_test.cc
+++ b/runtime/vm/metrics_test.cc
@@ -88,8 +88,9 @@
 
   // Ensure we've done new/old GCs to ensure max metrics are initialized.
   String::New("<land-in-new-space>", Heap::kNew);
-  IsolateGroup::Current()->heap()->new_space()->Scavenge(GCReason::kLowMemory);
-  IsolateGroup::Current()->heap()->CollectAllGarbage(GCReason::kLowMemory);
+  IsolateGroup::Current()->heap()->new_space()->Scavenge(GCReason::kDebugging);
+  IsolateGroup::Current()->heap()->CollectAllGarbage(GCReason::kDebugging,
+                                                     /*compact=*/ true);
 
   // Ensure we've something live in new space.
   String::New("<land-in-new-space2>", Heap::kNew);
@@ -114,13 +115,6 @@
   }
 }
 
-class MetricsTestHelper {
- public:
-  static void Scavenge(Thread* thread) {
-    thread->heap()->CollectNewSpaceGarbage(thread, GCReason::kDebugging);
-  }
-};
-
 static uintptr_t event_counter;
 static const char* last_gcevent_type;
 static const char* last_gcevent_reason;
@@ -151,18 +145,18 @@
 
   Dart_SetGCEventCallback(&MyGCEventCallback);
 
-  MetricsTestHelper::Scavenge(Thread::Current());
+  GCTestHelper::CollectNewSpace();
 
   EXPECT_EQ(1UL, event_counter);
   EXPECT_STREQ("Scavenge", last_gcevent_type);
   EXPECT_STREQ("debugging", last_gcevent_reason);
 
   // This call emits 2 or 3 events.
-  IsolateGroup::Current()->heap()->CollectAllGarbage(GCReason::kLowMemory);
+  GCTestHelper::CollectAllGarbage(/*compact=*/ true);
 
   EXPECT_GE(event_counter, 3UL);
   EXPECT_STREQ("MarkCompact", last_gcevent_type);
-  EXPECT_STREQ("low memory", last_gcevent_reason);
+  EXPECT_STREQ("debugging", last_gcevent_reason);
 }
 
 }  // namespace dart
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index 793accb..abaeb8b 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -276,7 +276,7 @@
     Isolate* isolate = (thread == NULL) ? NULL : thread->isolate();
     CHECK_ISOLATE(isolate);
     TransitionNativeToVM _(thread);
-    IsolateGroup::Current()->heap()->CollectAllGarbage();
+    IsolateGroup::Current()->heap()->CollectAllGarbage(GCReason::kDebugging);
     return nullptr;
 
   } else if (strcmp(command, "is-thread-in-generated") == 0) {
diff --git a/runtime/vm/object_graph_copy.cc b/runtime/vm/object_graph_copy.cc
index 0eeb88c..638febe 100644
--- a/runtime/vm/object_graph_copy.cc
+++ b/runtime/vm/object_graph_copy.cc
@@ -1812,10 +1812,10 @@
       }
 
       if (FLAG_gc_on_foc_slow_path) {
-        // We use kLowMemory to force the GC to compact, which is more likely to
-        // discover untracked pointers (and other issues, like incorrect class
-        // table).
-        thread_->heap()->CollectAllGarbage(GCReason::kLowMemory);
+        // We force the GC to compact, which is more likely to discover
+        // untracked pointers (and other issues, like incorrect class table).
+        thread_->heap()->CollectAllGarbage(GCReason::kDebugging,
+                                           /*compact=*/ true);
       }
 
       // Fast copy failed due to
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index b5b7854..2fb6faf 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -202,7 +202,7 @@
   const uword pc_offset = caller_frame->pc() - code.PayloadStart();
 
   if (FLAG_shared_slow_path_triggers_gc) {
-    isolate->group()->heap()->CollectAllGarbage();
+    isolate->group()->heap()->CollectAllGarbage(GCReason::kDebugging);
   }
 
   const CodeSourceMap& map =
@@ -373,7 +373,7 @@
 
 DEFINE_RUNTIME_ENTRY_NO_LAZY_DEOPT(AllocateDouble, 0) {
   if (FLAG_shared_slow_path_triggers_gc) {
-    isolate->group()->heap()->CollectAllGarbage();
+    isolate->group()->heap()->CollectAllGarbage(GCReason::kDebugging);
   }
   arguments.SetReturn(Object::Handle(zone, Double::New(0.0)));
 }
@@ -385,28 +385,28 @@
 
 DEFINE_RUNTIME_ENTRY_NO_LAZY_DEOPT(AllocateMint, 0) {
   if (FLAG_shared_slow_path_triggers_gc) {
-    isolate->group()->heap()->CollectAllGarbage();
+    isolate->group()->heap()->CollectAllGarbage(GCReason::kDebugging);
   }
   arguments.SetReturn(Object::Handle(zone, Integer::New(kMaxInt64)));
 }
 
 DEFINE_RUNTIME_ENTRY_NO_LAZY_DEOPT(AllocateFloat32x4, 0) {
   if (FLAG_shared_slow_path_triggers_gc) {
-    isolate->group()->heap()->CollectAllGarbage();
+    isolate->group()->heap()->CollectAllGarbage(GCReason::kDebugging);
   }
   arguments.SetReturn(Object::Handle(zone, Float32x4::New(0.0, 0.0, 0.0, 0.0)));
 }
 
 DEFINE_RUNTIME_ENTRY_NO_LAZY_DEOPT(AllocateFloat64x2, 0) {
   if (FLAG_shared_slow_path_triggers_gc) {
-    isolate->group()->heap()->CollectAllGarbage();
+    isolate->group()->heap()->CollectAllGarbage(GCReason::kDebugging);
   }
   arguments.SetReturn(Object::Handle(zone, Float64x2::New(0.0, 0.0)));
 }
 
 DEFINE_RUNTIME_ENTRY_NO_LAZY_DEOPT(AllocateInt32x4, 0) {
   if (FLAG_shared_slow_path_triggers_gc) {
-    isolate->group()->heap()->CollectAllGarbage();
+    isolate->group()->heap()->CollectAllGarbage(GCReason::kDebugging);
   }
   arguments.SetReturn(Object::Handle(zone, Int32x4::New(0, 0, 0, 0)));
 }
@@ -2680,7 +2680,7 @@
   auto isolate_group = thread->isolate_group();
 
   if (FLAG_shared_slow_path_triggers_gc) {
-    isolate->group()->heap()->CollectAllGarbage();
+    isolate->group()->heap()->CollectAllGarbage(GCReason::kDebugging);
   }
 
   bool do_deopt = false;
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 336cd88..eb99152 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -4389,7 +4389,7 @@
   bool include_code_samples =
       BoolParameter::Parse(js->LookupParam("_code"), false);
 #if defined(DEBUG)
-  IsolateGroup::Current()->heap()->CollectAllGarbage();
+  IsolateGroup::Current()->heap()->CollectAllGarbage(GCReason::kDebugging);
 #endif
   if (CheckNativeAllocationProfilerDisabled(thread, js)) {
     return;
@@ -4435,7 +4435,7 @@
   }
   if (should_collect) {
     isolate_group->UpdateLastAllocationProfileGCTimestamp();
-    isolate_group->heap()->CollectAllGarbage();
+    isolate_group->heap()->CollectAllGarbage(GCReason::kDebugging);
   }
   isolate_group->class_table()->AllocationProfilePrintJSON(js, internal);
 }
diff --git a/runtime/vm/zone.cc b/runtime/vm/zone.cc
index fc0fd8d..33b2332 100644
--- a/runtime/vm/zone.cc
+++ b/runtime/vm/zone.cc
@@ -61,18 +61,20 @@
 }
 
 void Zone::Cleanup() {
-  {
-    MutexLocker ml(segment_cache_mutex);
-    ASSERT(segment_cache_size >= 0);
-    ASSERT(segment_cache_size <= kSegmentCacheCapacity);
-    while (segment_cache_size > 0) {
-      delete segment_cache[--segment_cache_size];
-    }
-  }
+  ClearCache();
   delete segment_cache_mutex;
   segment_cache_mutex = nullptr;
 }
 
+void Zone::ClearCache() {
+  MutexLocker ml(segment_cache_mutex);
+  ASSERT(segment_cache_size >= 0);
+  ASSERT(segment_cache_size <= kSegmentCacheCapacity);
+  while (segment_cache_size > 0) {
+    delete segment_cache[--segment_cache_size];
+  }
+}
+
 Zone::Segment* Zone::Segment::New(intptr_t size, Zone::Segment* next) {
   size = Utils::RoundUp(size, VirtualMemory::PageSize());
   VirtualMemory* memory = nullptr;
diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h
index 5156751..a22f953 100644
--- a/runtime/vm/zone.h
+++ b/runtime/vm/zone.h
@@ -90,6 +90,7 @@
   static void Init();
   static void Cleanup();
 
+  static void ClearCache();
   static intptr_t Size() { return total_size_; }
 
  private:
diff --git a/tests/lib/js/operator_test.dart b/tests/lib/js/operator_test.dart
new file mode 100644
index 0000000..cd688cc
--- /dev/null
+++ b/tests/lib/js/operator_test.dart
@@ -0,0 +1,170 @@
+// 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.
+
+@JS()
+library operator_test;
+
+import 'package:js/js.dart';
+
+@JS()
+class JSClass {
+  // https://dart.dev/guides/language/language-tour#_operators for the list of
+  // operators allowed by the language.
+  external void operator <(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator <=(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >=(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator -(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator +(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator /(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator ~/(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator *(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator %(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator |(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator ^(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator &(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator <<(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >>(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >>>(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator [](_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator []=(_, __);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator ~();
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external bool operator ==(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+}
+
+@JS()
+@anonymous
+class AnonymousClass {
+  external void operator <(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator <=(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >=(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator -(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator +(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator /(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator ~/(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator *(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator %(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator |(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator ^(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator &(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator <<(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >>(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >>>(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator [](_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator []=(_, __);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator ~();
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external bool operator ==(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+}
+
+@JS()
+class JSClassExtensions {}
+
+extension _ on JSClassExtensions {
+  // External operators in extensions are allowed for now, but don't work as
+  // intended. Specific operators will need to be allowlisted in the future.
+  // TODO(srujzs): Remove this test once we do that.
+  external void operator <(_);
+  external void operator >(_);
+  external void operator <=(_);
+  external void operator >=(_);
+  external void operator -(_);
+  external void operator +(_);
+  external void operator /(_);
+  external void operator ~/(_);
+  external void operator *(_);
+  external void operator %(_);
+  external void operator |(_);
+  external void operator ^(_);
+  external void operator &(_);
+  external void operator <<(_);
+  external void operator >>(_);
+  external void operator >>>(_);
+  external void operator [](_);
+  external void operator []=(_, __);
+  external void operator ~();
+  // No `==` as it's an `Object` method.
+}
+
+void main() {}
diff --git a/tests/lib_2/js/operator_test.dart b/tests/lib_2/js/operator_test.dart
new file mode 100644
index 0000000..cd688cc
--- /dev/null
+++ b/tests/lib_2/js/operator_test.dart
@@ -0,0 +1,170 @@
+// 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.
+
+@JS()
+library operator_test;
+
+import 'package:js/js.dart';
+
+@JS()
+class JSClass {
+  // https://dart.dev/guides/language/language-tour#_operators for the list of
+  // operators allowed by the language.
+  external void operator <(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator <=(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >=(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator -(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator +(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator /(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator ~/(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator *(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator %(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator |(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator ^(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator &(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator <<(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >>(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >>>(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator [](_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator []=(_, __);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator ~();
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external bool operator ==(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+}
+
+@JS()
+@anonymous
+class AnonymousClass {
+  external void operator <(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator <=(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >=(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator -(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator +(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator /(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator ~/(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator *(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator %(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator |(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator ^(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator &(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator <<(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >>(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator >>>(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator [](_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator []=(_, __);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external void operator ~();
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+  external bool operator ==(_);
+  //                     ^
+  // [web] JS interop classes do not support operator methods.
+}
+
+@JS()
+class JSClassExtensions {}
+
+extension _ on JSClassExtensions {
+  // External operators in extensions are allowed for now, but don't work as
+  // intended. Specific operators will need to be allowlisted in the future.
+  // TODO(srujzs): Remove this test once we do that.
+  external void operator <(_);
+  external void operator >(_);
+  external void operator <=(_);
+  external void operator >=(_);
+  external void operator -(_);
+  external void operator +(_);
+  external void operator /(_);
+  external void operator ~/(_);
+  external void operator *(_);
+  external void operator %(_);
+  external void operator |(_);
+  external void operator ^(_);
+  external void operator &(_);
+  external void operator <<(_);
+  external void operator >>(_);
+  external void operator >>>(_);
+  external void operator [](_);
+  external void operator []=(_, __);
+  external void operator ~();
+  // No `==` as it's an `Object` method.
+}
+
+void main() {}
diff --git a/tools/VERSION b/tools/VERSION
index a26c379..6533fe6 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 190
+PRERELEASE 191
 PRERELEASE_PATCH 0
\ No newline at end of file