mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
[analyzer] Change the const evaluation result of variables to be Constant.
We rely on the result of the `ConstantVisitor` to indicate whether we have an error or a valid constant value. This CL changes `evaluationResult` to be a `Constant` and changes error reporting to occur at a POE for evaluating a constant. Last few chunks of cleaning up the constant evaluator, woo! Change-Id: Icd41a4fcbab0626df36c6a83cd60ecbb59c2dcf0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/324573 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Reviewed-by: Lasse Nielsen <lrn@google.com> Commit-Queue: Kallen Tu <kallentu@google.com>
This commit is contained in:
parent
5f33a9ab80
commit
742ba5c20d
|
@ -6,6 +6,7 @@ import 'dart:convert';
|
|||
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/exception/exception.dart';
|
||||
import 'package:analyzer/src/dart/constant/value.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/generated/source.dart';
|
||||
|
||||
|
@ -67,13 +68,15 @@ mixin TreeWriter {
|
|||
var buffer = StringBuffer();
|
||||
buffer.write(_toString(value.element));
|
||||
var result = value.evaluationResult;
|
||||
if (result == null) {
|
||||
buffer.write(': no result');
|
||||
} else {
|
||||
buffer.write(': value = ');
|
||||
buffer.write(result.value);
|
||||
buffer.write('; errors = ');
|
||||
buffer.write(result.errors);
|
||||
switch (result) {
|
||||
case null:
|
||||
buffer.write(': no result');
|
||||
case DartObjectImpl():
|
||||
buffer.write(': value = ');
|
||||
buffer.write(result);
|
||||
case InvalidConstant():
|
||||
buffer.write('; errors = ');
|
||||
buffer.writeAll(value.constantEvaluationErrors, ', ');
|
||||
}
|
||||
return buffer.toString();
|
||||
} else {
|
||||
|
|
|
@ -130,23 +130,21 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
|
||||
@override
|
||||
void visitConstantPattern(ConstantPattern node) {
|
||||
super.visitConstantPattern(node);
|
||||
|
||||
var expression = node.expression.unParenthesized;
|
||||
if (expression.typeOrThrow is InvalidType) {
|
||||
return;
|
||||
}
|
||||
|
||||
DartObjectImpl? value = _validate(
|
||||
var value = _evaluateAndReportError(
|
||||
expression,
|
||||
CompileTimeErrorCode.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION,
|
||||
);
|
||||
if (value != null) {
|
||||
if (value is DartObjectImpl) {
|
||||
if (_currentLibrary.featureSet.isEnabled(Feature.patterns)) {
|
||||
_constantPatternValues?[node] = value;
|
||||
if (value.hasPrimitiveEquality(_currentLibrary.featureSet)) {
|
||||
final constantType = value.type;
|
||||
final matchedValueType = node.matchedValueType;
|
||||
var constantType = value.type;
|
||||
var matchedValueType = node.matchedValueType;
|
||||
if (matchedValueType != null) {
|
||||
if (!_canBeEqual(constantType, matchedValueType)) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
|
@ -154,10 +152,12 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
node,
|
||||
[matchedValueType, constantType],
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
super.visitConstantPattern(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,8 +210,8 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
|
||||
var element = node.declaredElement as ConstFieldElementImpl;
|
||||
var result = element.evaluationResult;
|
||||
if (result != null) {
|
||||
_reportErrors(result.errors, null);
|
||||
if (result is InvalidConstant) {
|
||||
_reportError(result, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -320,11 +320,11 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
element.accept(this);
|
||||
if (element is MapPatternEntry) {
|
||||
var key = element.key;
|
||||
var keyValue = _validate(
|
||||
var keyValue = _evaluateAndReportError(
|
||||
key,
|
||||
CompileTimeErrorCode.NON_CONSTANT_MAP_PATTERN_KEY,
|
||||
);
|
||||
if (keyValue != null) {
|
||||
if (keyValue is DartObjectImpl) {
|
||||
_mapPatternKeyValues?[key] = keyValue;
|
||||
var existingKey = uniqueKeys[keyValue];
|
||||
if (existingKey != null) {
|
||||
|
@ -357,7 +357,7 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
void visitRelationalPattern(RelationalPattern node) {
|
||||
super.visitRelationalPattern(node);
|
||||
|
||||
_validate(
|
||||
_evaluateAndReportError(
|
||||
node.operand,
|
||||
CompileTimeErrorCode.NON_CONSTANT_RELATIONAL_PATTERN_EXPRESSION,
|
||||
);
|
||||
|
@ -483,11 +483,13 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
assert(!node.isConst);
|
||||
return;
|
||||
}
|
||||
if (node.isConst) {
|
||||
_reportErrors(result.errors,
|
||||
CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE);
|
||||
} else {
|
||||
_reportErrors(result.errors, null);
|
||||
if (result is InvalidConstant) {
|
||||
if (node.isConst) {
|
||||
_reportError(result,
|
||||
CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE);
|
||||
} else {
|
||||
_reportError(result, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -571,104 +573,137 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Report any errors in the given list. Except for special cases, use the
|
||||
/// given error code rather than the one reported in the error.
|
||||
/// Evaluates [expression] and reports any evaluation error.
|
||||
///
|
||||
/// @param errors the errors that need to be reported
|
||||
/// @param errorCode the error code to be used
|
||||
void _reportErrors(List<AnalysisError> errors, ErrorCode? errorCode) {
|
||||
int length = errors.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
AnalysisError data = errors[i];
|
||||
ErrorCode dataErrorCode = data.errorCode;
|
||||
if (identical(dataErrorCode,
|
||||
CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD) ||
|
||||
identical(dataErrorCode,
|
||||
CompileTimeErrorCode.CONST_EVAL_METHOD_INVOCATION) ||
|
||||
identical(dataErrorCode,
|
||||
CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION) ||
|
||||
identical(
|
||||
dataErrorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE) ||
|
||||
identical(dataErrorCode,
|
||||
CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING) ||
|
||||
identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL) ||
|
||||
identical(
|
||||
dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_INT) ||
|
||||
identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_INT) ||
|
||||
identical(dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM) ||
|
||||
identical(
|
||||
dataErrorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_STRING) ||
|
||||
identical(dataErrorCode,
|
||||
CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT) ||
|
||||
identical(dataErrorCode,
|
||||
CompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH) ||
|
||||
identical(dataErrorCode,
|
||||
CompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH) ||
|
||||
identical(dataErrorCode, CompileTimeErrorCode.CONST_TYPE_PARAMETER) ||
|
||||
identical(
|
||||
dataErrorCode, CompileTimeErrorCode.CONST_SPREAD_EXPECTED_MAP) ||
|
||||
identical(dataErrorCode,
|
||||
CompileTimeErrorCode.CONST_SPREAD_EXPECTED_LIST_OR_SET) ||
|
||||
identical(
|
||||
dataErrorCode,
|
||||
CompileTimeErrorCode
|
||||
.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF) ||
|
||||
identical(
|
||||
dataErrorCode, CompileTimeErrorCode.VARIABLE_TYPE_MISMATCH) ||
|
||||
identical(dataErrorCode, CompileTimeErrorCode.NON_BOOL_CONDITION) ||
|
||||
identical(
|
||||
dataErrorCode,
|
||||
CompileTimeErrorCode
|
||||
.NON_CONSTANT_DEFAULT_VALUE_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(
|
||||
dataErrorCode,
|
||||
CompileTimeErrorCode
|
||||
.NON_CONSTANT_MAP_KEY_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(
|
||||
dataErrorCode,
|
||||
CompileTimeErrorCode
|
||||
.NON_CONSTANT_MAP_VALUE_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(dataErrorCode,
|
||||
CompileTimeErrorCode.SET_ELEMENT_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(dataErrorCode,
|
||||
CompileTimeErrorCode.SPREAD_EXPRESSION_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(
|
||||
dataErrorCode,
|
||||
CompileTimeErrorCode
|
||||
.NON_CONSTANT_CASE_EXPRESSION_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(
|
||||
dataErrorCode,
|
||||
CompileTimeErrorCode
|
||||
.INVALID_ANNOTATION_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(
|
||||
dataErrorCode,
|
||||
CompileTimeErrorCode
|
||||
.IF_ELEMENT_CONDITION_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(
|
||||
dataErrorCode,
|
||||
CompileTimeErrorCode
|
||||
.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(
|
||||
dataErrorCode,
|
||||
CompileTimeErrorCode
|
||||
.NON_CONSTANT_LIST_ELEMENT_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(
|
||||
dataErrorCode,
|
||||
CompileTimeErrorCode
|
||||
.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(dataErrorCode,
|
||||
CompileTimeErrorCode.PATTERN_CONSTANT_FROM_DEFERRED_LIBRARY)) {
|
||||
_errorReporter.reportError(data);
|
||||
} else if (errorCode != null) {
|
||||
_errorReporter.reportError(
|
||||
AnalysisError.tmp(
|
||||
source: data.source,
|
||||
offset: data.offset,
|
||||
length: data.length,
|
||||
errorCode: errorCode,
|
||||
),
|
||||
);
|
||||
}
|
||||
/// Returns the compile time constant of [expression], or an [InvalidConstant]
|
||||
/// if an error was found during evaluation. If an [InvalidConstant] was
|
||||
/// found, the error will be reported and [errorCode] will be the default
|
||||
/// error code to be reported.
|
||||
Constant _evaluateAndReportError(Expression expression, ErrorCode errorCode) {
|
||||
var errorListener = RecordingErrorListener();
|
||||
var subErrorReporter = ErrorReporter(
|
||||
errorListener,
|
||||
_errorReporter.source,
|
||||
isNonNullableByDefault: _currentLibrary.isNonNullableByDefault,
|
||||
);
|
||||
var constantVisitor =
|
||||
ConstantVisitor(_evaluationEngine, _currentLibrary, subErrorReporter);
|
||||
var result = constantVisitor.evaluateConstant(expression);
|
||||
if (result is InvalidConstant) {
|
||||
_reportError(result, errorCode);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Reports an error to the [_errorReporter].
|
||||
///
|
||||
/// If the [error] isn't found in the list, use the given [defaultErrorCode]
|
||||
/// instead.
|
||||
void _reportError(InvalidConstant error, ErrorCode? defaultErrorCode) {
|
||||
if (error.avoidReporting) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(kallentu): Create a set of errors so this method is readable. But
|
||||
// also maybe turn this into a deny list instead of an allow list.
|
||||
//
|
||||
// These error codes are more specific than the [defaultErrorCode] so they
|
||||
// will overwrite and replace the default when we report the error.
|
||||
ErrorCode errorCode = error.errorCode;
|
||||
if (identical(
|
||||
errorCode, CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD) ||
|
||||
identical(errorCode, CompileTimeErrorCode.CONST_EVAL_FOR_ELEMENT) ||
|
||||
identical(
|
||||
errorCode, CompileTimeErrorCode.CONST_EVAL_METHOD_INVOCATION) ||
|
||||
identical(errorCode, CompileTimeErrorCode.CONST_EVAL_PROPERTY_ACCESS) ||
|
||||
identical(
|
||||
errorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION) ||
|
||||
identical(errorCode, CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE) ||
|
||||
identical(
|
||||
errorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING) ||
|
||||
identical(errorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL) ||
|
||||
identical(errorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_INT) ||
|
||||
identical(errorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_INT) ||
|
||||
identical(errorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM) ||
|
||||
identical(errorCode, CompileTimeErrorCode.CONST_EVAL_TYPE_STRING) ||
|
||||
identical(
|
||||
errorCode, CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT) ||
|
||||
identical(errorCode,
|
||||
CompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH) ||
|
||||
identical(errorCode,
|
||||
CompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH) ||
|
||||
identical(errorCode, CompileTimeErrorCode.CONST_TYPE_PARAMETER) ||
|
||||
identical(errorCode,
|
||||
CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF) ||
|
||||
identical(errorCode,
|
||||
CompileTimeErrorCode.CONST_SPREAD_EXPECTED_LIST_OR_SET) ||
|
||||
identical(errorCode, CompileTimeErrorCode.CONST_SPREAD_EXPECTED_MAP) ||
|
||||
identical(errorCode, CompileTimeErrorCode.EXPRESSION_IN_MAP) ||
|
||||
identical(errorCode, CompileTimeErrorCode.VARIABLE_TYPE_MISMATCH) ||
|
||||
identical(errorCode, CompileTimeErrorCode.NON_BOOL_CONDITION) ||
|
||||
identical(
|
||||
errorCode,
|
||||
CompileTimeErrorCode
|
||||
.NON_CONSTANT_DEFAULT_VALUE_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(errorCode,
|
||||
CompileTimeErrorCode.NON_CONSTANT_MAP_KEY_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(
|
||||
errorCode,
|
||||
CompileTimeErrorCode
|
||||
.NON_CONSTANT_MAP_VALUE_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(errorCode,
|
||||
CompileTimeErrorCode.SET_ELEMENT_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(errorCode,
|
||||
CompileTimeErrorCode.SPREAD_EXPRESSION_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(
|
||||
errorCode,
|
||||
CompileTimeErrorCode
|
||||
.NON_CONSTANT_CASE_EXPRESSION_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(
|
||||
errorCode,
|
||||
CompileTimeErrorCode
|
||||
.INVALID_ANNOTATION_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(errorCode,
|
||||
CompileTimeErrorCode.IF_ELEMENT_CONDITION_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(
|
||||
errorCode,
|
||||
CompileTimeErrorCode
|
||||
.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(
|
||||
errorCode,
|
||||
CompileTimeErrorCode
|
||||
.NON_CONSTANT_LIST_ELEMENT_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(
|
||||
errorCode,
|
||||
CompileTimeErrorCode
|
||||
.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(errorCode,
|
||||
CompileTimeErrorCode.PATTERN_CONSTANT_FROM_DEFERRED_LIBRARY) ||
|
||||
identical(errorCode,
|
||||
CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_FUNCTION) ||
|
||||
identical(
|
||||
errorCode,
|
||||
CompileTimeErrorCode
|
||||
.WRONG_NUMBER_OF_TYPE_ARGUMENTS_ANONYMOUS_FUNCTION)) {
|
||||
_errorReporter.reportError(
|
||||
AnalysisError.tmp(
|
||||
source: _errorReporter.source,
|
||||
offset: error.offset,
|
||||
length: error.length,
|
||||
errorCode: error.errorCode,
|
||||
arguments: error.arguments,
|
||||
contextMessages: error.contextMessages,
|
||||
),
|
||||
);
|
||||
} else if (defaultErrorCode != null) {
|
||||
_errorReporter.reportError(
|
||||
AnalysisError.tmp(
|
||||
source: _errorReporter.source,
|
||||
offset: error.offset,
|
||||
length: error.length,
|
||||
errorCode: defaultErrorCode,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -701,28 +736,6 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
return _currentLibrary.typeSystem.runtimeTypeMatch(obj, type);
|
||||
}
|
||||
|
||||
/// Validate that the given expression is a compile time constant. Return the
|
||||
/// value of the compile time constant, or `null` if the expression is not a
|
||||
/// compile time constant.
|
||||
///
|
||||
/// @param expression the expression to be validated
|
||||
/// @param errorCode the error code to be used if the expression is not a
|
||||
/// compile time constant
|
||||
/// @return the value of the compile time constant
|
||||
DartObjectImpl? _validate(Expression expression, ErrorCode errorCode) {
|
||||
RecordingErrorListener errorListener = RecordingErrorListener();
|
||||
ErrorReporter subErrorReporter = ErrorReporter(
|
||||
errorListener,
|
||||
_errorReporter.source,
|
||||
isNonNullableByDefault: _currentLibrary.isNonNullableByDefault,
|
||||
);
|
||||
var result = expression.accept(
|
||||
ConstantVisitor(_evaluationEngine, _currentLibrary, subErrorReporter));
|
||||
_reportErrors(errorListener.errors, errorCode);
|
||||
// TODO(kallentu): Evaluate whether we want to change the return type.
|
||||
return result is DartObjectImpl ? result : null;
|
||||
}
|
||||
|
||||
/// Validate that if the passed arguments are constant expressions.
|
||||
///
|
||||
/// @param argumentList the argument list to evaluate
|
||||
|
@ -730,7 +743,7 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
for (Expression argument in argumentList.arguments) {
|
||||
Expression realArgument =
|
||||
argument is NamedExpression ? argument.expression : argument;
|
||||
_validate(
|
||||
_evaluateAndReportError(
|
||||
realArgument, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT);
|
||||
}
|
||||
}
|
||||
|
@ -767,7 +780,7 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
for (FormalParameter parameter in parameters.parameters) {
|
||||
if (parameter is DefaultFormalParameter) {
|
||||
var defaultValue = parameter.defaultValue;
|
||||
DartObjectImpl? result;
|
||||
Constant? result;
|
||||
if (defaultValue == null) {
|
||||
result = DartObjectImpl(
|
||||
_typeSystem,
|
||||
|
@ -777,12 +790,12 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
} else if (defaultValue.typeOrThrow is InvalidType) {
|
||||
// We have already reported an error.
|
||||
} else {
|
||||
result = _validate(
|
||||
result = _evaluateAndReportError(
|
||||
defaultValue, CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE);
|
||||
}
|
||||
VariableElementImpl element =
|
||||
parameter.declaredElement as VariableElementImpl;
|
||||
element.evaluationResult = EvaluationResultImpl(result);
|
||||
element.evaluationResult = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -958,11 +971,11 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
if (switchMember is SwitchCase) {
|
||||
Expression expression = switchMember.expression;
|
||||
|
||||
var expressionValue = _validate(
|
||||
var expressionValue = _evaluateAndReportError(
|
||||
expression,
|
||||
CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION,
|
||||
);
|
||||
if (expressionValue == null) {
|
||||
if (expressionValue is! DartObjectImpl) {
|
||||
continue;
|
||||
}
|
||||
firstValue ??= expressionValue;
|
||||
|
@ -1004,11 +1017,11 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
|
||||
void _validateSwitchStatement_nullSafety(SwitchStatement node) {
|
||||
void validateExpression(Expression expression) {
|
||||
var expressionValue = _validate(
|
||||
var expressionValue = _evaluateAndReportError(
|
||||
expression,
|
||||
CompileTimeErrorCode.NON_CONSTANT_CASE_EXPRESSION,
|
||||
);
|
||||
if (expressionValue == null) {
|
||||
if (expressionValue is! DartObjectImpl) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1074,8 +1087,8 @@ class _ConstLiteralVerifier {
|
|||
|
||||
bool verify(CollectionElement element) {
|
||||
if (element is Expression) {
|
||||
var value = verifier._validate(element, errorCode);
|
||||
if (value == null) return false;
|
||||
var value = verifier._evaluateAndReportError(element, errorCode);
|
||||
if (value is! DartObjectImpl) return false;
|
||||
|
||||
final listElementType = this.listElementType;
|
||||
if (listElementType != null) {
|
||||
|
@ -1093,8 +1106,12 @@ class _ConstLiteralVerifier {
|
|||
CompileTimeErrorCode.CONST_EVAL_FOR_ELEMENT, element);
|
||||
return false;
|
||||
} else if (element is IfElement) {
|
||||
var conditionValue = verifier._validate(element.expression, errorCode);
|
||||
var conditionBool = conditionValue?.toBoolValue();
|
||||
var conditionValue =
|
||||
verifier._evaluateAndReportError(element.expression, errorCode);
|
||||
if (conditionValue is! DartObjectImpl) {
|
||||
return false;
|
||||
}
|
||||
var conditionBool = conditionValue.toBoolValue();
|
||||
|
||||
// The errors have already been reported.
|
||||
if (conditionBool == null) return false;
|
||||
|
@ -1119,8 +1136,9 @@ class _ConstLiteralVerifier {
|
|||
} else if (element is MapLiteralEntry) {
|
||||
return _validateMapLiteralEntry(element);
|
||||
} else if (element is SpreadElement) {
|
||||
var value = verifier._validate(element.expression, errorCode);
|
||||
if (value == null) return false;
|
||||
var value =
|
||||
verifier._evaluateAndReportError(element.expression, errorCode);
|
||||
if (value is! DartObjectImpl) return false;
|
||||
|
||||
if (listElementType != null || setConfig != null) {
|
||||
return _validateListOrSetSpread(element, value);
|
||||
|
@ -1245,16 +1263,16 @@ class _ConstLiteralVerifier {
|
|||
var keyExpression = entry.key;
|
||||
var valueExpression = entry.value;
|
||||
|
||||
var keyValue = verifier._validate(
|
||||
var keyValue = verifier._evaluateAndReportError(
|
||||
keyExpression,
|
||||
CompileTimeErrorCode.NON_CONSTANT_MAP_KEY,
|
||||
);
|
||||
var valueValue = verifier._validate(
|
||||
var valueValue = verifier._evaluateAndReportError(
|
||||
valueExpression,
|
||||
CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE,
|
||||
);
|
||||
|
||||
if (keyValue != null) {
|
||||
if (keyValue is DartObjectImpl) {
|
||||
var keyType = keyValue.type;
|
||||
|
||||
if (!verifier._runtimeTypeMatch(keyValue, config.keyType)) {
|
||||
|
@ -1282,7 +1300,7 @@ class _ConstLiteralVerifier {
|
|||
}
|
||||
}
|
||||
|
||||
if (valueValue != null) {
|
||||
if (valueValue is DartObjectImpl) {
|
||||
if (!verifier._runtimeTypeMatch(valueValue, config.valueType)) {
|
||||
verifier._errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.MAP_VALUE_TYPE_NOT_ASSIGNABLE,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2352,49 +2352,94 @@ class IntState extends NumState {
|
|||
|
||||
/// An invalid constant that contains diagnostic information.
|
||||
class InvalidConstant implements Constant {
|
||||
/// The entity that a constant evaluator error is reported at.
|
||||
final SyntacticEntity entity;
|
||||
/// The length of the entity that the evaluation error is reported at.
|
||||
final int length;
|
||||
|
||||
/// The error code that is reported at the location of the [entity].
|
||||
/// The offset of the entity that the evaluation error is reported at.
|
||||
final int offset;
|
||||
|
||||
/// The error code that is being reported.
|
||||
final ErrorCode errorCode;
|
||||
|
||||
/// The arguments required to complete the message.
|
||||
final List<Object>? arguments;
|
||||
final List<Object> arguments;
|
||||
|
||||
/// Additional context messages for the error, including stack trace
|
||||
/// information if the error occurs within a constructor.
|
||||
final List<DiagnosticMessage> contextMessages;
|
||||
|
||||
/// Return `true` if the error was an exception thrown during constant
|
||||
/// evaluation.
|
||||
/// Whether to omit reporting this error.
|
||||
///
|
||||
/// If set to `true`, error reporting will ignore this invalid constant.
|
||||
/// Defaults to `false`.
|
||||
///
|
||||
/// The `ConstantVisitor` can change this to `true` when there's already an
|
||||
/// error reported and this invalid constant would be an unnecessary follow-on
|
||||
/// error.
|
||||
bool avoidReporting;
|
||||
|
||||
/// Whether this error was an exception thrown during constant evaluation.
|
||||
///
|
||||
/// In [ConstantEvaluationEngine.evaluateAndReportErrorsInConstructorCall],
|
||||
/// we report this with a [CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION]
|
||||
/// and a context message pointing to where the exception was thrown.
|
||||
final bool isRuntimeException;
|
||||
|
||||
/// Return `true` if the constant evaluation encounters an unresolved
|
||||
/// expression.
|
||||
/// Whether the constant evaluation encounters an unresolved expression.
|
||||
final bool isUnresolved;
|
||||
|
||||
InvalidConstant(this.entity, this.errorCode,
|
||||
{this.arguments,
|
||||
List<DiagnosticMessage>? contextMessages,
|
||||
this.isUnresolved = false,
|
||||
this.isRuntimeException = false})
|
||||
: contextMessages = contextMessages ?? [];
|
||||
|
||||
/// Creates a duplicate instance of [other], with a different [entity].
|
||||
factory InvalidConstant.forEntity(
|
||||
factory InvalidConstant.copyWithEntity(
|
||||
InvalidConstant other, SyntacticEntity entity) {
|
||||
return InvalidConstant(entity, other.errorCode,
|
||||
arguments: other.arguments,
|
||||
contextMessages: other.contextMessages,
|
||||
isUnresolved: other.isUnresolved,
|
||||
isRuntimeException: other.isRuntimeException);
|
||||
return InvalidConstant.forEntity(
|
||||
entity,
|
||||
other.errorCode,
|
||||
arguments: other.arguments,
|
||||
contextMessages: other.contextMessages,
|
||||
avoidReporting: other.avoidReporting,
|
||||
isUnresolved: other.isUnresolved,
|
||||
isRuntimeException: other.isRuntimeException,
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns a generic error depending on the [node] provided.
|
||||
/// Creates a constant evaluation error associated with an [element].
|
||||
InvalidConstant.forElement(Element element, ErrorCode errorCode,
|
||||
{List<Object>? arguments,
|
||||
List<DiagnosticMessage>? contextMessages,
|
||||
bool avoidReporting = false,
|
||||
bool isUnresolved = false,
|
||||
bool isRuntimeException = false})
|
||||
: this._(
|
||||
element.nameLength,
|
||||
element.nameOffset,
|
||||
errorCode,
|
||||
arguments: arguments,
|
||||
contextMessages: contextMessages,
|
||||
avoidReporting: avoidReporting,
|
||||
isUnresolved: isUnresolved,
|
||||
isRuntimeException: isRuntimeException,
|
||||
);
|
||||
|
||||
/// Creates a constant evaluation error associated with a token or node
|
||||
/// [entity].
|
||||
InvalidConstant.forEntity(SyntacticEntity entity, ErrorCode errorCode,
|
||||
{List<Object>? arguments,
|
||||
List<DiagnosticMessage>? contextMessages,
|
||||
bool avoidReporting = false,
|
||||
bool isUnresolved = false,
|
||||
bool isRuntimeException = false})
|
||||
: this._(
|
||||
entity.length,
|
||||
entity.offset,
|
||||
errorCode,
|
||||
arguments: arguments,
|
||||
contextMessages: contextMessages,
|
||||
avoidReporting: avoidReporting,
|
||||
isUnresolved: isUnresolved,
|
||||
isRuntimeException: isRuntimeException,
|
||||
);
|
||||
|
||||
/// Creates a generic error depending on the [node] provided.
|
||||
factory InvalidConstant.genericError(AstNode node,
|
||||
{bool isUnresolved = false}) {
|
||||
final parent = node.parent;
|
||||
|
@ -2402,13 +2447,23 @@ class InvalidConstant implements Constant {
|
|||
if (parent is ArgumentList &&
|
||||
parent2 is InstanceCreationExpression &&
|
||||
parent2.isConst) {
|
||||
return InvalidConstant(
|
||||
return InvalidConstant.forEntity(
|
||||
node, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT,
|
||||
isUnresolved: isUnresolved);
|
||||
}
|
||||
return InvalidConstant(node, CompileTimeErrorCode.INVALID_CONSTANT,
|
||||
return InvalidConstant.forEntity(
|
||||
node, CompileTimeErrorCode.INVALID_CONSTANT,
|
||||
isUnresolved: isUnresolved);
|
||||
}
|
||||
|
||||
InvalidConstant._(this.length, this.offset, this.errorCode,
|
||||
{List<Object>? arguments,
|
||||
List<DiagnosticMessage>? contextMessages,
|
||||
this.avoidReporting = false,
|
||||
this.isUnresolved = false,
|
||||
this.isRuntimeException = false})
|
||||
: arguments = arguments ?? [],
|
||||
contextMessages = contextMessages ?? [];
|
||||
}
|
||||
|
||||
/// The state of an object representing a list.
|
||||
|
|
|
@ -25,6 +25,7 @@ import 'package:analyzer/src/dart/ast/ast.dart';
|
|||
import 'package:analyzer/src/dart/ast/token.dart';
|
||||
import 'package:analyzer/src/dart/constant/compute.dart';
|
||||
import 'package:analyzer/src/dart/constant/evaluation.dart';
|
||||
import 'package:analyzer/src/dart/constant/value.dart';
|
||||
import 'package:analyzer/src/dart/element/display_string_builder.dart';
|
||||
import 'package:analyzer/src/dart/element/member.dart';
|
||||
import 'package:analyzer/src/dart/element/name_union.dart';
|
||||
|
@ -1282,11 +1283,11 @@ mixin ConstVariableElement implements ElementImpl, ConstantEvaluationTarget {
|
|||
/// initializers.
|
||||
Expression? constantInitializer;
|
||||
|
||||
EvaluationResultImpl? _evaluationResult;
|
||||
Constant? _evaluationResult;
|
||||
|
||||
EvaluationResultImpl? get evaluationResult => _evaluationResult;
|
||||
Constant? get evaluationResult => _evaluationResult;
|
||||
|
||||
set evaluationResult(EvaluationResultImpl? evaluationResult) {
|
||||
set evaluationResult(Constant? evaluationResult) {
|
||||
_evaluationResult = evaluationResult;
|
||||
}
|
||||
|
||||
|
@ -1315,7 +1316,11 @@ mixin ConstVariableElement implements ElementImpl, ConstantEvaluationTarget {
|
|||
configuration: ConstantEvaluationConfiguration(),
|
||||
);
|
||||
}
|
||||
return evaluationResult?.value;
|
||||
|
||||
if (evaluationResult case DartObjectImpl result) {
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1378,7 +1383,7 @@ class DefaultSuperFormalParameterElementImpl
|
|||
}
|
||||
|
||||
@override
|
||||
EvaluationResultImpl? get evaluationResult {
|
||||
Constant? get evaluationResult {
|
||||
if (constantInitializer != null) {
|
||||
return super.evaluationResult;
|
||||
}
|
||||
|
@ -1663,15 +1668,41 @@ class ElementAnnotationImpl implements ElementAnnotation {
|
|||
/// The result of evaluating this annotation as a compile-time constant
|
||||
/// expression, or `null` if the compilation unit containing the variable has
|
||||
/// not been resolved.
|
||||
EvaluationResultImpl? evaluationResult;
|
||||
Constant? evaluationResult;
|
||||
|
||||
/// Any additional errors, other than [evaluationResult] being an
|
||||
/// [InvalidConstant], that came from evaluating the constant expression,
|
||||
/// or `null` if the compilation unit containing the variable has
|
||||
/// not been resolved.
|
||||
///
|
||||
/// TODO(kallentu): Remove this field once we fix up g3's dependency on
|
||||
/// annotations having a valid result as well as unresolved errors.
|
||||
List<AnalysisError>? additionalErrors;
|
||||
|
||||
/// Initialize a newly created annotation. The given [compilationUnit] is the
|
||||
/// compilation unit in which the annotation appears.
|
||||
ElementAnnotationImpl(this.compilationUnit);
|
||||
|
||||
@override
|
||||
List<AnalysisError> get constantEvaluationErrors =>
|
||||
evaluationResult?.errors ?? const <AnalysisError>[];
|
||||
List<AnalysisError> get constantEvaluationErrors {
|
||||
final evaluationResult = this.evaluationResult;
|
||||
final additionalErrors = this.additionalErrors;
|
||||
if (evaluationResult is InvalidConstant) {
|
||||
// When we have an [InvalidConstant], we don't report the additional
|
||||
// errors because this result contains the most relevant error.
|
||||
return [
|
||||
AnalysisError.tmp(
|
||||
source: source,
|
||||
offset: evaluationResult.offset,
|
||||
length: evaluationResult.length,
|
||||
errorCode: evaluationResult.errorCode,
|
||||
arguments: evaluationResult.arguments,
|
||||
contextMessages: evaluationResult.contextMessages,
|
||||
)
|
||||
];
|
||||
}
|
||||
return additionalErrors ?? const <AnalysisError>[];
|
||||
}
|
||||
|
||||
@override
|
||||
AnalysisContext get context => compilationUnit.library.context;
|
||||
|
@ -1824,7 +1855,11 @@ class ElementAnnotationImpl implements ElementAnnotation {
|
|||
configuration: ConstantEvaluationConfiguration(),
|
||||
);
|
||||
}
|
||||
return evaluationResult?.value;
|
||||
|
||||
if (evaluationResult case DartObjectImpl result) {
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -6876,11 +6911,11 @@ abstract class VariableElementImpl extends ElementImpl
|
|||
/// compile-time constant expression, or `null` if this variable is not a
|
||||
/// 'const' variable, if it does not have an initializer, or if the
|
||||
/// compilation unit containing the variable has not been resolved.
|
||||
EvaluationResultImpl? get evaluationResult => null;
|
||||
Constant? get evaluationResult => null;
|
||||
|
||||
/// Set the result of evaluating this variable's initializer as a compile-time
|
||||
/// constant expression to the given [result].
|
||||
set evaluationResult(EvaluationResultImpl? result) {
|
||||
set evaluationResult(Constant? result) {
|
||||
throw StateError("Invalid attempt to set a compile-time constant result");
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ import 'package:analyzer/dart/element/type.dart';
|
|||
import 'package:analyzer/error/error.dart';
|
||||
import 'package:analyzer/error/listener.dart';
|
||||
import 'package:analyzer/source/source_range.dart';
|
||||
import 'package:analyzer/src/dart/constant/evaluation.dart';
|
||||
import 'package:analyzer/src/dart/constant/value.dart';
|
||||
import 'package:analyzer/src/dart/element/type_system.dart';
|
||||
import 'package:analyzer/src/dart/resolver/exit_detector.dart';
|
||||
|
@ -160,9 +159,9 @@ class LegacyDeadCodeVerifier extends RecursiveAstVisitor<void> {
|
|||
if (isAmpAmp || isBarBar) {
|
||||
Expression lhsCondition = node.leftOperand;
|
||||
if (!_isDebugConstant(lhsCondition)) {
|
||||
var lhsResult = _getConstantBooleanValue(lhsCondition);
|
||||
var lhsResult = _constantBooleanValue(lhsCondition);
|
||||
if (lhsResult != null) {
|
||||
var value = lhsResult.value?.toBoolValue();
|
||||
var value = lhsResult.toBoolValue();
|
||||
// Report error on "else" block: true || !e!
|
||||
// or on "if" block: false && !e!
|
||||
if (value == true && isBarBar || value == false && isAmpAmp) {
|
||||
|
@ -213,9 +212,9 @@ class LegacyDeadCodeVerifier extends RecursiveAstVisitor<void> {
|
|||
Expression conditionExpression = node.condition;
|
||||
conditionExpression.accept(this);
|
||||
if (!_isDebugConstant(conditionExpression)) {
|
||||
var result = _getConstantBooleanValue(conditionExpression);
|
||||
var result = _constantBooleanValue(conditionExpression);
|
||||
if (result != null) {
|
||||
if (result.value?.toBoolValue() == true) {
|
||||
if (result.toBoolValue() == true) {
|
||||
// Report error on "else" block: true ? 1 : !2!
|
||||
_errorReporter.reportErrorForNode(
|
||||
WarningCode.DEAD_CODE, node.elseExpression);
|
||||
|
@ -238,9 +237,9 @@ class LegacyDeadCodeVerifier extends RecursiveAstVisitor<void> {
|
|||
Expression conditionExpression = node.expression;
|
||||
conditionExpression.accept(this);
|
||||
if (!_isDebugConstant(conditionExpression)) {
|
||||
var result = _getConstantBooleanValue(conditionExpression);
|
||||
var result = _constantBooleanValue(conditionExpression);
|
||||
if (result != null) {
|
||||
if (result.value?.toBoolValue() == true) {
|
||||
if (result.toBoolValue() == true) {
|
||||
// Report error on else block: if(true) {} else {!}
|
||||
var elseElement = node.elseElement;
|
||||
if (elseElement != null) {
|
||||
|
@ -266,9 +265,9 @@ class LegacyDeadCodeVerifier extends RecursiveAstVisitor<void> {
|
|||
Expression conditionExpression = node.expression;
|
||||
conditionExpression.accept(this);
|
||||
if (!_isDebugConstant(conditionExpression)) {
|
||||
var result = _getConstantBooleanValue(conditionExpression);
|
||||
var result = _constantBooleanValue(conditionExpression);
|
||||
if (result != null) {
|
||||
if (result.value?.toBoolValue() == true) {
|
||||
if (result.toBoolValue() == true) {
|
||||
// Report error on else block: if(true) {} else {!}
|
||||
var elseStatement = node.elseStatement;
|
||||
if (elseStatement != null) {
|
||||
|
@ -334,9 +333,9 @@ class LegacyDeadCodeVerifier extends RecursiveAstVisitor<void> {
|
|||
Expression conditionExpression = node.condition;
|
||||
conditionExpression.accept(this);
|
||||
if (!_isDebugConstant(conditionExpression)) {
|
||||
var result = _getConstantBooleanValue(conditionExpression);
|
||||
var result = _constantBooleanValue(conditionExpression);
|
||||
if (result != null) {
|
||||
if (result.value?.toBoolValue() == false) {
|
||||
if (result.toBoolValue() == false) {
|
||||
// Report error on while block: while (false) {!}
|
||||
_errorReporter.reportErrorForNode(WarningCode.DEAD_CODE, node.body);
|
||||
return;
|
||||
|
@ -387,17 +386,15 @@ class LegacyDeadCodeVerifier extends RecursiveAstVisitor<void> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Given some [expression], return [ValidResult.RESULT_TRUE] if it is `true`,
|
||||
/// [ValidResult.RESULT_FALSE] if it is `false`, or `null` if the expression
|
||||
/// is not a constant boolean value.
|
||||
EvaluationResultImpl? _getConstantBooleanValue(Expression expression) {
|
||||
/// A boolean [DartObjectImpl] from evaluating [expression].
|
||||
///
|
||||
/// Is `null` if [expression] does not evaluate to a boolean value.
|
||||
DartObjectImpl? _constantBooleanValue(Expression expression) {
|
||||
if (expression is BooleanLiteral) {
|
||||
return EvaluationResultImpl(
|
||||
DartObjectImpl(
|
||||
_typeSystem,
|
||||
_typeSystem.typeProvider.boolType,
|
||||
BoolState.from(expression.value),
|
||||
),
|
||||
return DartObjectImpl(
|
||||
_typeSystem,
|
||||
_typeSystem.typeProvider.boolType,
|
||||
BoolState.from(expression.value),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -9171,7 +9171,7 @@ CompileTimeErrorCode:
|
|||
entry even though it's a set literal:
|
||||
|
||||
```dart
|
||||
const collection = <String>{[!'a' : 'b'!]};
|
||||
var collection = <String>{[!'a' : 'b'!]};
|
||||
```
|
||||
|
||||
#### Common fixes
|
||||
|
@ -9181,7 +9181,7 @@ CompileTimeErrorCode:
|
|||
another type argument:
|
||||
|
||||
```dart
|
||||
const collection = <String, String>{'a' : 'b'};
|
||||
var collection = <String, String>{'a' : 'b'};
|
||||
```
|
||||
|
||||
In other cases, you might need to change the explicit type from `Set` to
|
||||
|
@ -9192,7 +9192,7 @@ CompileTimeErrorCode:
|
|||
included in the set:
|
||||
|
||||
```dart
|
||||
const collection = <String>{'a', 'b'};
|
||||
var collection = <String>{'a', 'b'};
|
||||
```
|
||||
MAP_KEY_TYPE_NOT_ASSIGNABLE:
|
||||
problemMessage: "The element type '{0}' can't be assigned to the map key type '{1}'."
|
||||
|
|
|
@ -15,7 +15,7 @@ import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
|
|||
import 'package:analyzer/src/dart/analysis/performance_logger.dart';
|
||||
import 'package:analyzer/src/dart/analysis/status.dart';
|
||||
import 'package:analyzer/src/dart/ast/extensions.dart';
|
||||
import 'package:analyzer/src/dart/constant/evaluation.dart';
|
||||
import 'package:analyzer/src/dart/constant/value.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/sdk/sdk.dart';
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
|
@ -1351,9 +1351,8 @@ class C {}
|
|||
var result = await driver.getResultValid(testFile);
|
||||
var atD = AstFinder.getClass(result.unit, 'C').metadata[0];
|
||||
var atDI = atD.elementAnnotation as ElementAnnotationImpl;
|
||||
var value = atDI.evaluationResult!.value;
|
||||
// That is illegal.
|
||||
expect(value, isNull);
|
||||
expect(atDI.evaluationResult, isNull);
|
||||
}
|
||||
|
||||
test_const_annotation_withArgs() async {
|
||||
|
@ -1368,12 +1367,11 @@ class D {
|
|||
var result = await driver.getResultValid(testFile);
|
||||
var atD = AstFinder.getClass(result.unit, 'C').metadata[0];
|
||||
var atDI = atD.elementAnnotation as ElementAnnotationImpl;
|
||||
var value = atDI.evaluationResult!.value!;
|
||||
var value = atDI.evaluationResult as DartObjectImpl;
|
||||
expect(value.type, isNotNull);
|
||||
assertType(value.type, 'D');
|
||||
expect(value.fields!.keys, ['value']);
|
||||
expect(value.getField('value')!.toIntValue(), 1);
|
||||
expect(atDI.evaluationResult!.errors, isEmpty);
|
||||
}
|
||||
|
||||
test_const_annotation_withoutArgs() async {
|
||||
|
@ -3736,11 +3734,11 @@ var v = 0
|
|||
assertType(variable.declaredElement!.type, expected);
|
||||
}
|
||||
|
||||
void _expectCircularityError(EvaluationResultImpl evaluationResult) {
|
||||
expect(evaluationResult, isNotNull);
|
||||
expect(evaluationResult.value, isNull);
|
||||
expect(evaluationResult.errors, hasLength(1));
|
||||
expect(evaluationResult.errors[0].errorCode,
|
||||
void _expectCircularityError(Constant evaluationResult) {
|
||||
if (evaluationResult is! InvalidConstant) {
|
||||
fail('No error found when we expected a circularity error.');
|
||||
}
|
||||
expect(evaluationResult.errorCode,
|
||||
CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT);
|
||||
}
|
||||
|
||||
|
|
|
@ -1504,7 +1504,6 @@ class C<U> {
|
|||
error(WarningCode.UNUSED_LOCAL_VARIABLE, 55, 1),
|
||||
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
|
||||
61, 1),
|
||||
error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 61, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -1791,6 +1790,8 @@ const x = C<int>.();
|
|||
// reported.
|
||||
error(CompileTimeErrorCode.CLASS_INSTANTIATION_ACCESS_TO_UNKNOWN_MEMBER,
|
||||
45, 8),
|
||||
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 45,
|
||||
8),
|
||||
error(ParserErrorCode.MISSING_IDENTIFIER, 52, 1),
|
||||
]);
|
||||
}
|
||||
|
@ -2428,6 +2429,15 @@ const res = {...?i};
|
|||
]);
|
||||
}
|
||||
|
||||
test_visitSetOrMapLiteral_ambiguous_expression() async {
|
||||
await assertErrorsInCode(r'''
|
||||
const m = {1: 1};
|
||||
const res = {...m, 2};
|
||||
''', [
|
||||
error(CompileTimeErrorCode.AMBIGUOUS_SET_OR_MAP_LITERAL_BOTH, 30, 9),
|
||||
]);
|
||||
}
|
||||
|
||||
test_visitSetOrMapLiteral_ambiguous_inList() async {
|
||||
await assertErrorsInCode(r'''
|
||||
const l = [];
|
||||
|
@ -3191,8 +3201,6 @@ const c = true && a;
|
|||
''', [
|
||||
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 27,
|
||||
9),
|
||||
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 35,
|
||||
1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -3361,8 +3369,6 @@ const c = false || a;
|
|||
''', [
|
||||
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 27,
|
||||
10),
|
||||
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 36,
|
||||
1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -3946,8 +3952,6 @@ const y = B(x);
|
|||
),
|
||||
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),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -4104,10 +4108,14 @@ class ConstantVisitorTestSupport extends PubPackageResolutionTest {
|
|||
|
||||
DartObjectImpl? _evaluationResult(ConstVariableElement element) {
|
||||
final evaluationResult = element.evaluationResult;
|
||||
if (evaluationResult == null) {
|
||||
fail('Not evaluated: ${element.name}');
|
||||
switch (evaluationResult) {
|
||||
case null:
|
||||
fail('Not evaluated: ${element.name}');
|
||||
case InvalidConstant():
|
||||
return null;
|
||||
case DartObjectImpl():
|
||||
return evaluationResult;
|
||||
}
|
||||
return evaluationResult.value;
|
||||
}
|
||||
|
||||
DartObjectImpl? _field(String variableName) {
|
||||
|
|
|
@ -397,7 +397,7 @@ class B extends A {
|
|||
assertErrorsInResolvedUnit(result, []);
|
||||
|
||||
var bElement = FindElement(result.unit).field('b') as ConstVariableElement;
|
||||
var bValue = bElement.evaluationResult!.value!;
|
||||
var bValue = bElement.evaluationResult as DartObjectImpl;
|
||||
var superFields = bValue.getField(GenericState.SUPERCLASS_FIELD);
|
||||
expect(superFields!.getField('f1')!.toBoolValue(), false);
|
||||
}
|
||||
|
|
|
@ -38,8 +38,6 @@ const a = const A();
|
|||
"The error is in the field initializer of 'A', and occurs here."),
|
||||
],
|
||||
),
|
||||
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 29,
|
||||
9),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -65,4 +63,17 @@ class RequiresNonEmptyList {
|
|||
),
|
||||
]);
|
||||
}
|
||||
|
||||
test_nonStaticField_inGenericClass() async {
|
||||
await assertErrorsInCode('''
|
||||
class C<T> {
|
||||
const C();
|
||||
T? get t => null;
|
||||
}
|
||||
|
||||
const x = const C().t;
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONST_EVAL_PROPERTY_ACCESS, 59, 11),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,8 +37,6 @@ const y = B(x);
|
|||
),
|
||||
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),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,20 +84,6 @@ const x = const A();
|
|||
''');
|
||||
}
|
||||
|
||||
test_nonStaticField_inGenericClass() async {
|
||||
await assertErrorsInCode('''
|
||||
class C<T> {
|
||||
const C();
|
||||
T? get t => null;
|
||||
}
|
||||
|
||||
const x = const C().t;
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 59,
|
||||
11),
|
||||
]);
|
||||
}
|
||||
|
||||
test_propertyExtraction_targetNotConst() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {
|
||||
|
|
|
@ -204,7 +204,6 @@ class A<U> {
|
|||
''', [
|
||||
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
|
||||
65, 1),
|
||||
error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 65, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -220,7 +219,6 @@ class A<U> {
|
|||
error(HintCode.UNUSED_LOCAL_VARIABLE, 54, 1),
|
||||
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
|
||||
60, 1),
|
||||
error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 60, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -239,7 +237,6 @@ class A<U> {
|
|||
5),
|
||||
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
|
||||
58, 1),
|
||||
error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 58, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -290,7 +290,6 @@ void f(x) {
|
|||
''', [
|
||||
error(CompileTimeErrorCode.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION,
|
||||
47, 1),
|
||||
error(CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT, 47, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -397,7 +396,6 @@ void f(x) {
|
|||
''', [
|
||||
error(CompileTimeErrorCode.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION,
|
||||
47, 1),
|
||||
error(CompileTimeErrorCode.NON_CONSTANT_MAP_KEY, 47, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -442,7 +440,6 @@ void f(x) {
|
|||
''', [
|
||||
error(CompileTimeErrorCode.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION,
|
||||
50, 1),
|
||||
error(CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE, 50, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -11586,7 +11586,7 @@ The following code produces this diagnostic because the literal has a map
|
|||
entry even though it's a set literal:
|
||||
|
||||
{% prettify dart tag=pre+code %}
|
||||
const collection = <String>{[!'a' : 'b'!]};
|
||||
var collection = <String>{[!'a' : 'b'!]};
|
||||
{% endprettify %}
|
||||
|
||||
#### Common fixes
|
||||
|
@ -11596,7 +11596,7 @@ that it is a map. In the previous example, you could do this by adding
|
|||
another type argument:
|
||||
|
||||
{% prettify dart tag=pre+code %}
|
||||
const collection = <String, String>{'a' : 'b'};
|
||||
var collection = <String, String>{'a' : 'b'};
|
||||
{% endprettify %}
|
||||
|
||||
In other cases, you might need to change the explicit type from `Set` to
|
||||
|
@ -11607,7 +11607,7 @@ possibly by replacing the colon with a comma if both values should be
|
|||
included in the set:
|
||||
|
||||
{% prettify dart tag=pre+code %}
|
||||
const collection = <String>{'a', 'b'};
|
||||
var collection = <String>{'a', 'b'};
|
||||
{% endprettify %}
|
||||
|
||||
### map_key_type_not_assignable
|
||||
|
|
|
@ -35,7 +35,7 @@ int fn2() {
|
|||
|
||||
const var3 = const A(1).x;
|
||||
// ^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_EVAL_PROPERTY_ACCESS
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_GETTER
|
||||
// [cfe] The getter 'x' isn't defined for the class 'A'.
|
||||
|
|
|
@ -29,7 +29,7 @@ int fn2() {
|
|||
|
||||
const var3 = const A(1).y;
|
||||
// ^^^^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_EVAL_PROPERTY_ACCESS
|
||||
|
||||
class B extends A {
|
||||
const B(int x) : super(x);
|
||||
|
|
|
@ -9,6 +9,8 @@ class A {
|
|||
//^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER
|
||||
static const field = const B();
|
||||
// ^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CREATION_WITH_NON_TYPE
|
||||
// [cfe] Can't access 'this' in a field initializer to read 'B'.
|
||||
|
|
|
@ -14,7 +14,6 @@ class StringInterpolation1NegativeTest {
|
|||
static const DOLLAR = const A("$");
|
||||
// ^
|
||||
// [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
// [analyzer] COMPILE_TIME_ERROR.INVALID_CONSTANT
|
||||
// [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
|
||||
static testMain() {
|
||||
|
|
|
@ -11,6 +11,8 @@ class A {
|
|||
//^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER
|
||||
static const field = const B();
|
||||
// ^^^^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CREATION_WITH_NON_TYPE
|
||||
// [cfe] Can't access 'this' in a field initializer to read 'B'.
|
||||
|
|
|
@ -14,11 +14,9 @@ class A {
|
|||
class StringInterpolation1NegativeTest {
|
||||
// Dollar not followed by "{" or identifier.
|
||||
static const DOLLAR = const A("$");
|
||||
// [error line 16, column 35, length 0]
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
// [analyzer] COMPILE_TIME_ERROR.INVALID_CONSTANT
|
||||
// ^
|
||||
// [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
|
||||
// [analyzer] COMPILE_TIME_ERROR.INVALID_CONSTANT
|
||||
// [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
|
||||
static testMain() {
|
||||
print(DOLLAR);
|
||||
|
|
Loading…
Reference in a new issue