mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 10:48:25 +00:00
[analyzer] Report more specific diagnostic codes instead of INVALID_CONSTANT.
Add a more specific, but for general use, diagnostic for when the evaluator encounters a type parameter. The errors should match more closely to the CFE errors now. This CL also tidies up some other areas like `_evaluatePropertyAccess` and produces a better error than `INVALID_CONSTANT` when you try to access something that's not String.length. Change-Id: I4780e6e52049887a0ee44cdf046968f332527079 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/322364 Commit-Queue: Kallen Tu <kallentu@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
2ee7f1ff0c
commit
af24f1d61a
|
@ -445,6 +445,8 @@ CompileTimeErrorCode.CONST_SPREAD_EXPECTED_LIST_OR_SET:
|
|||
status: noFix
|
||||
CompileTimeErrorCode.CONST_SPREAD_EXPECTED_MAP:
|
||||
status: noFix
|
||||
CompileTimeErrorCode.CONST_TYPE_PARAMETER:
|
||||
status: needsEvaluation
|
||||
CompileTimeErrorCode.CONST_WITH_NON_CONST:
|
||||
status: hasFix
|
||||
CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT:
|
||||
|
|
|
@ -535,6 +535,7 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
// Should not be a type parameter.
|
||||
if (type.element is TypeParameterElement) {
|
||||
_errorReporter.reportErrorForNode(errorCode, type);
|
||||
return;
|
||||
}
|
||||
// Check type arguments.
|
||||
var typeArguments = type.typeArguments;
|
||||
|
@ -603,6 +604,11 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
|
|||
CompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH) ||
|
||||
identical(dataErrorCode,
|
||||
CompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH) ||
|
||||
identical(dataErrorCode, CompileTimeErrorCode.CONST_TYPE_PARAMETER) ||
|
||||
identical(
|
||||
dataErrorCode,
|
||||
CompileTimeErrorCode
|
||||
.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF) ||
|
||||
identical(
|
||||
dataErrorCode, CompileTimeErrorCode.VARIABLE_TYPE_MISMATCH) ||
|
||||
identical(dataErrorCode, CompileTimeErrorCode.NON_BOOL_CONDITION) ||
|
||||
|
|
|
@ -836,7 +836,7 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
|
||||
@override
|
||||
Constant visitFunctionReference(FunctionReference node) {
|
||||
var functionResult = _getConstant(node.function);
|
||||
final functionResult = _getConstant(node.function);
|
||||
if (functionResult is! DartObjectImpl) {
|
||||
return functionResult;
|
||||
}
|
||||
|
@ -846,9 +846,9 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
// any type parameters contained therein are reported as non-constant in
|
||||
// [ConstantVerifier].
|
||||
if (node.typeArguments == null) {
|
||||
var typeArgumentTypes = node.typeArgumentTypes;
|
||||
final typeArgumentTypes = node.typeArgumentTypes;
|
||||
if (typeArgumentTypes != null) {
|
||||
var instantiatedTypeArgumentTypes = typeArgumentTypes.map((type) {
|
||||
final instantiatedTypeArgumentTypes = typeArgumentTypes.map((type) {
|
||||
if (type is TypeParameterType) {
|
||||
return _lexicalTypeEnvironment?[type.element] ?? type;
|
||||
} else {
|
||||
|
@ -866,18 +866,30 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
}
|
||||
}
|
||||
|
||||
var typeArgumentList = node.typeArguments;
|
||||
final typeArgumentList = node.typeArguments;
|
||||
if (typeArgumentList == null) {
|
||||
return _instantiateFunctionType(node, functionResult);
|
||||
}
|
||||
|
||||
var typeArguments = <DartType>[];
|
||||
final typeArguments = <DartType>[];
|
||||
for (var typeArgument in typeArgumentList.arguments) {
|
||||
var object = _getConstant(typeArgument);
|
||||
if (object is! DartObjectImpl) {
|
||||
return object;
|
||||
}
|
||||
var typeArgumentType = object.toTypeValue();
|
||||
final typeArgumentConstant = _getConstant(typeArgument);
|
||||
switch (typeArgumentConstant) {
|
||||
case InvalidConstant(
|
||||
errorCode: CompileTimeErrorCode.CONST_TYPE_PARAMETER
|
||||
):
|
||||
// If there's a type parameter error in the evaluated constant, we
|
||||
// convert the message to a more specific function reference error.
|
||||
// TODO(kallentu): Don't report error here.
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
|
||||
typeArgument);
|
||||
return InvalidConstant(typeArgument,
|
||||
CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF);
|
||||
case InvalidConstant():
|
||||
return typeArgumentConstant;
|
||||
case DartObjectImpl():
|
||||
final typeArgumentType = typeArgumentConstant.toTypeValue();
|
||||
if (typeArgumentType == null) {
|
||||
return InvalidConstant(
|
||||
typeArgument, CompileTimeErrorCode.INVALID_CONSTANT);
|
||||
|
@ -887,6 +899,7 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
// canonicalization rules.
|
||||
typeArguments.add(typeArgumentType);
|
||||
}
|
||||
}
|
||||
return _dartObjectComputer.typeInstantiate(
|
||||
functionResult, typeArguments, node.function);
|
||||
}
|
||||
|
@ -954,7 +967,8 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
|
||||
if (!result.isBoolNumStringOrNull) {
|
||||
// TODO(kallentu): Don't report error here.
|
||||
_error(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING, node);
|
||||
return InvalidConstant(
|
||||
node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
|
||||
}
|
||||
|
@ -1070,11 +1084,10 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
|
||||
if ((!_isNonNullableByDefault || node.isTypeLiteralInConstantPattern) &&
|
||||
hasTypeParameterReference(type)) {
|
||||
// TODO(kallentu): Don't report error here and report a more specific
|
||||
// diagnostic
|
||||
// TODO(kallentu): Don't report error here
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.INVALID_CONSTANT, node);
|
||||
return InvalidConstant(node, CompileTimeErrorCode.INVALID_CONSTANT);
|
||||
CompileTimeErrorCode.CONST_TYPE_PARAMETER, node);
|
||||
return InvalidConstant(node, CompileTimeErrorCode.CONST_TYPE_PARAMETER);
|
||||
} else if (node.isDeferred) {
|
||||
return _getDeferredLibraryError(node, node.name2) ??
|
||||
InvalidConstant(node, CompileTimeErrorCode.INVALID_CONSTANT);
|
||||
|
@ -1129,10 +1142,10 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
|
||||
// String.length
|
||||
if (prefixElement is! InterfaceElement) {
|
||||
final stringLengthResult =
|
||||
_evaluateStringLength(prefixResult, node.identifier, node);
|
||||
if (stringLengthResult != null) {
|
||||
return stringLengthResult;
|
||||
final propertyAccessResult =
|
||||
_evaluatePropertyAccess(prefixResult, node.identifier, node);
|
||||
if (propertyAccessResult != null) {
|
||||
return propertyAccessResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1182,10 +1195,10 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
return prefixResult;
|
||||
}
|
||||
|
||||
final stringLengthResult =
|
||||
_evaluateStringLength(prefixResult, node.propertyName, node);
|
||||
if (stringLengthResult != null) {
|
||||
return stringLengthResult;
|
||||
final propertyAccessResult =
|
||||
_evaluatePropertyAccess(prefixResult, node.propertyName, node);
|
||||
if (propertyAccessResult != null) {
|
||||
return propertyAccessResult;
|
||||
}
|
||||
}
|
||||
return _getConstantValue(
|
||||
|
@ -1380,7 +1393,8 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
return null;
|
||||
}
|
||||
case MapLiteralEntry():
|
||||
return InvalidConstant(element, CompileTimeErrorCode.INVALID_CONSTANT);
|
||||
return InvalidConstant(
|
||||
element, CompileTimeErrorCode.MAP_ENTRY_NOT_IN_MAP);
|
||||
case SpreadElement():
|
||||
var spread = _getConstant(element.expression);
|
||||
switch (spread) {
|
||||
|
@ -1405,7 +1419,7 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
Map<DartObjectImpl, DartObjectImpl> map, CollectionElement element) {
|
||||
switch (element) {
|
||||
case Expression():
|
||||
return InvalidConstant(element, CompileTimeErrorCode.INVALID_CONSTANT);
|
||||
return InvalidConstant(element, CompileTimeErrorCode.EXPRESSION_IN_MAP);
|
||||
case ForElement():
|
||||
// TODO(kallentu): Don't report error here.
|
||||
_errorReporter.reportErrorForNode(
|
||||
|
@ -1508,7 +1522,8 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
return null;
|
||||
}
|
||||
case MapLiteralEntry():
|
||||
return InvalidConstant(element, CompileTimeErrorCode.INVALID_CONSTANT);
|
||||
return InvalidConstant(
|
||||
element, CompileTimeErrorCode.MAP_ENTRY_NOT_IN_MAP);
|
||||
case SpreadElement():
|
||||
var spread = _getConstant(element.expression);
|
||||
switch (spread) {
|
||||
|
@ -1578,12 +1593,12 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
_errorReporter.reportErrorForNode(code, node);
|
||||
}
|
||||
|
||||
/// Attempt to evaluate a constant that reads the length of a `String`.
|
||||
/// Attempt to evaluate a constant property access.
|
||||
///
|
||||
/// Return a valid [DartObjectImpl] if the given [targetResult] represents a
|
||||
/// `String` and the [identifier] is `length`, an [InvalidConstant] if there's
|
||||
/// an error, and `null` otherwise.
|
||||
Constant? _evaluateStringLength(DartObjectImpl targetResult,
|
||||
Constant? _evaluatePropertyAccess(DartObjectImpl targetResult,
|
||||
SimpleIdentifier identifier, AstNode errorNode) {
|
||||
if (identifier.staticElement?.enclosingElement is ExtensionElement) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
|
@ -1592,25 +1607,35 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
errorNode, CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD);
|
||||
}
|
||||
|
||||
if (identifier.name == 'length') {
|
||||
final targetType = targetResult.type;
|
||||
if (!(targetType is InterfaceType && targetType.isDartCoreString)) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.CONST_EVAL_PROPERTY_ACCESS,
|
||||
errorNode,
|
||||
[identifier.name, targetType]);
|
||||
return InvalidConstant(
|
||||
errorNode, CompileTimeErrorCode.CONST_EVAL_PROPERTY_ACCESS,
|
||||
arguments: [identifier.name, targetType]);
|
||||
}
|
||||
|
||||
// Evaluate a constant that reads the length of a `String`.
|
||||
if (identifier.name == 'length' &&
|
||||
targetType is InterfaceType &&
|
||||
targetType.isDartCoreString) {
|
||||
return _dartObjectComputer.stringLength(errorNode, targetResult);
|
||||
}
|
||||
|
||||
// TODO(kallentu): Make a more specific error here if we aren't accessing
|
||||
// the '.length' property.
|
||||
final element = identifier.staticElement;
|
||||
if (element != null && element is ExecutableElement && element.isStatic) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// No other property access is allowed except for `.length` of a `String`.
|
||||
// TODO(kallentu): Don't report error here.
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.CONST_EVAL_PROPERTY_ACCESS, errorNode, [
|
||||
identifier.name,
|
||||
targetType.getDisplayString(withNullability: _isNonNullableByDefault)
|
||||
]);
|
||||
return InvalidConstant(
|
||||
errorNode, CompileTimeErrorCode.CONST_EVAL_PROPERTY_ACCESS,
|
||||
arguments: [
|
||||
identifier.name,
|
||||
targetType.getDisplayString(withNullability: _isNonNullableByDefault)
|
||||
]);
|
||||
}
|
||||
|
||||
/// Return a [Constant], evaluated by the [ConstantVisitor].
|
||||
///
|
||||
/// The [ConstantVisitor] shouldn't return any `null` values even though
|
||||
|
@ -1650,8 +1675,10 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
(expression.tearOffTypeArgumentTypes?.any(hasTypeParameterReference) ??
|
||||
false)) {
|
||||
// TODO(kallentu): Don't report error here.
|
||||
_error(expression, null);
|
||||
return InvalidConstant.genericError(expression);
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.CONST_TYPE_PARAMETER, expression);
|
||||
return InvalidConstant(
|
||||
expression, CompileTimeErrorCode.CONST_TYPE_PARAMETER);
|
||||
}
|
||||
|
||||
if (variableElement is VariableElementImpl) {
|
||||
|
@ -1748,7 +1775,7 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
// Constants may refer to type parameters only if the constructor-tearoffs
|
||||
// feature is enabled.
|
||||
if (_library.featureSet.isEnabled(Feature.constructor_tearoffs)) {
|
||||
var typeArgument = _lexicalTypeEnvironment?[variableElement];
|
||||
final typeArgument = _lexicalTypeEnvironment?[variableElement];
|
||||
if (typeArgument != null) {
|
||||
return DartObjectImpl(
|
||||
typeSystem,
|
||||
|
@ -1756,6 +1783,10 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
|
|||
TypeState(typeArgument),
|
||||
);
|
||||
}
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.CONST_TYPE_PARAMETER, errorNode2);
|
||||
return InvalidConstant(
|
||||
errorNode2, CompileTimeErrorCode.CONST_TYPE_PARAMETER);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1027,6 +1027,14 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
|
|||
hasPublishedDocs: true,
|
||||
);
|
||||
|
||||
/// No parameters.
|
||||
static const CompileTimeErrorCode CONST_TYPE_PARAMETER = CompileTimeErrorCode(
|
||||
'CONST_TYPE_PARAMETER',
|
||||
"Type parameters can't be used in a constant expression.",
|
||||
correctionMessage:
|
||||
"Try replacing the type parameter with a different type.",
|
||||
);
|
||||
|
||||
/// No parameters.
|
||||
static const CompileTimeErrorCode CONST_WITH_NON_CONST = CompileTimeErrorCode(
|
||||
'CONST_WITH_NON_CONST',
|
||||
|
|
|
@ -138,6 +138,7 @@ const List<ErrorCode> errorCodeValues = [
|
|||
CompileTimeErrorCode.CONST_SET_ELEMENT_NOT_PRIMITIVE_EQUALITY,
|
||||
CompileTimeErrorCode.CONST_SPREAD_EXPECTED_LIST_OR_SET,
|
||||
CompileTimeErrorCode.CONST_SPREAD_EXPECTED_MAP,
|
||||
CompileTimeErrorCode.CONST_TYPE_PARAMETER,
|
||||
CompileTimeErrorCode.CONST_WITH_NON_CONST,
|
||||
CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT,
|
||||
CompileTimeErrorCode.CONST_WITH_NON_TYPE,
|
||||
|
|
|
@ -986,6 +986,7 @@ class _ConstantAnalysisErrorListener extends AnalysisErrorListener {
|
|||
case CompileTimeErrorCode.CONST_EVAL_FOR_ELEMENT:
|
||||
case CompileTimeErrorCode.CONST_MAP_KEY_NOT_PRIMITIVE_EQUALITY:
|
||||
case CompileTimeErrorCode.CONST_SET_ELEMENT_NOT_PRIMITIVE_EQUALITY:
|
||||
case CompileTimeErrorCode.CONST_TYPE_PARAMETER:
|
||||
case CompileTimeErrorCode.CONST_WITH_NON_CONST:
|
||||
case CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT:
|
||||
case CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS:
|
||||
|
|
|
@ -3034,6 +3034,10 @@ CompileTimeErrorCode:
|
|||
const Map<String, int> map1 = {};
|
||||
const Map<String, int> map2 = {...map1};
|
||||
```
|
||||
CONST_TYPE_PARAMETER:
|
||||
problemMessage: "Type parameters can't be used in a constant expression."
|
||||
correctionMessage: Try replacing the type parameter with a different type.
|
||||
comment: No parameters.
|
||||
CONST_WITH_NON_CONST:
|
||||
problemMessage: "The constructor being called isn't a const constructor."
|
||||
correctionMessage: "Try removing 'const' from the constructor invocation."
|
||||
|
|
|
@ -542,6 +542,22 @@ void f(Object? x) {
|
|||
''');
|
||||
}
|
||||
|
||||
test_typeParameter() async {
|
||||
await assertErrorsInCode('''
|
||||
class A<X> {
|
||||
const A();
|
||||
void m() {
|
||||
const x = X;
|
||||
}
|
||||
}
|
||||
''', [
|
||||
error(WarningCode.UNUSED_LOCAL_VARIABLE, 49, 1),
|
||||
error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 53, 1),
|
||||
]);
|
||||
final result = _localVar('x');
|
||||
_assertNull(result);
|
||||
}
|
||||
|
||||
test_visitBinaryExpression_extensionMethod() async {
|
||||
await assertErrorsInCode('''
|
||||
extension on Object {
|
||||
|
@ -1102,7 +1118,8 @@ class C<T> {
|
|||
const C({this.p = f});
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE, 83, 1),
|
||||
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
|
||||
83, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -1223,8 +1240,7 @@ class C<U> {
|
|||
error(WarningCode.UNUSED_LOCAL_VARIABLE, 55, 1),
|
||||
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
|
||||
61, 1),
|
||||
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 61,
|
||||
1),
|
||||
error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 61, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -1668,8 +1684,7 @@ void f<T>(Object? x) {
|
|||
if (x case const (T)) {}
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION,
|
||||
43, 1),
|
||||
error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 43, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -1679,8 +1694,7 @@ void f<T>(Object? x) {
|
|||
if (x case const (List<T>)) {}
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION,
|
||||
43, 7),
|
||||
error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 43, 7),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -2265,23 +2279,6 @@ const c = {1, ...{2, 3}, 4};
|
|||
expect(result.toSetValue()!.map((e) => e.toIntValue()), [1, 2, 3, 4]);
|
||||
}
|
||||
|
||||
test_typeParameter() async {
|
||||
await assertErrorsInCode('''
|
||||
class A<X> {
|
||||
const A();
|
||||
void m() {
|
||||
const x = X;
|
||||
}
|
||||
}
|
||||
''', [
|
||||
error(WarningCode.UNUSED_LOCAL_VARIABLE, 49, 1),
|
||||
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 53,
|
||||
1),
|
||||
]);
|
||||
final result = _localVar('x');
|
||||
_assertNull(result);
|
||||
}
|
||||
|
||||
test_visitAsExpression_instanceOfSameClass() async {
|
||||
await resolveTestCode('''
|
||||
const a = const A();
|
||||
|
|
|
@ -16,6 +16,33 @@ main() {
|
|||
|
||||
@reflectiveTest
|
||||
class ConstEvalPropertyAccessTest extends PubPackageResolutionTest {
|
||||
test_constructorFieldInitializer_fromSeparateLibrary() async {
|
||||
newFile('$testPackageLibPath/lib.dart', r'''
|
||||
class A<T> {
|
||||
final int f;
|
||||
const A() : f = T.foo;
|
||||
}
|
||||
''');
|
||||
await assertErrorsInCode(r'''
|
||||
import 'lib.dart';
|
||||
const a = const A();
|
||||
''', [
|
||||
error(
|
||||
CompileTimeErrorCode.CONST_EVAL_PROPERTY_ACCESS,
|
||||
29,
|
||||
9,
|
||||
contextMessages: [
|
||||
ExpectedContextMessage(
|
||||
convertPath('$testPackageLibPath/lib.dart'), 46, 5,
|
||||
text:
|
||||
"The error is in the field initializer of 'A', and occurs here."),
|
||||
],
|
||||
),
|
||||
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 29,
|
||||
9),
|
||||
]);
|
||||
}
|
||||
|
||||
test_length_invalidTarget() async {
|
||||
await assertErrorsInCode('''
|
||||
void main() {
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../dart/resolution/context_collection_resolution.dart';
|
||||
|
||||
main() {
|
||||
defineReflectiveSuite(() {
|
||||
defineReflectiveTests(ConstTypeParameterTest);
|
||||
});
|
||||
}
|
||||
|
||||
@reflectiveTest
|
||||
class ConstTypeParameterTest extends PubPackageResolutionTest {
|
||||
test_constantPattern_typeParameter() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(x) {
|
||||
if (x case T) {}
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 28, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_constantPattern_typeParameter_nested() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(Object? x) {
|
||||
if (x case const (T)) {}
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 43, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_constantPattern_typeParameter_nested2() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(Object? x) {
|
||||
if (x case const (List<T>)) {}
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 43, 7),
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -135,6 +135,66 @@ class A<T> {
|
|||
@reflectiveTest
|
||||
class ConstWithTypeParametersFunctionTearoffTest
|
||||
extends PubPackageResolutionTest {
|
||||
test_appliedTypeParameter_defaultConstructorValue() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(T t) => t;
|
||||
|
||||
class C<T> {
|
||||
final void Function(T) p;
|
||||
const C({this.p = f});
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
|
||||
83, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_appliedTypeParameter_defaultFunctionValue() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(T t) => t;
|
||||
|
||||
void bar<T>([void Function(T) p = f]) {}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
|
||||
56, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_appliedTypeParameter_defaultMethodValue() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(T t) => t;
|
||||
|
||||
class C<T> {
|
||||
void foo([void Function(T) p = f]) {}
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
|
||||
68, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_appliedTypeParameter_nested() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(T t) => t;
|
||||
|
||||
void bar<T>([void Function(List<T>) p = f]) {}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
|
||||
62, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_appliedTypeParameter_nestedFunction() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(T t) => t;
|
||||
|
||||
void bar<T>([void Function(T Function()) p = f]) {}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
|
||||
67, 1)
|
||||
]);
|
||||
}
|
||||
|
||||
test_defaultValue() async {
|
||||
await assertErrorsInCode('''
|
||||
void f<T>(T a) {}
|
||||
|
@ -144,7 +204,7 @@ class A<U> {
|
|||
''', [
|
||||
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
|
||||
65, 1),
|
||||
error(CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE, 65, 1),
|
||||
error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 65, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -160,8 +220,7 @@ class A<U> {
|
|||
error(HintCode.UNUSED_LOCAL_VARIABLE, 54, 1),
|
||||
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
|
||||
60, 1),
|
||||
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 60,
|
||||
1),
|
||||
error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 60, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -180,6 +239,7 @@ class A<U> {
|
|||
5),
|
||||
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
|
||||
58, 1),
|
||||
error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 58, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -557,39 +557,6 @@ GuardedPattern
|
|||
''');
|
||||
}
|
||||
|
||||
test_typeLiteral_typeParameter() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(x) {
|
||||
if (x case T) {}
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION,
|
||||
28, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_typeLiteral_typeParameter_nested() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(Object? x) {
|
||||
if (x case const (T)) {}
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION,
|
||||
43, 1),
|
||||
]);
|
||||
}
|
||||
|
||||
test_typeLiteral_typeParameter_nested2() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(Object? x) {
|
||||
if (x case const (List<T>)) {}
|
||||
}
|
||||
''', [
|
||||
error(CompileTimeErrorCode.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION,
|
||||
43, 7),
|
||||
]);
|
||||
}
|
||||
|
||||
test_unresolvedIdentifier() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f(Object? x) {
|
||||
|
|
|
@ -49,33 +49,6 @@ class A {
|
|||
]);
|
||||
}
|
||||
|
||||
test_constructorFieldInitializer_fromSeparateLibrary() async {
|
||||
newFile('$testPackageLibPath/lib.dart', r'''
|
||||
class A<T> {
|
||||
final int f;
|
||||
const A() : f = T.foo;
|
||||
}
|
||||
''');
|
||||
await assertErrorsInCode(r'''
|
||||
import 'lib.dart';
|
||||
const a = const A();
|
||||
''', [
|
||||
error(
|
||||
CompileTimeErrorCode.INVALID_CONSTANT,
|
||||
29,
|
||||
9,
|
||||
contextMessages: [
|
||||
ExpectedContextMessage(
|
||||
convertPath('$testPackageLibPath/lib.dart'), 46, 5,
|
||||
text:
|
||||
"The error is in the field initializer of 'A', and occurs here."),
|
||||
],
|
||||
),
|
||||
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 29,
|
||||
9),
|
||||
]);
|
||||
}
|
||||
|
||||
test_in_initializer_field_as() async {
|
||||
await assertNoErrorsInCode('''
|
||||
class C<T> {
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../../generated/test_support.dart';
|
||||
import '../dart/resolution/context_collection_resolution.dart';
|
||||
|
||||
main() {
|
||||
|
@ -16,51 +15,6 @@ main() {
|
|||
|
||||
@reflectiveTest
|
||||
class NonConstantDefaultValueTest extends PubPackageResolutionTest {
|
||||
test_appliedTypeParameter_defaultConstructorValue() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(T t) => t;
|
||||
|
||||
class C<T> {
|
||||
final void Function(T) p;
|
||||
const C({this.p = f});
|
||||
}
|
||||
''', [ExpectedError(CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE, 83, 1)]);
|
||||
}
|
||||
|
||||
test_appliedTypeParameter_defaultFunctionValue() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(T t) => t;
|
||||
|
||||
void bar<T>([void Function(T) p = f]) {}
|
||||
''', [ExpectedError(CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE, 56, 1)]);
|
||||
}
|
||||
|
||||
test_appliedTypeParameter_defaultMethodValue() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(T t) => t;
|
||||
|
||||
class C<T> {
|
||||
void foo([void Function(T) p = f]) {}
|
||||
}
|
||||
''', [ExpectedError(CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE, 68, 1)]);
|
||||
}
|
||||
|
||||
test_appliedTypeParameter_nested() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(T t) => t;
|
||||
|
||||
void bar<T>([void Function(List<T>) p = f]) {}
|
||||
''', [ExpectedError(CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE, 62, 1)]);
|
||||
}
|
||||
|
||||
test_appliedTypeParameter_nestedFunction() async {
|
||||
await assertErrorsInCode(r'''
|
||||
void f<T>(T t) => t;
|
||||
|
||||
void bar<T>([void Function(T Function()) p = f]) {}
|
||||
''', [ExpectedError(CompileTimeErrorCode.NON_CONSTANT_DEFAULT_VALUE, 67, 1)]);
|
||||
}
|
||||
|
||||
test_constructor_named() async {
|
||||
await assertErrorsInCode(r'''
|
||||
class A {
|
||||
|
|
|
@ -132,6 +132,7 @@ import 'const_set_element_not_primitive_equality_test.dart'
|
|||
import 'const_spread_expected_list_or_set_test.dart'
|
||||
as const_spread_expected_list_or_set;
|
||||
import 'const_spread_expected_map_test.dart' as const_spread_expected_map;
|
||||
import 'const_type_parameter_test.dart' as const_type_parameter;
|
||||
import 'const_with_non_const_test.dart' as const_with_non_const;
|
||||
import 'const_with_non_constant_argument_test.dart'
|
||||
as const_with_non_constant_argument;
|
||||
|
@ -986,6 +987,7 @@ main() {
|
|||
const_set_element_not_primitive_equality.main();
|
||||
const_spread_expected_list_or_set.main();
|
||||
const_spread_expected_map.main();
|
||||
const_type_parameter.main();
|
||||
const_with_non_const.main();
|
||||
const_with_non_constant_argument.main();
|
||||
const_with_non_type.main();
|
||||
|
|
|
@ -15,37 +15,37 @@ class Annotation {
|
|||
|
||||
class Class<T, @Annotation(T) U> {}
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_TYPE_PARAMETER
|
||||
// [cfe] Type variables can't be used as constants.
|
||||
|
||||
void function<T, @Annotation(T) U>() {}
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_TYPE_PARAMETER
|
||||
// [cfe] Type variables can't be used as constants.
|
||||
|
||||
extension Extension<T, @Annotation(T) U> on Map<T, U> {}
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_TYPE_PARAMETER
|
||||
// [cfe] Type variables can't be used as constants.
|
||||
|
||||
class C {
|
||||
void method<T, @Annotation(T) U>() {}
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_TYPE_PARAMETER
|
||||
// [cfe] Type variables can't be used as constants.
|
||||
}
|
||||
|
||||
mixin Mixin<T, @Annotation(T) U> {}
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_TYPE_PARAMETER
|
||||
// [cfe] Type variables can't be used as constants.
|
||||
|
||||
typedef void Typedef1<T, @Annotation(T) U>(T t, U u);
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_TYPE_PARAMETER
|
||||
// [cfe] Type variables can't be used as constants.
|
||||
|
||||
typedef Typedef2<T, @Annotation(T) U> = void Function(T t, U u);
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_TYPE_PARAMETER
|
||||
// [cfe] Type variables can't be used as constants.
|
||||
|
|
|
@ -9,10 +9,8 @@ class C<T> {
|
|||
const List lst = const [
|
||||
T
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_TYPE_PARAMETER
|
||||
// [cfe] Type variables can't be used as constants.
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.NON_CONSTANT_LIST_ELEMENT
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,37 +15,37 @@ class Annotation {
|
|||
|
||||
class Class<T, @Annotation(T) U> {}
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_TYPE_PARAMETER
|
||||
// [cfe] Type variables can't be used as constants.
|
||||
|
||||
void function<T, @Annotation(T) U>() {}
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_TYPE_PARAMETER
|
||||
// [cfe] Type variables can't be used as constants.
|
||||
|
||||
extension Extension<T, @Annotation(T) U> on Map<T, U> {}
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_TYPE_PARAMETER
|
||||
// [cfe] Type variables can't be used as constants.
|
||||
|
||||
class C {
|
||||
void method<T, @Annotation(T) U>() {}
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_TYPE_PARAMETER
|
||||
// [cfe] Type variables can't be used as constants.
|
||||
}
|
||||
|
||||
mixin Mixin<T, @Annotation(T) U> {}
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_TYPE_PARAMETER
|
||||
// [cfe] Type variables can't be used as constants.
|
||||
|
||||
typedef void Typedef1<T, @Annotation(T) U>(T t, U u);
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_TYPE_PARAMETER
|
||||
// [cfe] Type variables can't be used as constants.
|
||||
|
||||
typedef Typedef2<T, @Annotation(T) U> = void Function(T t, U u);
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_WITH_NON_CONSTANT_ARGUMENT
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_TYPE_PARAMETER
|
||||
// [cfe] Type variables can't be used as constants.
|
||||
|
|
Loading…
Reference in a new issue