From 873ecfd8fd4a5a3f6562242c42d80bdbd24e48b7 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Mon, 30 Aug 2021 17:19:07 +0000 Subject: [PATCH] Suppress redundant tearoff errors when constructor tearoffs not enabled Fixes https://github.com/dart-lang/sdk/issues/47035 Change-Id: I745da785d80744f84e3582727e423e4caed866c0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/211720 Reviewed-by: Brian Wilkerson Commit-Queue: Samuel Rawlins --- .../constructor_reference_resolver.dart | 7 +++++- .../resolver/function_reference_resolver.dart | 14 +++++++---- .../src/dart/resolver/resolution_visitor.dart | 14 +++++++++++ .../constructor_reference_test.dart | 23 ++++++++++++++++++ .../resolution/function_reference_test.dart | 24 +++++++++++++++++++ .../language/constructor/reference_test.dart | 2 -- .../constructor/reference_test.dart | 2 -- 7 files changed, 76 insertions(+), 10 deletions(-) diff --git a/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart index e70c49d59b7..e2a2b97d227 100644 --- a/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart @@ -39,11 +39,16 @@ class ConstructorReferenceResolver { ); } var name = node.constructorName.name; - if (element == null && name != null) { + if (element == null && + name != null && + _resolver.isConstructorTearoffsEnabled) { // The illegal construction, which looks like a type-instantiated // constructor tearoff, may be an attempt to reference a member on // [enclosingElement]. Try to provide a helpful error, and fall back to // "unknown constructor." + // + // Only report errors when the constructor tearoff feature is enabled, + // to avoid reporting redundant errors. var enclosingElement = node.constructorName.type.name.staticElement; if (enclosingElement is TypeAliasElement) { enclosingElement = enclosingElement.aliasedType.element; diff --git a/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart index c1f43c38c5b..223ea61391c 100644 --- a/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/function_reference_resolver.dart @@ -186,11 +186,15 @@ class FunctionReferenceResolver { /// with what the user may be intending. void _resolveDisallowedExpression( FunctionReferenceImpl node, DartType? rawType) { - _errorReporter.reportErrorForNode( - CompileTimeErrorCode.DISALLOWED_TYPE_INSTANTIATION_EXPRESSION, - node.function, - [], - ); + if (_resolver.isConstructorTearoffsEnabled) { + // Only report constructor tearoff-related errors if the constructor + // tearoff feature is enabled. + _errorReporter.reportErrorForNode( + CompileTimeErrorCode.DISALLOWED_TYPE_INSTANTIATION_EXPRESSION, + node.function, + [], + ); + } _resolve(node: node, rawType: rawType); } diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart index fd3bdeb0310..9efde388349 100644 --- a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart +++ b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart @@ -761,6 +761,20 @@ class ResolutionVisitor extends RecursiveAstVisitor { void visitInstanceCreationExpression(InstanceCreationExpression node) { var newNode = _astRewriter.instanceCreationExpression(_nameScope, node); if (newNode != node) { + if (node.constructorName.type.typeArguments != null && + newNode is MethodInvocation && + newNode.target is FunctionReference && + !_libraryElement.featureSet.isEnabled(Feature.constructor_tearoffs)) { + // A function reference with explicit type arguments (an expression of + // the form `a<...>.m(...)` or `p.a<...>.m(...)` where `a` does not + // refer to a class name, nor a type alias), is illegal without the + // constructor tearoff feature. + // + // This is a case where the parser does not report an error, because the + // parser thinks this could be an InstanceCreationExpression. + _errorReporter.reportErrorForNode( + HintCode.SDK_VERSION_CONSTRUCTOR_TEAROFFS, node, []); + } return newNode.accept(this); } diff --git a/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart b/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart index 087615af9b5..1efe8b92dc6 100644 --- a/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart +++ b/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart @@ -805,6 +805,29 @@ bar() { @reflectiveTest class ConstructorReferenceResolutionWithoutConstructorTearoffsTest extends PubPackageResolutionTest with WithoutConstructorTearoffsMixin { + test_class_generic_nonConstructor() async { + await assertErrorsInCode(''' +class A { + static int i = 1; +} + +void bar() { + A.i; +} +''', [ + error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 52, 5), + ]); + + var classElement = findElement.class_('A'); + assertConstructorReference( + findNode.constructorReference('A.i;'), + null, + classElement, + 'dynamic', + expectedTypeNameType: 'A', + ); + } + test_constructorTearoff() async { await assertErrorsInCode(''' class A { diff --git a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart index 9a4bed50ccc..0674a5adad6 100644 --- a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart +++ b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart @@ -2,6 +2,7 @@ // 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/dart/error/syntactic_errors.dart'; import 'package:analyzer/src/error/codes.dart'; import 'package:test_reflective_loader/test_reflective_loader.dart'; @@ -10,6 +11,8 @@ import 'context_collection_resolution.dart'; main() { defineReflectiveSuite(() { defineReflectiveTests(FunctionReferenceResolutionTest); + defineReflectiveTests( + FunctionReferenceResolutionWithoutConstructorTearoffsTest); }); } @@ -996,3 +999,24 @@ void bar() { findNode.functionReference('foo;'), null, 'dynamic'); } } + +@reflectiveTest +class FunctionReferenceResolutionWithoutConstructorTearoffsTest + extends PubPackageResolutionTest with WithoutConstructorTearoffsMixin { + test_localVariable() async { + // This code includes a disallowed type instantiation (local variable), + // but in the case that the experiment is not enabled, we suppress the + // associated error. + await assertErrorsInCode(''' +void bar(void Function(T a) foo) { + foo; +} +''', [ + error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 43, 5), + ]); + + var reference = findNode.functionReference('foo;'); + assertFunctionReference( + reference, findElement.parameter('foo'), 'void Function(int)'); + } +} diff --git a/tests/language/constructor/reference_test.dart b/tests/language/constructor/reference_test.dart index 0a7cb379318..f2821562832 100644 --- a/tests/language/constructor/reference_test.dart +++ b/tests/language/constructor/reference_test.dart @@ -100,8 +100,6 @@ main() { // ^^^^^ // [analyzer] COMPILE_TIME_ERROR.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR Foo.bar.baz(); -//^^^^^^^ -// [analyzer] COMPILE_TIME_ERROR.DISALLOWED_TYPE_INSTANTIATION_EXPRESSION // ^ // [cfe] Couldn't find constructor 'bar'. // ^^^ diff --git a/tests/language_2/constructor/reference_test.dart b/tests/language_2/constructor/reference_test.dart index 776fe8b51fe..658781b3766 100644 --- a/tests/language_2/constructor/reference_test.dart +++ b/tests/language_2/constructor/reference_test.dart @@ -102,8 +102,6 @@ main() { // ^^^^^ // [analyzer] COMPILE_TIME_ERROR.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR Foo.bar.baz(); -//^^^^^^^ -// [analyzer] COMPILE_TIME_ERROR.DISALLOWED_TYPE_INSTANTIATION_EXPRESSION // ^ // [cfe] Couldn't find constructor 'bar'. // ^^^