Remove hack that builds FunctionExpressionInvocation with synthetic arguments.

Now that we have an AST and visitor support for the FunctionReference
structure (which represents `Expression<TypeArguments>` for various
kinds of expressions), we no longer need to error recover this as a
FunctionExpressionInvocation with synthetic arguments.  The resolver
still doesn't resolve the syntax properly, but that's ok because it's
not permitted in valid code (for now we just treat it as having type
`dynamic`).

Fixes #46150.

Change-Id: I357175cc16bcf2f9027be2e1da66bb6ca70a9400
Bug: https://github.com/dart-lang/sdk/issues/46020
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/199682
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Paul Berry 2021-06-01 22:44:45 +00:00 committed by commit-bot@chromium.org
parent 46b04e6c4a
commit b7c6ad117f
9 changed files with 37 additions and 40 deletions

View file

@ -304,6 +304,13 @@ class ExitDetector extends GeneralizingAstVisitor<bool> {
return node.argumentList.accept(this)!;
}
@override
bool visitFunctionReference(FunctionReference node) {
// Note: `node.function` could be a reference to a method
// (`Target.methodName`) so we need to visit it in case the target exits.
return node.function.accept(this)!;
}
@override
bool visitGenericFunctionType(GenericFunctionType node) => false;

View file

@ -3532,14 +3532,6 @@ class AstBuilder extends StackListener {
typeArguments.leftBracket,
typeArguments.rightBracket,
);
// Since analyzer visitors don't yet support constructor tear-offs, create
// a FunctionExpressionInvocation with a synthetic argument list instead.
// TODO(paulberry): once we have visitor support for constructor
// tear-offs, fall through and return a FunctionReference instead since
// that should lead to better quality error recovery.
push(ast.functionExpressionInvocation(receiver, typeArguments,
_syntheticArgumentList(typeArguments.rightBracket)));
return;
}
push(ast.functionReference(
function: receiver, typeArguments: typeArguments));

View file

@ -163,6 +163,12 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<void> {
@override
void visitFunctionExpression(FunctionExpression node) {}
@override
void visitFunctionReference(covariant FunctionReferenceImpl node) {
// TODO(paulberry): implement
node.staticType = _dynamicType;
}
/// The Dart Language Specification, 12.11.1: <blockquote>The static type of a new expression of
/// either the form <i>new T.id(a<sub>1</sub>, &hellip;, a<sub>n</sub>)</i> or the form <i>new
/// T(a<sub>1</sub>, &hellip;, a<sub>n</sub>)</i> is <i>T</i>.</blockquote>

View file

@ -36,23 +36,9 @@ class FunctionReferenceParserTest extends FastaParserTestCase {
}
void test_feature_disabled() {
var expression =
(parseStatement('f<a, b>;', featureSet: preConstructorTearoffs)
as ExpressionStatement)
.expression;
// TODO(paulberry): once we have visitor support for FunctionReference, this
// should be parsed as a FunctionReference, so we should be able to validate
// it using `expect_f_a_b`. But for now it's parsed as a
// FunctionExpressionInvocation with synthetic arguments.
var functionExpressionInvocation =
expression as FunctionExpressionInvocation;
expect(
(functionExpressionInvocation.function as SimpleIdentifier).name, 'f');
expect(functionExpressionInvocation.argumentList.arguments, isEmpty);
var typeArgs = functionExpressionInvocation.typeArguments!.arguments;
expect(typeArgs, hasLength(2));
expect(((typeArgs[0] as TypeName).name as SimpleIdentifier).name, 'a');
expect(((typeArgs[1] as TypeName).name as SimpleIdentifier).name, 'b');
expect_f_a_b((parseStatement('f<a, b>;', featureSet: preConstructorTearoffs)
as ExpressionStatement)
.expression);
listener.assertErrors([
expectedError(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 1, 6),
]);

View file

@ -1449,8 +1449,8 @@ var c = Future<int>.sync(() => 3).then<int>((e) => e);
expect(body.expression, isMethodInvocation);
var methodInvocation = body.expression as MethodInvocationImpl;
var target = methodInvocation.target!;
expect(target, isFunctionExpressionInvocation);
expect(target.toSource(), 'C<E>()');
expect(target, isFunctionReference);
expect(target.toSource(), 'C<E>');
expect(methodInvocation.methodName.name, 'n');
expect(methodInvocation.argumentList, isNotNull);
expect(methodInvocation.typeArguments!.arguments, hasLength(1));

View file

@ -2,8 +2,10 @@
// 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/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/dart/resolver/exit_detector.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/test_utilities/find_node.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@ -143,6 +145,11 @@ void f() { // ref
/// See [ExitDetectorResolvedStatementTest] for tests that require the AST to be resolved.
@reflectiveTest
class ExitDetectorParsedStatementTest extends ParseBase {
@override
AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
..contextFeatures = FeatureSet.forTesting(
sdkVersion: '2.13', additionalFeatures: [Feature.constructor_tearoffs]);
test_asExpression() async {
_assertFalse('a as Object;');
}
@ -514,6 +521,18 @@ class ExitDetectorParsedStatementTest extends ParseBase {
_assertTrue("(throw 42)(g);");
}
test_functionReference() async {
_assertFalse('a<int>;');
}
test_functionReference_method() async {
_assertFalse('(a).m<int>;');
}
test_functionReference_method_throw() async {
_assertTrue('(throw 42).m<int>;');
}
test_identifier_prefixedIdentifier() async {
_assertFalse('a.b;');
}

View file

@ -3,7 +3,6 @@
// 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';
import '../dart/resolution/context_collection_resolution.dart';
@ -26,10 +25,6 @@ main() {
Foo<int>.bar.baz();
}
''', [
// TODO(paulberry): the INVOCATION_OF_NON_FUNCTION_EXPRESSION error is
// bogus, and should go away once we implement visitor and resolution
// support for constructor tearoffs.
error(CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, 67, 3),
error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 70, 5),
]);
}
@ -45,10 +40,6 @@ main() {
Foo<int>.bar.baz();
}
''', [
// TODO(paulberry): the INVOCATION_OF_NON_FUNCTION_EXPRESSION error is
// bogus, and should go away once we implement visitor and resolution
// support for constructor tearoffs.
error(CompileTimeErrorCode.INVOCATION_OF_NON_FUNCTION_EXPRESSION, 80, 3),
error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 83, 5),
]);
}

View file

@ -92,8 +92,6 @@ main() {
Foo<int>();
Foo<int>.bar();
Foo<int>.bar.baz();
//^^^
// [analyzer] COMPILE_TIME_ERROR.INVOCATION_OF_NON_FUNCTION_EXPRESSION
// ^^^^^
// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
// [cfe] This requires the 'constructor-tearoffs' language feature to be enabled.

View file

@ -94,8 +94,6 @@ main() {
Foo<int>();
Foo<int>.bar();
Foo<int>.bar.baz();
//^^^
// [analyzer] COMPILE_TIME_ERROR.INVOCATION_OF_NON_FUNCTION_EXPRESSION
// ^^^^^
// [analyzer] SYNTACTIC_ERROR.EXPERIMENT_NOT_ENABLED
// [cfe] This requires the 'constructor-tearoffs' language feature to be enabled.