[analyzer] Refactor visitConditionExpression in the const evaluator.

Moved a test from `constant_test.dart` to slowly migrate it over.

Change-Id: Id7d0ef0edcfa4fced056ec8fc937b060a74f4468
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/306919
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Kallen Tu <kallentu@google.com>
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index 4866938..060aa73 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -690,36 +690,42 @@
   }
 
   @override
-  Constant? visitConditionalExpression(ConditionalExpression node) {
+  Constant visitConditionalExpression(ConditionalExpression node) {
     var condition = node.condition;
-    // TODO(kallentu): Remove this unwrapping when helpers can handle Constant.
-    var conditionConstant = condition.accept(this);
-    var conditionResult =
-        conditionConstant is DartObjectImpl ? conditionConstant : null;
+    var conditionConstant = _getConstant(condition);
+    if (conditionConstant is! DartObjectImpl) {
+      return conditionConstant;
+    }
 
-    if (conditionResult == null) {
-      return conditionResult;
-    } else if (!conditionResult.isBool) {
+    if (!conditionConstant.isBool) {
+      // TODO(kallentu): Don't report error here.
       _errorReporter.reportErrorForNode(
           CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL, condition);
-      return null;
+      return InvalidConstant(
+          condition, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL);
     }
-    conditionResult =
-        _dartObjectComputer.applyBooleanConversion(condition, conditionResult);
-    if (conditionResult == null) {
-      return conditionResult;
+    conditionConstant = _dartObjectComputer.applyBooleanConversion(
+        condition, conditionConstant);
+    if (conditionConstant is! DartObjectImpl) {
+      return conditionConstant;
     }
 
-    var conditionResultBool = conditionResult.toBoolValue();
+    var conditionResultBool = conditionConstant.toBoolValue();
     if (conditionResultBool == true) {
       _reportNotPotentialConstants(node.elseExpression);
-      return node.thenExpression.accept(this);
+      return _getConstant(node.thenExpression);
     } else if (conditionResultBool == false) {
       _reportNotPotentialConstants(node.thenExpression);
-      return node.elseExpression.accept(this);
+      return _getConstant(node.elseExpression);
     } else {
-      node.thenExpression.accept(this);
-      node.elseExpression.accept(this);
+      var thenConstant = _getConstant(node.thenExpression);
+      if (thenConstant is InvalidConstant) {
+        return thenConstant;
+      }
+      var elseConstant = _getConstant(node.elseExpression);
+      if (elseConstant is InvalidConstant) {
+        return elseConstant;
+      }
       return DartObjectImpl.validWithUnknownValue(
         typeSystem,
         node.typeOrThrow,
@@ -1738,16 +1744,15 @@
   /// Return the result of applying boolean conversion to the
   /// [evaluationResult]. The [node] is the node against which errors should be
   /// reported.
-  DartObjectImpl? applyBooleanConversion(
-      AstNode node, DartObjectImpl? evaluationResult) {
-    if (evaluationResult != null) {
-      try {
-        return evaluationResult.convertToBool(_typeSystem);
-      } on EvaluationException catch (exception) {
-        _errorReporter.reportErrorForNode(exception.errorCode, node);
-      }
+  Constant applyBooleanConversion(
+      AstNode node, DartObjectImpl evaluationResult) {
+    try {
+      return evaluationResult.convertToBool(_typeSystem);
+    } on EvaluationException catch (exception) {
+      // TODO(kallentu): Don't report error here.
+      _errorReporter.reportErrorForNode(exception.errorCode, node);
+      return InvalidConstant(node, exception.errorCode);
     }
-    return null;
   }
 
   DartObjectImpl? bitNot(Expression node, DartObjectImpl? evaluationResult) {
diff --git a/pkg/analyzer/test/generated/constant_test.dart b/pkg/analyzer/test/generated/constant_test.dart
index dc3ab06..7b8f59f 100644
--- a/pkg/analyzer/test/generated/constant_test.dart
+++ b/pkg/analyzer/test/generated/constant_test.dart
@@ -66,26 +66,6 @@
 ''');
   }
 
-  test_conditionalExpression_unknownCondition_dynamic() async {
-    await assertErrorsInCode('''
-const bool kIsWeb = identical(0, 0.0);
-const x = kIsWeb ? a : b;
-''', [
-      error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 58,
-          1),
-      error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 58, 1),
-      error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 62, 1),
-      error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 62,
-          1),
-    ]);
-
-    var result = findElement.topVar('x').evaluationResult;
-    assertDartObjectText(result.value, r'''
-InvalidType <unknown>
-  variable: self::@variable::x
-''');
-  }
-
   test_constructorInvocation_fieldInitializer() async {
     var result = await _getExpressionValue("const C(2)", context: '''
 class C {
diff --git a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
index cbc0101..5766372 100644
--- a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
@@ -932,6 +932,52 @@
     _assertTypeArguments(result, ['int']);
   }
 
+  test_visitConditionalExpression_unknownCondition() async {
+    await assertNoErrorsInCode('''
+const bool kIsWeb = identical(0, 0.0);
+const x = kIsWeb ? 0 : 1;
+''');
+    _assertValue('x', r'''
+int <unknown>
+  variable: self::@variable::x
+''');
+  }
+
+  test_visitConditionalExpression_unknownCondition_errorInConstructor() async {
+    await assertErrorsInCode(r'''
+const bool kIsWeb = identical(0, 0.0);
+
+var a = 2;
+const x = A(kIsWeb ? 0 : a);
+
+class A {
+  const A(int _);
+}
+''', [
+      error(CompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH, 63, 14),
+      error(CompileTimeErrorCode.INVALID_CONSTANT, 76, 1),
+      error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 76,
+          1),
+    ]);
+    _assertValue('x', r'''
+A
+  variable: self::@variable::x
+''');
+  }
+
+  test_visitConditionalExpression_unknownCondition_undefinedIdentifier() async {
+    await assertErrorsInCode(r'''
+const bool kIsWeb = identical(0, 0.0);
+const x = kIsWeb ? a : b;
+''', [
+      error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 58, 1),
+      error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 58,
+          1),
+      error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 62, 1),
+    ]);
+    _assertNull('x');
+  }
+
   test_visitFunctionReference_explicitTypeArgs_complexExpression() async {
     await resolveTestCode('''
 const b = true;
@@ -1298,6 +1344,24 @@
     final has = value.hasPrimitiveEquality(featureSet);
     expect(has, isTrue);
   }
+
+  void _assertNull(String variableName) {
+    final variable = findElement.topVar(variableName) as ConstVariableElement;
+    final evaluationResult = variable.evaluationResult;
+    if (evaluationResult == null) {
+      fail('Not evaluated: $this');
+    }
+    expect(evaluationResult.value, isNull);
+  }
+
+  void _assertValue(String variableName, String expectedText) {
+    final variable = findElement.topVar(variableName) as ConstVariableElement;
+    final evaluationResult = variable.evaluationResult;
+    if (evaluationResult == null) {
+      fail('Not evaluated: $this');
+    }
+    assertDartObjectText(evaluationResult.value, expectedText);
+  }
 }
 
 @reflectiveTest
diff --git a/pkg/analyzer/test/src/diagnostics/const_constructor_param_type_mismatch_test.dart b/pkg/analyzer/test/src/diagnostics/const_constructor_param_type_mismatch_test.dart
index 060ade5..6a50c49 100644
--- a/pkg/analyzer/test/src/diagnostics/const_constructor_param_type_mismatch_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/const_constructor_param_type_mismatch_test.dart
@@ -370,6 +370,24 @@
 }
 ''');
   }
+
+  test_unknown_conditionalExpression_unknownCondition_errorInBranch() async {
+    await assertErrorsInCode(r'''
+const bool kIsWeb = identical(0, 0.0);
+
+void f() {
+  var x = 2;
+  const A(kIsWeb ? 0 : x);
+}
+
+class A {
+  const A(int _);
+}
+''', [
+      error(CompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH, 74, 14),
+      error(CompileTimeErrorCode.INVALID_CONSTANT, 87, 1),
+    ]);
+  }
 }
 
 @reflectiveTest