[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