[analyzer] Issue 53163: Fix crash with unresolved object in String length for const expressions.

Unresolved types would throw in `stringLength` and we don't handle them the same way we do with the other operators. Throwing EvaluationExceptions is the problem here, but that's for another CL.

In the meantime, this CL makes `stringLength` consistent to the other operators in the DartObjectComputer.

Fixes https://github.com/dart-lang/sdk/issues/53163

Bug: https://github.com/dart-lang/sdk/issues/53163
Change-Id: Ib99b61736d699056fa3c379e4d9c79756a4425f3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/319562
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Kallen Tu <kallentu@google.com>
This commit is contained in:
Kallen Tu
2023-08-17 19:48:28 +00:00
committed by Commit Queue
parent 7703609cc1
commit 48245c1064
8 changed files with 78 additions and 2 deletions
@@ -421,6 +421,8 @@ CompileTimeErrorCode.CONST_EVAL_TYPE_INT:
status: noFix
CompileTimeErrorCode.CONST_EVAL_TYPE_NUM:
status: noFix
CompileTimeErrorCode.CONST_EVAL_TYPE_STRING:
status: noFix
CompileTimeErrorCode.CONST_EVAL_TYPE_TYPE:
status: noFix
CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE:
@@ -1538,7 +1538,7 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
errorNode, CompileTimeErrorCode.CONST_EVAL_PROPERTY_ACCESS,
arguments: [identifier.name, targetType]);
}
return targetResult.stringLength(typeSystem);
return _dartObjectComputer.stringLength(errorNode, targetResult);
}
// TODO(kallentu): Make a more specific error here if we aren't accessing
@@ -2173,6 +2173,16 @@ class DartObjectComputer {
}
}
Constant stringLength(AstNode node, DartObjectImpl evaluationResult) {
try {
return evaluationResult.stringLength(_typeSystem);
} on EvaluationException catch (exception) {
// TODO(kallentu): Don't report error here.
_errorReporter.reportErrorForNode(exception.errorCode, node);
return InvalidConstant(node, exception.errorCode);
}
}
Constant times(BinaryExpression node, DartObjectImpl leftOperand,
DartObjectImpl rightOperand) {
try {
@@ -1594,7 +1594,7 @@ abstract class InstanceState {
/// Throw an exception if the given [state] does not represent a String value.
void assertString(InstanceState state) {
if (state is! StringState) {
throw EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL);
throw EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_STRING);
}
}
+8
View File
@@ -916,6 +916,14 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
"In constant expressions, operands of this operator must be of type 'num'.",
);
/// No parameters.
static const CompileTimeErrorCode CONST_EVAL_TYPE_STRING =
CompileTimeErrorCode(
'CONST_EVAL_TYPE_STRING',
"In constant expressions, operands of this operator must be of type "
"'String'.",
);
static const CompileTimeErrorCode CONST_EVAL_TYPE_TYPE = CompileTimeErrorCode(
'CONST_EVAL_TYPE_TYPE',
"In constant expressions, operands of this operator must be of type "
@@ -126,6 +126,7 @@ const List<ErrorCode> errorCodeValues = [
CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING,
CompileTimeErrorCode.CONST_EVAL_TYPE_INT,
CompileTimeErrorCode.CONST_EVAL_TYPE_NUM,
CompileTimeErrorCode.CONST_EVAL_TYPE_STRING,
CompileTimeErrorCode.CONST_EVAL_TYPE_TYPE,
CompileTimeErrorCode.CONST_FIELD_INITIALIZER_NOT_ASSIGNABLE,
CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE,
+3
View File
@@ -2670,6 +2670,9 @@ CompileTimeErrorCode:
e2, e1 / e2, e1 ~/ e2, e1 > e2, e1 < e2, e1 >= e2, e1 <= e2 or e1 % e2,
where e, e1 and e2 are constant expressions that evaluate to a numeric
value or to null.
CONST_EVAL_TYPE_STRING:
problemMessage: "In constant expressions, operands of this operator must be of type 'String'."
comment: No parameters.
CONST_EVAL_TYPE_TYPE:
problemMessage: "In constant expressions, operands of this operator must be of type 'Type'."
CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE:
@@ -2883,6 +2883,32 @@ const b = B('');
]);
}
test_visitPropertyAccess_length_unresolvedType() async {
await assertErrorsInCode('''
class B {
final l;
const B(String o) : l = o.length;
}
const y = B(x);
''', [
error(
CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION,
70,
4,
contextMessages: [
ExpectedContextMessage(testFile.path, 47, 8,
text:
"The exception is 'In constant expressions, operands of this operator must be of type 'String'.' and occurs here."),
],
),
error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 72, 1),
error(CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT, 72, 1),
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 72,
1),
]);
}
test_visitSimpleIdentifier_dynamic() async {
await resolveTestCode('''
const a = dynamic;
@@ -471,6 +471,32 @@ class RequiresNonEmptyList {
]);
}
test_property_length_unresolvedType() async {
await assertErrorsInCode('''
class B {
final l;
const B(String o) : l = o.length;
}
const y = B(x);
''', [
error(
CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION,
70,
4,
contextMessages: [
ExpectedContextMessage(testFile.path, 47, 8,
text:
"The exception is 'In constant expressions, operands of this operator must be of type 'String'.' and occurs here."),
],
),
error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 72, 1),
error(CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT, 72, 1),
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 72,
1),
]);
}
test_redirectingConstructor_paramTypeMismatch() async {
await assertErrorsInCode(r'''
class A {