Add a temporary analyzer error to work around #28515
Analyzer summaries do not yet support generic function-typed parameters. To avoid user confusion, generate an error if the user tries to use a generic function-typed parameter. The error can be worked around by using a typedef or changing generic types to `dynamic`. R=brianwilkerson@google.com, scheglov@google.com Review-Url: https://codereview.chromium.org/2656303004 .
This commit is contained in:
@@ -118,6 +118,7 @@ const List<ErrorCode> errorCodeValues = const [
|
||||
CompileTimeErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR,
|
||||
CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR,
|
||||
CompileTimeErrorCode.FINAL_INITIALIZED_MULTIPLE_TIMES,
|
||||
CompileTimeErrorCode.GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED,
|
||||
CompileTimeErrorCode.GETTER_AND_METHOD_WITH_SAME_NAME,
|
||||
CompileTimeErrorCode.IMPLEMENTS_DEFERRED_CLASS,
|
||||
CompileTimeErrorCode.IMPLEMENTS_DISALLOWED_CLASS,
|
||||
|
||||
@@ -1047,6 +1047,22 @@ class CompileTimeErrorCode extends ErrorCode {
|
||||
"The redirecting constructor can't have a field initializer.",
|
||||
"Try using a normal parameter.");
|
||||
|
||||
/**
|
||||
* Temporary error to work around dartbug.com/28515.
|
||||
*
|
||||
* We cannot yet properly summarize function-typed parameters with generic
|
||||
* arguments, so to prevent confusion, we produce an error for any such
|
||||
* constructs (regardless of whether summaries are in use).
|
||||
*
|
||||
* TODO(paulberry): remove this once dartbug.com/28515 is fixed.
|
||||
*/
|
||||
static const GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED =
|
||||
const CompileTimeErrorCode(
|
||||
'GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED',
|
||||
"Analysis of generic function typed parameters is not yet supported.",
|
||||
"Try using an explicit typedef, or changing type parameters to "
|
||||
"`dynamic`.");
|
||||
|
||||
/**
|
||||
* 7.2 Getters: It is a compile-time error if a class has both a getter and a
|
||||
* method with the same name.
|
||||
|
||||
@@ -386,6 +386,13 @@ class DeclarationResolver extends RecursiveAstVisitor<Object> {
|
||||
|
||||
@override
|
||||
Object visitTypeParameter(TypeParameter node) {
|
||||
if (node.parent.parent is FunctionTypedFormalParameter) {
|
||||
// Work around dartbug.com/28515.
|
||||
// TODO(paulberry): remove this once dartbug.com/28515 is fixed.
|
||||
Element element = new TypeParameterElementImpl.forNode(node.name);
|
||||
node.name?.staticElement = element;
|
||||
return null;
|
||||
}
|
||||
Element element = _match(node.name, _walker.getTypeParameter());
|
||||
super.visitTypeParameter(node);
|
||||
_resolveMetadata(node, node.metadata, element);
|
||||
|
||||
@@ -857,6 +857,14 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
||||
[node.identifier]);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(paulberry): remove this once dartbug.com/28515 is fixed.
|
||||
if (node.typeParameters != null) {
|
||||
_errorReporter.reportErrorForNode(
|
||||
CompileTimeErrorCode.GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED,
|
||||
node);
|
||||
}
|
||||
|
||||
return super.visitFunctionTypedFormalParameter(node);
|
||||
} finally {
|
||||
_isInFunctionTypedFormalParameter = old;
|
||||
@@ -2572,6 +2580,40 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the class is not named `Function` and that it doesn't
|
||||
* extends/implements/mixes in `Function`.
|
||||
*/
|
||||
void _checkForBadFunctionUse(ClassDeclaration node) {
|
||||
ExtendsClause extendsClause = node.extendsClause;
|
||||
ImplementsClause implementsClause = node.implementsClause;
|
||||
WithClause withClause = node.withClause;
|
||||
|
||||
if (node.name.name == "Function") {
|
||||
_errorReporter.reportErrorForNode(
|
||||
HintCode.DEPRECATED_FUNCTION_CLASS_DECLARATION, node.name);
|
||||
}
|
||||
|
||||
if (extendsClause != null) {
|
||||
InterfaceType superclassType = _enclosingClass.supertype;
|
||||
ClassElement superclassElement = superclassType?.element;
|
||||
if (superclassElement != null && superclassElement.name == "Function") {
|
||||
_errorReporter.reportErrorForNode(
|
||||
HintCode.DEPRECATED_EXTENDS_FUNCTION, extendsClause.superclass);
|
||||
}
|
||||
}
|
||||
|
||||
if (withClause != null) {
|
||||
for (TypeName type in withClause.mixinTypes) {
|
||||
Element mixinElement = type.name.staticElement;
|
||||
if (mixinElement != null && mixinElement.name == "Function") {
|
||||
_errorReporter.reportErrorForNode(
|
||||
HintCode.DEPRECATED_MIXIN_FUNCTION, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the given [identifier] is not a keyword, and generates the
|
||||
* given [errorCode] on the identifier if it is a keyword.
|
||||
@@ -2942,40 +2984,6 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the class is not named `Function` and that it doesn't
|
||||
* extends/implements/mixes in `Function`.
|
||||
*/
|
||||
void _checkForBadFunctionUse(ClassDeclaration node) {
|
||||
ExtendsClause extendsClause = node.extendsClause;
|
||||
ImplementsClause implementsClause = node.implementsClause;
|
||||
WithClause withClause = node.withClause;
|
||||
|
||||
if (node.name.name == "Function") {
|
||||
_errorReporter.reportErrorForNode(
|
||||
HintCode.DEPRECATED_FUNCTION_CLASS_DECLARATION, node.name);
|
||||
}
|
||||
|
||||
if (extendsClause != null) {
|
||||
InterfaceType superclassType = _enclosingClass.supertype;
|
||||
ClassElement superclassElement = superclassType?.element;
|
||||
if (superclassElement != null && superclassElement.name == "Function") {
|
||||
_errorReporter.reportErrorForNode(
|
||||
HintCode.DEPRECATED_EXTENDS_FUNCTION, extendsClause.superclass);
|
||||
}
|
||||
}
|
||||
|
||||
if (withClause != null) {
|
||||
for (TypeName type in withClause.mixinTypes) {
|
||||
Element mixinElement = type.name.staticElement;
|
||||
if (mixinElement != null && mixinElement.name == "Function") {
|
||||
_errorReporter.reportErrorForNode(
|
||||
HintCode.DEPRECATED_MIXIN_FUNCTION, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the enclosing class does not have an instance member with the
|
||||
* same name as the given static [method] declaration.
|
||||
|
||||
@@ -2441,6 +2441,51 @@ var b2 = const bool.fromEnvironment('x', defaultValue: 1);''');
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_genericFunctionTypedParameter() async {
|
||||
// Once dartbug.com/28515 is fixed, this syntax should no longer generate an
|
||||
// error.
|
||||
// TODO(paulberry): When dartbug.com/28515 is fixed, convert this into a
|
||||
// NonErrorResolverTest.
|
||||
Source source = addSource('void g(T f<T>(T x)) {}');
|
||||
await computeAnalysisResult(source);
|
||||
var expectedErrorCodes = <ErrorCode>[
|
||||
CompileTimeErrorCode.GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED
|
||||
];
|
||||
if (enableNewAnalysisDriver) {
|
||||
// Due to dartbug.com/28515, some additional errors appear when using the
|
||||
// new analysis driver.
|
||||
expectedErrorCodes.addAll([
|
||||
StaticWarningCode.UNDEFINED_CLASS,
|
||||
StaticWarningCode.UNDEFINED_CLASS
|
||||
]);
|
||||
}
|
||||
assertErrors(source, expectedErrorCodes);
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_genericFunctionTypedParameter_commentSyntax() async {
|
||||
// Once dartbug.com/28515 is fixed, this syntax should no longer generate an
|
||||
// error.
|
||||
// TODO(paulberry): When dartbug.com/28515 is fixed, convert this into a
|
||||
// NonErrorResolverTest.
|
||||
resetWith(options: new AnalysisOptionsImpl()..strongMode = true);
|
||||
Source source = addSource('void g(/*=T*/ f/*<T>*/(/*=T*/ x)) {}');
|
||||
await computeAnalysisResult(source);
|
||||
var expectedErrorCodes = <ErrorCode>[
|
||||
CompileTimeErrorCode.GENERIC_FUNCTION_TYPED_PARAM_UNSUPPORTED
|
||||
];
|
||||
if (enableNewAnalysisDriver) {
|
||||
// Due to dartbug.com/28515, some additional errors appear when using the
|
||||
// new analysis driver.
|
||||
expectedErrorCodes.addAll([
|
||||
StaticWarningCode.UNDEFINED_CLASS,
|
||||
StaticWarningCode.UNDEFINED_CLASS
|
||||
]);
|
||||
}
|
||||
assertErrors(source, expectedErrorCodes);
|
||||
verify([source]);
|
||||
}
|
||||
|
||||
test_getterAndMethodWithSameName() async {
|
||||
Source source = addSource(r'''
|
||||
class A {
|
||||
|
||||
@@ -2154,9 +2154,12 @@ main() {
|
||||
}
|
||||
|
||||
test_genericFunction_parameter() async {
|
||||
await resolveTestUnit(r'''
|
||||
await resolveTestUnit(
|
||||
r'''
|
||||
void g(/*=T*/ f/*<T>*/(/*=T*/ x)) {}
|
||||
''');
|
||||
''',
|
||||
noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
|
||||
);
|
||||
expectFunctionType('f', '<T>(T) → T',
|
||||
elementTypeParams: '[T]', typeFormals: '[T]');
|
||||
SimpleIdentifier f = findIdentifier('f');
|
||||
@@ -2276,7 +2279,8 @@ main() {
|
||||
}
|
||||
|
||||
test_genericMethod_functionExpressionInvocation_explicit() async {
|
||||
await resolveTestUnit(r'''
|
||||
await resolveTestUnit(
|
||||
r'''
|
||||
class C<E> {
|
||||
/*=T*/ f/*<T>*/(/*=T*/ e) => null;
|
||||
static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
|
||||
@@ -2298,7 +2302,9 @@ void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
|
||||
var localCall = (lf)/*<int>*/(3);
|
||||
var paramCall = (pf)/*<int>*/(3);
|
||||
}
|
||||
''');
|
||||
''',
|
||||
noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
|
||||
);
|
||||
expectIdentifierType('methodCall', "int");
|
||||
expectIdentifierType('staticCall', "int");
|
||||
expectIdentifierType('staticFieldCall', "int");
|
||||
@@ -2310,7 +2316,8 @@ void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
|
||||
}
|
||||
|
||||
test_genericMethod_functionExpressionInvocation_inferred() async {
|
||||
await resolveTestUnit(r'''
|
||||
await resolveTestUnit(
|
||||
r'''
|
||||
class C<E> {
|
||||
/*=T*/ f/*<T>*/(/*=T*/ e) => null;
|
||||
static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
|
||||
@@ -2332,7 +2339,9 @@ void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
|
||||
var localCall = (lf)(3);
|
||||
var paramCall = (pf)(3);
|
||||
}
|
||||
''');
|
||||
''',
|
||||
noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
|
||||
);
|
||||
expectIdentifierType('methodCall', "int");
|
||||
expectIdentifierType('staticCall', "int");
|
||||
expectIdentifierType('staticFieldCall', "int");
|
||||
@@ -2344,7 +2353,8 @@ void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
|
||||
}
|
||||
|
||||
test_genericMethod_functionInvocation_explicit() async {
|
||||
await resolveTestUnit(r'''
|
||||
await resolveTestUnit(
|
||||
r'''
|
||||
class C<E> {
|
||||
/*=T*/ f/*<T>*/(/*=T*/ e) => null;
|
||||
static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
|
||||
@@ -2364,7 +2374,9 @@ void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
|
||||
var localCall = lf/*<int>*/(3);
|
||||
var paramCall = pf/*<int>*/(3);
|
||||
}
|
||||
''');
|
||||
''',
|
||||
noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
|
||||
);
|
||||
expectIdentifierType('methodCall', "int");
|
||||
expectIdentifierType('staticCall', "int");
|
||||
expectIdentifierType('staticFieldCall', "int");
|
||||
@@ -2375,7 +2387,8 @@ void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
|
||||
}
|
||||
|
||||
test_genericMethod_functionInvocation_inferred() async {
|
||||
await resolveTestUnit(r'''
|
||||
await resolveTestUnit(
|
||||
r'''
|
||||
class C<E> {
|
||||
/*=T*/ f/*<T>*/(/*=T*/ e) => null;
|
||||
static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
|
||||
@@ -2395,7 +2408,9 @@ void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
|
||||
var localCall = lf(3);
|
||||
var paramCall = pf(3);
|
||||
}
|
||||
''');
|
||||
''',
|
||||
noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
|
||||
);
|
||||
expectIdentifierType('methodCall', "int");
|
||||
expectIdentifierType('staticCall', "int");
|
||||
expectIdentifierType('staticFieldCall', "int");
|
||||
@@ -2640,7 +2655,8 @@ C toSpan(dynamic element) {
|
||||
}
|
||||
|
||||
test_genericMethod_tearoff() async {
|
||||
await resolveTestUnit(r'''
|
||||
await resolveTestUnit(
|
||||
r'''
|
||||
class C<E> {
|
||||
/*=T*/ f/*<T>*/(E e) => null;
|
||||
static /*=T*/ g/*<T>*/(/*=T*/ e) => null;
|
||||
@@ -2660,7 +2676,9 @@ void test/*<S>*/(/*=T*/ pf/*<T>*/(/*=T*/ e)) {
|
||||
var localTearOff = lf;
|
||||
var paramTearOff = pf;
|
||||
}
|
||||
''');
|
||||
''',
|
||||
noErrors: false // TODO(paulberry): remove when dartbug.com/28515 fixed.
|
||||
);
|
||||
expectIdentifierType('methodTearOff', "<T>(int) → T");
|
||||
expectIdentifierType('staticTearOff', "<T>(T) → T");
|
||||
expectIdentifierType('staticFieldTearOff', "<T>(T) → T");
|
||||
|
||||
@@ -2534,6 +2534,7 @@ import 'package:crypto/crypto.dart';
|
||||
_assertNoExceptions();
|
||||
}
|
||||
|
||||
@failingTest // TODO(paulberry): Remove the annotation when dartbug.com/28515 is fixed.
|
||||
void test_resolveCompilationUnit_existingElementModel() {
|
||||
prepareAnalysisContext(new AnalysisOptionsImpl()..strongMode = true);
|
||||
Source source = addSource(
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
[ $compiler == dart2analyzer ]
|
||||
|
||||
generic_methods_generic_function_parameter_test: CompileTimeError # Issue 28515
|
||||
generic_local_functions_test: CompileTimeError # Issue 28515
|
||||
|
||||
regress_26668_test: Fail # Issue 26678
|
||||
regress_27617_test/1: MissingCompileTimeError
|
||||
|
||||
|
||||
Reference in New Issue
Block a user