[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:
Kallen Tu 2023-08-29 22:36:02 +00:00 committed by Commit Queue
parent 2ee7f1ff0c
commit af24f1d61a
18 changed files with 280 additions and 202 deletions

View file

@ -445,6 +445,8 @@ CompileTimeErrorCode.CONST_SPREAD_EXPECTED_LIST_OR_SET:
status: noFix status: noFix
CompileTimeErrorCode.CONST_SPREAD_EXPECTED_MAP: CompileTimeErrorCode.CONST_SPREAD_EXPECTED_MAP:
status: noFix status: noFix
CompileTimeErrorCode.CONST_TYPE_PARAMETER:
status: needsEvaluation
CompileTimeErrorCode.CONST_WITH_NON_CONST: CompileTimeErrorCode.CONST_WITH_NON_CONST:
status: hasFix status: hasFix
CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT: CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT:

View file

@ -535,6 +535,7 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
// Should not be a type parameter. // Should not be a type parameter.
if (type.element is TypeParameterElement) { if (type.element is TypeParameterElement) {
_errorReporter.reportErrorForNode(errorCode, type); _errorReporter.reportErrorForNode(errorCode, type);
return;
} }
// Check type arguments. // Check type arguments.
var typeArguments = type.typeArguments; var typeArguments = type.typeArguments;
@ -603,6 +604,11 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
CompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH) || CompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH) ||
identical(dataErrorCode, identical(dataErrorCode,
CompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH) || CompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH) ||
identical(dataErrorCode, CompileTimeErrorCode.CONST_TYPE_PARAMETER) ||
identical(
dataErrorCode,
CompileTimeErrorCode
.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF) ||
identical( identical(
dataErrorCode, CompileTimeErrorCode.VARIABLE_TYPE_MISMATCH) || dataErrorCode, CompileTimeErrorCode.VARIABLE_TYPE_MISMATCH) ||
identical(dataErrorCode, CompileTimeErrorCode.NON_BOOL_CONDITION) || identical(dataErrorCode, CompileTimeErrorCode.NON_BOOL_CONDITION) ||

View file

@ -836,7 +836,7 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
@override @override
Constant visitFunctionReference(FunctionReference node) { Constant visitFunctionReference(FunctionReference node) {
var functionResult = _getConstant(node.function); final functionResult = _getConstant(node.function);
if (functionResult is! DartObjectImpl) { if (functionResult is! DartObjectImpl) {
return functionResult; return functionResult;
} }
@ -846,9 +846,9 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
// any type parameters contained therein are reported as non-constant in // any type parameters contained therein are reported as non-constant in
// [ConstantVerifier]. // [ConstantVerifier].
if (node.typeArguments == null) { if (node.typeArguments == null) {
var typeArgumentTypes = node.typeArgumentTypes; final typeArgumentTypes = node.typeArgumentTypes;
if (typeArgumentTypes != null) { if (typeArgumentTypes != null) {
var instantiatedTypeArgumentTypes = typeArgumentTypes.map((type) { final instantiatedTypeArgumentTypes = typeArgumentTypes.map((type) {
if (type is TypeParameterType) { if (type is TypeParameterType) {
return _lexicalTypeEnvironment?[type.element] ?? type; return _lexicalTypeEnvironment?[type.element] ?? type;
} else { } else {
@ -866,26 +866,39 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
} }
} }
var typeArgumentList = node.typeArguments; final typeArgumentList = node.typeArguments;
if (typeArgumentList == null) { if (typeArgumentList == null) {
return _instantiateFunctionType(node, functionResult); return _instantiateFunctionType(node, functionResult);
} }
var typeArguments = <DartType>[]; final typeArguments = <DartType>[];
for (var typeArgument in typeArgumentList.arguments) { for (var typeArgument in typeArgumentList.arguments) {
var object = _getConstant(typeArgument); final typeArgumentConstant = _getConstant(typeArgument);
if (object is! DartObjectImpl) { switch (typeArgumentConstant) {
return object; 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);
}
// TODO(srawlins): Test type alias types (`typedef i = int`) used as
// type arguments. Possibly change implementation based on
// canonicalization rules.
typeArguments.add(typeArgumentType);
} }
var typeArgumentType = object.toTypeValue();
if (typeArgumentType == null) {
return InvalidConstant(
typeArgument, CompileTimeErrorCode.INVALID_CONSTANT);
}
// TODO(srawlins): Test type alias types (`typedef i = int`) used as
// type arguments. Possibly change implementation based on
// canonicalization rules.
typeArguments.add(typeArgumentType);
} }
return _dartObjectComputer.typeInstantiate( return _dartObjectComputer.typeInstantiate(
functionResult, typeArguments, node.function); functionResult, typeArguments, node.function);
@ -954,7 +967,8 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
if (!result.isBoolNumStringOrNull) { if (!result.isBoolNumStringOrNull) {
// TODO(kallentu): Don't report error here. // 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( return InvalidConstant(
node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING); node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
} }
@ -1070,11 +1084,10 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
if ((!_isNonNullableByDefault || node.isTypeLiteralInConstantPattern) && if ((!_isNonNullableByDefault || node.isTypeLiteralInConstantPattern) &&
hasTypeParameterReference(type)) { hasTypeParameterReference(type)) {
// TODO(kallentu): Don't report error here and report a more specific // TODO(kallentu): Don't report error here
// diagnostic
_errorReporter.reportErrorForNode( _errorReporter.reportErrorForNode(
CompileTimeErrorCode.INVALID_CONSTANT, node); CompileTimeErrorCode.CONST_TYPE_PARAMETER, node);
return InvalidConstant(node, CompileTimeErrorCode.INVALID_CONSTANT); return InvalidConstant(node, CompileTimeErrorCode.CONST_TYPE_PARAMETER);
} else if (node.isDeferred) { } else if (node.isDeferred) {
return _getDeferredLibraryError(node, node.name2) ?? return _getDeferredLibraryError(node, node.name2) ??
InvalidConstant(node, CompileTimeErrorCode.INVALID_CONSTANT); InvalidConstant(node, CompileTimeErrorCode.INVALID_CONSTANT);
@ -1129,10 +1142,10 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
// String.length // String.length
if (prefixElement is! InterfaceElement) { if (prefixElement is! InterfaceElement) {
final stringLengthResult = final propertyAccessResult =
_evaluateStringLength(prefixResult, node.identifier, node); _evaluatePropertyAccess(prefixResult, node.identifier, node);
if (stringLengthResult != null) { if (propertyAccessResult != null) {
return stringLengthResult; return propertyAccessResult;
} }
} }
} }
@ -1182,10 +1195,10 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
return prefixResult; return prefixResult;
} }
final stringLengthResult = final propertyAccessResult =
_evaluateStringLength(prefixResult, node.propertyName, node); _evaluatePropertyAccess(prefixResult, node.propertyName, node);
if (stringLengthResult != null) { if (propertyAccessResult != null) {
return stringLengthResult; return propertyAccessResult;
} }
} }
return _getConstantValue( return _getConstantValue(
@ -1380,7 +1393,8 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
return null; return null;
} }
case MapLiteralEntry(): case MapLiteralEntry():
return InvalidConstant(element, CompileTimeErrorCode.INVALID_CONSTANT); return InvalidConstant(
element, CompileTimeErrorCode.MAP_ENTRY_NOT_IN_MAP);
case SpreadElement(): case SpreadElement():
var spread = _getConstant(element.expression); var spread = _getConstant(element.expression);
switch (spread) { switch (spread) {
@ -1405,7 +1419,7 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
Map<DartObjectImpl, DartObjectImpl> map, CollectionElement element) { Map<DartObjectImpl, DartObjectImpl> map, CollectionElement element) {
switch (element) { switch (element) {
case Expression(): case Expression():
return InvalidConstant(element, CompileTimeErrorCode.INVALID_CONSTANT); return InvalidConstant(element, CompileTimeErrorCode.EXPRESSION_IN_MAP);
case ForElement(): case ForElement():
// TODO(kallentu): Don't report error here. // TODO(kallentu): Don't report error here.
_errorReporter.reportErrorForNode( _errorReporter.reportErrorForNode(
@ -1508,7 +1522,8 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
return null; return null;
} }
case MapLiteralEntry(): case MapLiteralEntry():
return InvalidConstant(element, CompileTimeErrorCode.INVALID_CONSTANT); return InvalidConstant(
element, CompileTimeErrorCode.MAP_ENTRY_NOT_IN_MAP);
case SpreadElement(): case SpreadElement():
var spread = _getConstant(element.expression); var spread = _getConstant(element.expression);
switch (spread) { switch (spread) {
@ -1578,12 +1593,12 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
_errorReporter.reportErrorForNode(code, node); _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 /// Return a valid [DartObjectImpl] if the given [targetResult] represents a
/// `String` and the [identifier] is `length`, an [InvalidConstant] if there's /// `String` and the [identifier] is `length`, an [InvalidConstant] if there's
/// an error, and `null` otherwise. /// an error, and `null` otherwise.
Constant? _evaluateStringLength(DartObjectImpl targetResult, Constant? _evaluatePropertyAccess(DartObjectImpl targetResult,
SimpleIdentifier identifier, AstNode errorNode) { SimpleIdentifier identifier, AstNode errorNode) {
if (identifier.staticElement?.enclosingElement is ExtensionElement) { if (identifier.staticElement?.enclosingElement is ExtensionElement) {
_errorReporter.reportErrorForNode( _errorReporter.reportErrorForNode(
@ -1592,23 +1607,33 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
errorNode, CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD); errorNode, CompileTimeErrorCode.CONST_EVAL_EXTENSION_METHOD);
} }
if (identifier.name == 'length') { final targetType = targetResult.type;
final targetType = targetResult.type;
if (!(targetType is InterfaceType && targetType.isDartCoreString)) { // Evaluate a constant that reads the length of a `String`.
_errorReporter.reportErrorForNode( if (identifier.name == 'length' &&
CompileTimeErrorCode.CONST_EVAL_PROPERTY_ACCESS, targetType is InterfaceType &&
errorNode, targetType.isDartCoreString) {
[identifier.name, targetType]);
return InvalidConstant(
errorNode, CompileTimeErrorCode.CONST_EVAL_PROPERTY_ACCESS,
arguments: [identifier.name, targetType]);
}
return _dartObjectComputer.stringLength(errorNode, targetResult); return _dartObjectComputer.stringLength(errorNode, targetResult);
} }
// TODO(kallentu): Make a more specific error here if we aren't accessing final element = identifier.staticElement;
// the '.length' property. if (element != null && element is ExecutableElement && element.isStatic) {
return null; 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]. /// Return a [Constant], evaluated by the [ConstantVisitor].
@ -1650,8 +1675,10 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
(expression.tearOffTypeArgumentTypes?.any(hasTypeParameterReference) ?? (expression.tearOffTypeArgumentTypes?.any(hasTypeParameterReference) ??
false)) { false)) {
// TODO(kallentu): Don't report error here. // TODO(kallentu): Don't report error here.
_error(expression, null); _errorReporter.reportErrorForNode(
return InvalidConstant.genericError(expression); CompileTimeErrorCode.CONST_TYPE_PARAMETER, expression);
return InvalidConstant(
expression, CompileTimeErrorCode.CONST_TYPE_PARAMETER);
} }
if (variableElement is VariableElementImpl) { if (variableElement is VariableElementImpl) {
@ -1748,7 +1775,7 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
// Constants may refer to type parameters only if the constructor-tearoffs // Constants may refer to type parameters only if the constructor-tearoffs
// feature is enabled. // feature is enabled.
if (_library.featureSet.isEnabled(Feature.constructor_tearoffs)) { if (_library.featureSet.isEnabled(Feature.constructor_tearoffs)) {
var typeArgument = _lexicalTypeEnvironment?[variableElement]; final typeArgument = _lexicalTypeEnvironment?[variableElement];
if (typeArgument != null) { if (typeArgument != null) {
return DartObjectImpl( return DartObjectImpl(
typeSystem, typeSystem,
@ -1756,6 +1783,10 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
TypeState(typeArgument), TypeState(typeArgument),
); );
} }
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.CONST_TYPE_PARAMETER, errorNode2);
return InvalidConstant(
errorNode2, CompileTimeErrorCode.CONST_TYPE_PARAMETER);
} }
} }

View file

@ -1027,6 +1027,14 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
hasPublishedDocs: true, 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. /// No parameters.
static const CompileTimeErrorCode CONST_WITH_NON_CONST = CompileTimeErrorCode( static const CompileTimeErrorCode CONST_WITH_NON_CONST = CompileTimeErrorCode(
'CONST_WITH_NON_CONST', 'CONST_WITH_NON_CONST',

View file

@ -138,6 +138,7 @@ const List<ErrorCode> errorCodeValues = [
CompileTimeErrorCode.CONST_SET_ELEMENT_NOT_PRIMITIVE_EQUALITY, CompileTimeErrorCode.CONST_SET_ELEMENT_NOT_PRIMITIVE_EQUALITY,
CompileTimeErrorCode.CONST_SPREAD_EXPECTED_LIST_OR_SET, CompileTimeErrorCode.CONST_SPREAD_EXPECTED_LIST_OR_SET,
CompileTimeErrorCode.CONST_SPREAD_EXPECTED_MAP, CompileTimeErrorCode.CONST_SPREAD_EXPECTED_MAP,
CompileTimeErrorCode.CONST_TYPE_PARAMETER,
CompileTimeErrorCode.CONST_WITH_NON_CONST, CompileTimeErrorCode.CONST_WITH_NON_CONST,
CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT, CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT,
CompileTimeErrorCode.CONST_WITH_NON_TYPE, CompileTimeErrorCode.CONST_WITH_NON_TYPE,

View file

@ -986,6 +986,7 @@ class _ConstantAnalysisErrorListener extends AnalysisErrorListener {
case CompileTimeErrorCode.CONST_EVAL_FOR_ELEMENT: case CompileTimeErrorCode.CONST_EVAL_FOR_ELEMENT:
case CompileTimeErrorCode.CONST_MAP_KEY_NOT_PRIMITIVE_EQUALITY: case CompileTimeErrorCode.CONST_MAP_KEY_NOT_PRIMITIVE_EQUALITY:
case CompileTimeErrorCode.CONST_SET_ELEMENT_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_CONST:
case CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT: case CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT:
case CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS: case CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS:

View file

@ -3034,6 +3034,10 @@ CompileTimeErrorCode:
const Map<String, int> map1 = {}; const Map<String, int> map1 = {};
const Map<String, int> map2 = {...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: CONST_WITH_NON_CONST:
problemMessage: "The constructor being called isn't a const constructor." problemMessage: "The constructor being called isn't a const constructor."
correctionMessage: "Try removing 'const' from the constructor invocation." correctionMessage: "Try removing 'const' from the constructor invocation."

View file

@ -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 { test_visitBinaryExpression_extensionMethod() async {
await assertErrorsInCode(''' await assertErrorsInCode('''
extension on Object { extension on Object {
@ -1102,7 +1118,8 @@ class C<T> {
const C({this.p = f}); 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(WarningCode.UNUSED_LOCAL_VARIABLE, 55, 1),
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF, error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
61, 1), 61, 1),
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 61, error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 61, 1),
1),
]); ]);
} }
@ -1668,8 +1684,7 @@ void f<T>(Object? x) {
if (x case const (T)) {} if (x case const (T)) {}
} }
''', [ ''', [
error(CompileTimeErrorCode.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION, error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 43, 1),
43, 1),
]); ]);
} }
@ -1679,8 +1694,7 @@ void f<T>(Object? x) {
if (x case const (List<T>)) {} if (x case const (List<T>)) {}
} }
''', [ ''', [
error(CompileTimeErrorCode.CONSTANT_PATTERN_WITH_NON_CONSTANT_EXPRESSION, error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 43, 7),
43, 7),
]); ]);
} }
@ -2265,23 +2279,6 @@ const c = {1, ...{2, 3}, 4};
expect(result.toSetValue()!.map((e) => e.toIntValue()), [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 { test_visitAsExpression_instanceOfSameClass() async {
await resolveTestCode(''' await resolveTestCode('''
const a = const A(); const a = const A();

View file

@ -16,6 +16,33 @@ main() {
@reflectiveTest @reflectiveTest
class ConstEvalPropertyAccessTest extends PubPackageResolutionTest { 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 { test_length_invalidTarget() async {
await assertErrorsInCode(''' await assertErrorsInCode('''
void main() { void main() {

View file

@ -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),
]);
}
}

View file

@ -135,6 +135,66 @@ class A<T> {
@reflectiveTest @reflectiveTest
class ConstWithTypeParametersFunctionTearoffTest class ConstWithTypeParametersFunctionTearoffTest
extends PubPackageResolutionTest { 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 { test_defaultValue() async {
await assertErrorsInCode(''' await assertErrorsInCode('''
void f<T>(T a) {} void f<T>(T a) {}
@ -144,7 +204,7 @@ class A<U> {
''', [ ''', [
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF, error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
65, 1), 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(HintCode.UNUSED_LOCAL_VARIABLE, 54, 1),
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF, error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
60, 1), 60, 1),
error(CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE, 60, error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 60, 1),
1),
]); ]);
} }
@ -180,6 +239,7 @@ class A<U> {
5), 5),
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF, error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
58, 1), 58, 1),
error(CompileTimeErrorCode.CONST_TYPE_PARAMETER, 58, 1),
]); ]);
} }

View file

@ -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 { test_unresolvedIdentifier() async {
await assertErrorsInCode(r''' await assertErrorsInCode(r'''
void f(Object? x) { void f(Object? x) {

View file

@ -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 { test_in_initializer_field_as() async {
await assertNoErrorsInCode(''' await assertNoErrorsInCode('''
class C<T> { class C<T> {

View file

@ -5,7 +5,6 @@
import 'package:analyzer/src/error/codes.dart'; import 'package:analyzer/src/error/codes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../../generated/test_support.dart';
import '../dart/resolution/context_collection_resolution.dart'; import '../dart/resolution/context_collection_resolution.dart';
main() { main() {
@ -16,51 +15,6 @@ main() {
@reflectiveTest @reflectiveTest
class NonConstantDefaultValueTest extends PubPackageResolutionTest { 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 { test_constructor_named() async {
await assertErrorsInCode(r''' await assertErrorsInCode(r'''
class A { class A {

View file

@ -132,6 +132,7 @@ import 'const_set_element_not_primitive_equality_test.dart'
import 'const_spread_expected_list_or_set_test.dart' import 'const_spread_expected_list_or_set_test.dart'
as const_spread_expected_list_or_set; as const_spread_expected_list_or_set;
import 'const_spread_expected_map_test.dart' as const_spread_expected_map; 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_const_test.dart' as const_with_non_const;
import 'const_with_non_constant_argument_test.dart' import 'const_with_non_constant_argument_test.dart'
as const_with_non_constant_argument; as const_with_non_constant_argument;
@ -986,6 +987,7 @@ main() {
const_set_element_not_primitive_equality.main(); const_set_element_not_primitive_equality.main();
const_spread_expected_list_or_set.main(); const_spread_expected_list_or_set.main();
const_spread_expected_map.main(); const_spread_expected_map.main();
const_type_parameter.main();
const_with_non_const.main(); const_with_non_const.main();
const_with_non_constant_argument.main(); const_with_non_constant_argument.main();
const_with_non_type.main(); const_with_non_type.main();

View file

@ -15,37 +15,37 @@ class Annotation {
class Class<T, @Annotation(T) U> {} 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. // [cfe] Type variables can't be used as constants.
void function<T, @Annotation(T) U>() {} 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. // [cfe] Type variables can't be used as constants.
extension Extension<T, @Annotation(T) U> on Map<T, U> {} 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. // [cfe] Type variables can't be used as constants.
class C { class C {
void method<T, @Annotation(T) U>() {} 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. // [cfe] Type variables can't be used as constants.
} }
mixin Mixin<T, @Annotation(T) U> {} 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. // [cfe] Type variables can't be used as constants.
typedef void Typedef1<T, @Annotation(T) U>(T t, U u); 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. // [cfe] Type variables can't be used as constants.
typedef Typedef2<T, @Annotation(T) U> = void Function(T t, U u); 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. // [cfe] Type variables can't be used as constants.

View file

@ -9,10 +9,8 @@ class C<T> {
const List lst = const [ const List lst = const [
T 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. // [cfe] Type variables can't be used as constants.
// ^
// [analyzer] COMPILE_TIME_ERROR.NON_CONSTANT_LIST_ELEMENT
]; ];
} }
} }

View file

@ -15,37 +15,37 @@ class Annotation {
class Class<T, @Annotation(T) U> {} 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. // [cfe] Type variables can't be used as constants.
void function<T, @Annotation(T) U>() {} 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. // [cfe] Type variables can't be used as constants.
extension Extension<T, @Annotation(T) U> on Map<T, U> {} 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. // [cfe] Type variables can't be used as constants.
class C { class C {
void method<T, @Annotation(T) U>() {} 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. // [cfe] Type variables can't be used as constants.
} }
mixin Mixin<T, @Annotation(T) U> {} 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. // [cfe] Type variables can't be used as constants.
typedef void Typedef1<T, @Annotation(T) U>(T t, U u); 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. // [cfe] Type variables can't be used as constants.
typedef Typedef2<T, @Annotation(T) U> = void Function(T t, U u); 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. // [cfe] Type variables can't be used as constants.