From 48245c1064db59ac5be23fc16fc00a2120e925ae Mon Sep 17 00:00:00 2001 From: Kallen Tu Date: Thu, 17 Aug 2023 19:48:28 +0000 Subject: [PATCH] [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 Commit-Queue: Kallen Tu --- .../services/correction/error_fix_status.yaml | 2 ++ .../lib/src/dart/constant/evaluation.dart | 12 ++++++++- pkg/analyzer/lib/src/dart/constant/value.dart | 2 +- pkg/analyzer/lib/src/error/codes.g.dart | 8 ++++++ .../lib/src/error/error_code_values.g.dart | 1 + pkg/analyzer/messages.yaml | 3 +++ .../src/dart/constant/evaluation_test.dart | 26 +++++++++++++++++++ .../const_eval_throws_exception_test.dart | 26 +++++++++++++++++++ 8 files changed, 78 insertions(+), 2 deletions(-) diff --git a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml index 370573e4c70..50fb626957f 100644 --- a/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml +++ b/pkg/analysis_server/lib/src/services/correction/error_fix_status.yaml @@ -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: diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart index 21e964ced6b..92432f63c82 100644 --- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart +++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart @@ -1538,7 +1538,7 @@ class ConstantVisitor extends UnifyingAstVisitor { 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 { diff --git a/pkg/analyzer/lib/src/dart/constant/value.dart b/pkg/analyzer/lib/src/dart/constant/value.dart index d83f18b378e..578e2896038 100644 --- a/pkg/analyzer/lib/src/dart/constant/value.dart +++ b/pkg/analyzer/lib/src/dart/constant/value.dart @@ -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); } } diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart index 02ad133d899..23d1d335186 100644 --- a/pkg/analyzer/lib/src/error/codes.g.dart +++ b/pkg/analyzer/lib/src/error/codes.g.dart @@ -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 " diff --git a/pkg/analyzer/lib/src/error/error_code_values.g.dart b/pkg/analyzer/lib/src/error/error_code_values.g.dart index 8b6ec3d2806..85671e8495f 100644 --- a/pkg/analyzer/lib/src/error/error_code_values.g.dart +++ b/pkg/analyzer/lib/src/error/error_code_values.g.dart @@ -126,6 +126,7 @@ const List 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, diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml index 91f67a9bea2..a6dcdd4a1e5 100644 --- a/pkg/analyzer/messages.yaml +++ b/pkg/analyzer/messages.yaml @@ -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: diff --git a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart index bfa9ba28000..350d53277bb 100644 --- a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart +++ b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart @@ -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; diff --git a/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart b/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart index f0ee1e1889e..389834392ad 100644 --- a/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart +++ b/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart @@ -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 {