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 {