Check type parameters in const function tearoff

Fixes https://github.com/dart-lang/sdk/issues/47213

Change-Id: I6c1c7e386e64b877e1ea7d312335d924488f2306
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/214134
Commit-Queue: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Sam Rawlins 2021-09-22 19:36:04 +00:00 committed by commit-bot@chromium.org
parent f1e6092dd8
commit 1379c867a4
5 changed files with 97 additions and 0 deletions

View file

@ -141,6 +141,7 @@ const List<ErrorCode> errorCodeValues = [
CompileTimeErrorCode.CONST_WITH_NON_TYPE,
CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS,
CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_CONSTRUCTOR_TEAROFF,
CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR,
CompileTimeErrorCode.CONST_WITH_UNDEFINED_CONSTRUCTOR_DEFAULT,
CompileTimeErrorCode.CONTINUE_LABEL_ON_SWITCH,

View file

@ -128,6 +128,21 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
_validateDefaultValues(node.parameters);
}
@override
void visitFunctionReference(FunctionReference node) {
super.visitFunctionReference(node);
if (node.inConstantContext) {
var typeArguments = node.typeArguments;
if (typeArguments == null) {
return;
}
for (var typeArgument in typeArguments.arguments) {
_checkForConstWithTypeParameters(typeArgument,
CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF);
}
}
}
@override
void visitGenericFunctionType(GenericFunctionType node) {
// TODO(srawlins): Also check interface types (TypeName?).

View file

@ -2898,6 +2898,18 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
uniqueName: 'CONST_WITH_TYPE_PARAMETERS_CONSTRUCTOR_TEAROFF',
hasPublishedDocs: true);
/**
* No parameters.
*/
static const CompileTimeErrorCode
CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF = CompileTimeErrorCode(
'CONST_WITH_TYPE_PARAMETERS',
"A constant function tearoff can't use a type parameter as a type "
"argument.",
correction: "Try replacing the type parameter with a different type.",
uniqueName: 'CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF',
hasPublishedDocs: true);
/**
* 16.12.2 Const: It is a compile-time error if <i>T.id</i> is not the name of
* a constant constructor declared by the type <i>T</i>.

View file

@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/src/error/codes.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../dart/resolution/context_collection_resolution.dart';
@ -10,6 +11,7 @@ import '../dart/resolution/context_collection_resolution.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(ConstWithTypeParametersConstructorTearoffTest);
defineReflectiveTests(ConstWithTypeParametersFunctionTearoffTest);
defineReflectiveTests(ConstWithTypeParametersTest);
});
}
@ -83,6 +85,71 @@ class A<T> {
}
}
@reflectiveTest
class ConstWithTypeParametersFunctionTearoffTest
extends PubPackageResolutionTest {
@FailingTest(
reason: 'The default value of an optional parameter is not considered a '
'"constant context". Currently only ConstantVerifier checks '
'CONST_WITH_TYPE_PARAMETERS (and related) errors, and only for '
'constant contexts. These checks should probably be moved to '
'ConstantVisitor (evaluation.dart), so as to check all expressions '
'expected to be constant expressions. Another example of a missing '
'error is a field initializer in a class with a constant constructor.',
)
test_defaultValue() async {
addTestFile('''
void f<T>(T a) {}
class A<U> {
void m([void Function(U) fn = f<U>]) {}
}
''');
await resolveTestFile();
expect(result.errors, isNotEmpty);
}
test_direct() async {
await assertErrorsInCode('''
void f<T>(T a) {}
class A<U> {
void m() {
const c = f<U>;
}
}
''', [
error(HintCode.UNUSED_LOCAL_VARIABLE, 54, 1),
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
60, 1),
]);
}
test_indirect() async {
await assertErrorsInCode('''
void f<T>(T a) {}
class A<U> {
void m() {
const c = f<List<U>>;
}
}
''', [
error(HintCode.UNUSED_LOCAL_VARIABLE, 54, 1),
error(CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS_FUNCTION_TEAROFF,
65, 1),
]);
}
test_nonConst() async {
await assertNoErrorsInCode('''
void f<T>(T a) {}
class A<U> {
void m() {
f<U>;
}
}
''');
}
}
@reflectiveTest
class ConstWithTypeParametersTest extends PubPackageResolutionTest {
test_direct() async {

View file

@ -2648,6 +2648,8 @@ _A constant constructor tearoff can't use a type parameter as a type argument._
_A constant creation can't use a type parameter as a type argument._
_A constant function tearoff can't use a type parameter as a type argument._
#### Description
The analyzer produces this diagnostic when a type parameter is used as a