[cfe] Check primitive equals in legacy libraries

This enables the check for primitive equals in switch cases in
legacy libraries.

Change-Id: Iddc464f39525d5167a5c6e8c40c95acc3c245d76
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/231701
Reviewed-by: Joshua Litt <joshualitt@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index 9aca3e3..4bb0a08 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -728,7 +728,7 @@
     TreeNode result = super.visitSwitchStatement(node, removalSentinel);
     Library library = constantEvaluator.libraryOf(node);
     // ignore: unnecessary_null_comparison
-    if (library != null && library.isNonNullableByDefault) {
+    if (library != null) {
       for (SwitchCase switchCase in node.cases) {
         for (Expression caseExpression in switchCase.expressions) {
           if (caseExpression is ConstantExpression) {
diff --git a/tests/language/type/constants_test.dart b/tests/language/type/constants_test.dart
index 560e485..2a35320 100644
--- a/tests/language/type/constants_test.dart
+++ b/tests/language/type/constants_test.dart
@@ -15,6 +15,9 @@
 
 const Type numType = num;
 
+const bool fromEnvironment =
+    const bool.fromEnvironment("foo", defaultValue: true);
+
 Type argumentType<T>() => T;
 
 void testSwitch<T extends MyType>(args) {
@@ -22,7 +25,7 @@
   for (int i = 0; i < types.length; i++) {
     switch (types[i]) {
       // Must be type literal or not override `==`.
-      case const MyType(): //# 01: compile-time error
+      case const MyType(0): //# 01: compile-time error
 
       // Must not be type variable.
       case T: //# 02: compile-time error
@@ -39,6 +42,8 @@
         throw "unreachable: num #$i";
       case MyType:
         break;
+      // Must be type literal or not override `==`.
+      case fromEnvironment ? const MyType(1) : Type: //# 07: compile-time error
       default:
         throw "unreachable: default #$i";
     }
@@ -48,7 +53,7 @@
 void testMaps<T extends MyType>(args) {
   const map = {
     // Must be type literal or not override `==`.
-    MyType(): 0, //# 04: compile-time error
+    MyType(0): 0, //# 04: compile-time error
 
     // Must not be type variable.
     T: 0, //# 05: compile-time error
@@ -61,6 +66,8 @@
     int: 1,
     String: 2,
     numType: 3,
+    // Must be type literal or not override `==`.
+    fromEnvironment ? const MyType(1) : Type: 4, //# 08: compile-time error
   };
   if (map[MyType] != 0) throw "Map Error: ${MyType} as literal";
   if (map[T] != 0) throw "Map Error: ${T} as type argument";
@@ -76,7 +83,8 @@
 // An implementation of `Type` which overrides `==`,
 // but is not the value of a constant type literal.
 class MyType implements Type {
-  const MyType();
+  final int value;
+  const MyType(this.value);
   int get hashCode => 0;
   bool operator ==(Object other) => identical(this, other);
 }
diff --git a/tests/language_2/const/switch2_test.dart b/tests/language_2/const/switch2_test.dart
index 772846e..ce881a4 100644
--- a/tests/language_2/const/switch2_test.dart
+++ b/tests/language_2/const/switch2_test.dart
@@ -13,6 +13,7 @@
   // [analyzer] COMPILE_TIME_ERROR.SWITCH_EXPRESSION_NOT_ASSIGNABLE
     case 0.0:
     //   ^
+    // [cfe] Case expression '0.0' does not have a primitive operator '=='.
     // [cfe] Type 'int' of the switch expression isn't assignable to the type 'double' of this case expression.
       print("illegal");
       break;
diff --git a/tests/language_2/switch/bad_case_test.dart b/tests/language_2/switch/bad_case_test.dart
index 3e3a340..85c88fa 100644
--- a/tests/language_2/switch/bad_case_test.dart
+++ b/tests/language_2/switch/bad_case_test.dart
@@ -34,8 +34,12 @@
 //^^^^^^
 // [analyzer] COMPILE_TIME_ERROR.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS
     case 3.14:
+    //   ^
+    // [cfe] Case expression '3.14' does not have a primitive operator '=='.
       return "Pi";
     case 2.71828:
+    //   ^
+    // [cfe] Case expression '2.71828' does not have a primitive operator '=='.
       return "Huh?";
   }
   return null;
diff --git a/tests/language_2/switch/case_test.dart b/tests/language_2/switch/case_test.dart
index af15ac6..fa519fd0 100644
--- a/tests/language_2/switch/case_test.dart
+++ b/tests/language_2/switch/case_test.dart
@@ -35,6 +35,8 @@
 //^^^^^^
 // [analyzer] COMPILE_TIME_ERROR.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS
     case const A.B(): Expect.fail("bad switch"); break;
+    //         ^
+    // [cfe] Case expression 'B {}' does not have a primitive operator '=='.
   }
 
   switch (new C()) {
@@ -59,5 +61,7 @@
     case const A.B(): Expect.fail("bad switch"); break;
     //   ^^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.INCONSISTENT_CASE_EXPRESSION_TYPES
+    //         ^
+    // [cfe] Case expression 'B {}' does not have a primitive operator '=='.
   }
 }
diff --git a/tests/language_2/type/constants_test.dart b/tests/language_2/type/constants_test.dart
index ded5300..cda34ff 100644
--- a/tests/language_2/type/constants_test.dart
+++ b/tests/language_2/type/constants_test.dart
@@ -17,6 +17,9 @@
 
 const Type numType = num;
 
+const bool fromEnvironment =
+    const bool.fromEnvironment("foo", defaultValue: true);
+
 Type argumentType<T>() => T;
 
 void testSwitch<T extends MyType>(args) {
@@ -24,7 +27,7 @@
   for (int i = 0; i < types.length; i++) {
     switch (types[i]) {
       // Must be type literal or not override `==`.
-      case const MyType(): //# 01: compile-time error
+      case const MyType(0): //# 01: compile-time error
 
       // Must not be type variable.
       case T: //# 02: compile-time error
@@ -41,6 +44,8 @@
         throw "unreachable: num #$i";
       case MyType:
         break;
+      // Must be type literal or not override `==`.
+      case fromEnvironment ? const MyType(1) : Type: //# 07: compile-time error
       default:
         throw "unreachable: default #$i";
     }
@@ -50,7 +55,7 @@
 void testMaps<T extends MyType>(args) {
   const map = {
     // Must be type literal or not override `==`.
-    MyType(): 0, //# 04: compile-time error
+    MyType(0): 0, //# 04: compile-time error
 
     // Must not be type variable.
     T: 0, //# 05: compile-time error
@@ -63,6 +68,8 @@
     int: 1,
     String: 2,
     numType: 3,
+    // Must be type literal or not override `==`.
+    fromEnvironment ? const MyType(1) : Type: 4, //# 08: compile-time error
   };
   if (map[MyType] != 0) throw "Map Error: ${MyType} as literal";
   if (map[T] != 0) throw "Map Error: ${T} as type argument";
@@ -78,7 +85,8 @@
 // An implementation of `Type` which overrides `==`,
 // but is not the value of a constant type literal.
 class MyType implements Type {
-  const MyType();
+  final int value;
+  const MyType(this.value);
   int get hashCode => 0;
   bool operator ==(Object other) => identical(this, other);
 }