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:
Paul Berry
2017-01-29 07:35:03 -08:00
parent 4974b71709
commit c9b692e8d9
8 changed files with 145 additions and 46 deletions
+1
View File
@@ -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,
+16
View File
@@ -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(
+3
View File
@@ -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