[_fe_analyzer_shared] Exclude patterns with when clauses from exhaustiveness

Change-Id: I6cc552854139d9476c9b33d93a6d7fdc55e845a3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/285903
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/_fe_analyzer_shared/test/exhaustiveness/data/when.dart b/pkg/_fe_analyzer_shared/test/exhaustiveness/data/when.dart
new file mode 100644
index 0000000..928a5b9
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/exhaustiveness/data/when.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2023, 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.
+
+sealed class A {
+  int get field;
+}
+
+class B extends A {
+  final int field;
+  B(this.field);
+}
+
+class C extends A {
+  final int field;
+
+  C(this.field);
+}
+
+method(A a) {
+  /*
+   fields={field:int,hashCode:int,runtimeType:Type},
+   subtypes={B,C},
+   type=A
+  */switch (a) {
+    /*space=B*/case B():
+    /*space=C*/case C():
+  }
+  /*
+   fields={field:int,hashCode:int,runtimeType:Type},
+   subtypes={B,C},
+   type=A
+  */switch (a) {
+    /*space=B(field: int)*/case B(:var field):
+    /*space=C(field: int)*/case C(:var field):
+  }
+  /*
+   error=non-exhaustive:B,
+   fields={field:int,hashCode:int,runtimeType:Type},
+   subtypes={B,C},
+   type=A
+  */switch (a) {
+    /*space=??*/case B(:var field) when field > 0:
+    /*space=C(field: int)*/case C(:var field):
+  }
+  /*
+   error=non-exhaustive:C,
+   fields={field:int,hashCode:int,runtimeType:Type},
+   subtypes={B,C},
+   type=A
+  */switch (a) {
+    /*space=B(field: int)*/case B(:var field):
+    /*space=??*/case C(:var field) when field > 0:
+  }
+}
\ No newline at end of file
diff --git a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
index a6c4fee..4fc9a29 100644
--- a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
+++ b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
@@ -780,7 +780,6 @@
       if (guardedPattern != null) {
         Space space;
         if (guardedPattern.whenClause != null) {
-          // TODO(johnniwinther): Test this.
           space = Space(_exhaustivenessCache.getUnknownStaticType());
         } else {
           final pattern = guardedPattern.pattern;
diff --git a/pkg/front_end/lib/src/fasta/kernel/exhaustiveness.dart b/pkg/front_end/lib/src/fasta/kernel/exhaustiveness.dart
index f9aa7a0..3633324 100644
--- a/pkg/front_end/lib/src/fasta/kernel/exhaustiveness.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/exhaustiveness.dart
@@ -341,14 +341,19 @@
 
 class PatternCaseInfo extends SwitchCaseInfo {
   final Pattern pattern;
+
+  final bool hasGuard;
+
   @override
   final int fileOffset;
 
-  PatternCaseInfo(this.pattern, {required this.fileOffset});
+  PatternCaseInfo(this.pattern,
+      {required this.hasGuard, required this.fileOffset});
 
   @override
   Space createSpace(CfeExhaustivenessCache cache,
       Map<Node, Constant?> constants, StaticTypeContext context) {
+    if (hasGuard) return new Space(cache.getUnknownStaticType());
     return convertPatternToSpace(cache, pattern, constants, context,
         nonNull: false);
   }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart
index e45e01e..c1ccde5 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart
@@ -9856,6 +9856,7 @@
 
         pushRewrite(case_);
         _switchCasePatternInfo.add(new PatternCaseInfo(patternGuard.pattern,
+            hasGuard: patternGuard.guard != null,
             fileOffset: case_.caseOffsets[subIndex]));
       }
     } else {
@@ -9891,6 +9892,7 @@
         }
       }
       _switchCasePatternInfo.add(new PatternCaseInfo(patternGuard.pattern,
+          hasGuard: patternGuard.guard != null,
           fileOffset: switchExpressionCase.fileOffset));
     }
   }
diff --git a/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.strong.expect b/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.strong.expect
index 5598ff4..8f7c3a5 100644
--- a/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.strong.expect
+++ b/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.strong.expect
@@ -1,4 +1,12 @@
 library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart:5:16: Error: The type 'dynamic' is not exhaustively matched by the switch cases.
+// Try adding a default case or cases that match Object.
+// f(x) => switch(x) {
+//                ^
+//
 import self as self;
 import "dart:core" as core;
 
diff --git a/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.strong.transformed.expect
index 78bd2f1..0bbfc21 100644
--- a/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.strong.transformed.expect
@@ -1,4 +1,12 @@
 library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart:5:16: Error: The type 'dynamic' is not exhaustively matched by the switch cases.
+// Try adding a default case or cases that match Object.
+// f(x) => switch(x) {
+//                ^
+//
 import self as self;
 import "dart:core" as core;
 
diff --git a/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.weak.expect b/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.weak.expect
index 5598ff4..8f7c3a5 100644
--- a/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.weak.expect
+++ b/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.weak.expect
@@ -1,4 +1,12 @@
 library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart:5:16: Error: The type 'dynamic' is not exhaustively matched by the switch cases.
+// Try adding a default case or cases that match Object.
+// f(x) => switch(x) {
+//                ^
+//
 import self as self;
 import "dart:core" as core;
 
diff --git a/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.weak.modular.expect b/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.weak.modular.expect
index 5598ff4..8f7c3a5 100644
--- a/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.weak.modular.expect
@@ -1,4 +1,12 @@
 library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart:5:16: Error: The type 'dynamic' is not exhaustively matched by the switch cases.
+// Try adding a default case or cases that match Object.
+// f(x) => switch(x) {
+//                ^
+//
 import self as self;
 import "dart:core" as core;
 
diff --git a/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.weak.transformed.expect b/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.weak.transformed.expect
index 78bd2f1..0bbfc21 100644
--- a/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart.weak.transformed.expect
@@ -1,4 +1,12 @@
 library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/patterns/switchExpression_onePattern_guarded.dart:5:16: Error: The type 'dynamic' is not exhaustively matched by the switch cases.
+// Try adding a default case or cases that match Object.
+// f(x) => switch(x) {
+//                ^
+//
 import self as self;
 import "dart:core" as core;