Fix constant evaluation for the new bool operators

Change-Id: I4a30544b2d0e5cff8287dbe5fc83387b4e92a875
Reviewed-on: https://dart-review.googlesource.com/c/88437
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/constant/value.dart b/pkg/analyzer/lib/src/dart/constant/value.dart
index 189a436..4666351 100644
--- a/pkg/analyzer/lib/src/dart/constant/value.dart
+++ b/pkg/analyzer/lib/src/dart/constant/value.dart
@@ -1893,8 +1893,12 @@
   BoolState logicalAnd(InstanceState rightOperand) {
     assertBool(this);
     assertBool(rightOperand);
-    return BoolState.from(
-        convertToBool().value & rightOperand.convertToBool().value);
+    bool leftValue = convertToBool().value;
+    bool rightValue = rightOperand.convertToBool().value;
+    if (leftValue == null || rightValue == null) {
+      return BoolState.UNKNOWN_VALUE;
+    }
+    return BoolState.from(leftValue & rightValue);
   }
 
   /**
@@ -1918,8 +1922,12 @@
   BoolState logicalOr(InstanceState rightOperand) {
     assertBool(this);
     assertBool(rightOperand);
-    return BoolState.from(
-        convertToBool().value | rightOperand.convertToBool().value);
+    bool leftValue = convertToBool().value;
+    bool rightValue = rightOperand.convertToBool().value;
+    if (leftValue == null || rightValue == null) {
+      return BoolState.UNKNOWN_VALUE;
+    }
+    return BoolState.from(leftValue | rightValue);
   }
 
   /**
@@ -1946,8 +1954,12 @@
   BoolState logicalXor(InstanceState rightOperand) {
     assertBool(this);
     assertBool(rightOperand);
-    return BoolState.from(
-        convertToBool().value ^ rightOperand.convertToBool().value);
+    bool leftValue = convertToBool().value;
+    bool rightValue = rightOperand.convertToBool().value;
+    if (leftValue == null || rightValue == null) {
+      return BoolState.UNKNOWN_VALUE;
+    }
+    return BoolState.from(leftValue ^ rightValue);
   }
 
   /**
diff --git a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
index f6af9c7..b144d20 100644
--- a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
@@ -112,7 +112,7 @@
     expect(result.type, typeProvider.nullType);
   }
 
-  test_visitBinaryExpression_and_bool() async {
+  test_visitBinaryExpression_and_bool_known_known() async {
     CompilationUnit compilationUnit = await resolveSource('''
 const c = false & true;
 ''');
@@ -121,6 +121,37 @@
     expect(result.type, typeProvider.boolType);
   }
 
+  test_visitBinaryExpression_and_bool_known_unknown() async {
+    CompilationUnit compilationUnit = await resolveSource('''
+const b = bool.fromEnvironment('y');
+const c = false & b;
+''');
+    DartObjectImpl result = _evaluateConstant(compilationUnit, 'c',
+        experiments: [EnableString.constant_update_2018]);
+    expect(result.type, typeProvider.boolType);
+  }
+
+  test_visitBinaryExpression_and_bool_unknown_known() async {
+    CompilationUnit compilationUnit = await resolveSource('''
+const a = bool.fromEnvironment('x');
+const c = a & true;
+''');
+    DartObjectImpl result = _evaluateConstant(compilationUnit, 'c',
+        experiments: [EnableString.constant_update_2018]);
+    expect(result.type, typeProvider.boolType);
+  }
+
+  test_visitBinaryExpression_and_bool_unknown_unknown() async {
+    CompilationUnit compilationUnit = await resolveSource('''
+const a = bool.fromEnvironment('x');
+const b = bool.fromEnvironment('y');
+const c = a & b;
+''');
+    DartObjectImpl result = _evaluateConstant(compilationUnit, 'c',
+        experiments: [EnableString.constant_update_2018]);
+    expect(result.type, typeProvider.boolType);
+  }
+
   test_visitBinaryExpression_and_int() async {
     CompilationUnit compilationUnit = await resolveSource('''
 const c = 3 & 5;
@@ -139,7 +170,7 @@
         experiments: [EnableString.constant_update_2018]);
   }
 
-  test_visitBinaryExpression_or_bool() async {
+  test_visitBinaryExpression_or_bool_known_known() async {
     CompilationUnit compilationUnit = await resolveSource('''
 const c = false | true;
 ''');
@@ -148,6 +179,37 @@
     expect(result.type, typeProvider.boolType);
   }
 
+  test_visitBinaryExpression_or_bool_known_unknown() async {
+    CompilationUnit compilationUnit = await resolveSource('''
+const b = bool.fromEnvironment('y');
+const c = false | b;
+''');
+    DartObjectImpl result = _evaluateConstant(compilationUnit, 'c',
+        experiments: [EnableString.constant_update_2018]);
+    expect(result.type, typeProvider.boolType);
+  }
+
+  test_visitBinaryExpression_or_bool_unknown_known() async {
+    CompilationUnit compilationUnit = await resolveSource('''
+const a = bool.fromEnvironment('x');
+const c = a | true;
+''');
+    DartObjectImpl result = _evaluateConstant(compilationUnit, 'c',
+        experiments: [EnableString.constant_update_2018]);
+    expect(result.type, typeProvider.boolType);
+  }
+
+  test_visitBinaryExpression_or_bool_unknown_unknown() async {
+    CompilationUnit compilationUnit = await resolveSource('''
+const a = bool.fromEnvironment('x');
+const b = bool.fromEnvironment('y');
+const c = a | b;
+''');
+    DartObjectImpl result = _evaluateConstant(compilationUnit, 'c',
+        experiments: [EnableString.constant_update_2018]);
+    expect(result.type, typeProvider.boolType);
+  }
+
   test_visitBinaryExpression_or_int() async {
     CompilationUnit compilationUnit = await resolveSource('''
 const c = 3 | 5;
@@ -263,7 +325,7 @@
     expect(result.isNull, isTrue);
   }
 
-  test_visitBinaryExpression_xor_bool() async {
+  test_visitBinaryExpression_xor_bool_known_known() async {
     CompilationUnit compilationUnit = await resolveSource('''
 const c = false ^ true;
 ''');
@@ -272,6 +334,37 @@
     expect(result.type, typeProvider.boolType);
   }
 
+  test_visitBinaryExpression_xor_bool_known_unknown() async {
+    CompilationUnit compilationUnit = await resolveSource('''
+const b = bool.fromEnvironment('y');
+const c = false ^ b;
+''');
+    DartObjectImpl result = _evaluateConstant(compilationUnit, 'c',
+        experiments: [EnableString.constant_update_2018]);
+    expect(result.type, typeProvider.boolType);
+  }
+
+  test_visitBinaryExpression_xor_bool_unknown_known() async {
+    CompilationUnit compilationUnit = await resolveSource('''
+const a = bool.fromEnvironment('x');
+const c = a ^ true;
+''');
+    DartObjectImpl result = _evaluateConstant(compilationUnit, 'c',
+        experiments: [EnableString.constant_update_2018]);
+    expect(result.type, typeProvider.boolType);
+  }
+
+  test_visitBinaryExpression_xor_bool_unknown_unknown() async {
+    CompilationUnit compilationUnit = await resolveSource('''
+const a = bool.fromEnvironment('x');
+const b = bool.fromEnvironment('y');
+const c = a ^ b;
+''');
+    DartObjectImpl result = _evaluateConstant(compilationUnit, 'c',
+        experiments: [EnableString.constant_update_2018]);
+    expect(result.type, typeProvider.boolType);
+  }
+
   test_visitBinaryExpression_xor_int() async {
     CompilationUnit compilationUnit = await resolveSource('''
 const c = 3 ^ 5;