Version 2.0.0-dev.58.0
Merge commit '88d847ea3e62e4cadc326357a09e5a02a8ad0caf' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e02675e..4d101527 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,5 @@
+## 2.0.0-dev.58.0
+
## 2.0.0-dev.57.0
* Support Javascript Promise APIs as a Dart Future. In Javascript a Promise has two
diff --git a/DEPS b/DEPS
index 204088f..9f020fb 100644
--- a/DEPS
+++ b/DEPS
@@ -110,7 +110,7 @@
"ply_rev": "604b32590ffad5cbb82e4afef1d305512d06ae93",
"pool_tag": "1.3.4",
"protobuf_tag": "0.7.1",
- "pub_rev": "0c172864be2d2043a9d630e07f6b4eae7472653f",
+ "pub_rev": "7bdcf4e4de85a7a8c7a322511b8198f1b6cb0a73",
"pub_semver_tag": "1.4.1",
"quiver_tag": "5aaa3f58c48608af5b027444d561270b53f15dbf",
"resource_rev":"af5a5bf65511943398146cf146e466e5f0b95cb9",
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index 7be888a..e967809 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -23,6 +23,7 @@
import 'package:analyzer/src/generated/bazel.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/gn.dart';
+import 'package:analyzer/src/generated/package_build.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/workspace.dart';
@@ -281,11 +282,13 @@
Workspace createWorkspace(String rootPath) {
if (_hasPackageFileInPath(rootPath)) {
// Bazel workspaces that include package files are treated like normal
- // (non-Bazel) directories.
- return _BasicWorkspace.find(resourceProvider, rootPath, this);
+ // (non-Bazel) directories. But may still use package:build.
+ return PackageBuildWorkspace.find(resourceProvider, rootPath, this) ??
+ _BasicWorkspace.find(resourceProvider, rootPath, this);
}
Workspace workspace = BazelWorkspace.find(resourceProvider, rootPath);
workspace ??= GnWorkspace.find(resourceProvider, rootPath);
+ workspace ??= PackageBuildWorkspace.find(resourceProvider, rootPath, this);
return workspace ?? _BasicWorkspace.find(resourceProvider, rootPath, this);
}
diff --git a/pkg/analyzer/lib/src/fasta/ast_building_factory.dart b/pkg/analyzer/lib/src/fasta/ast_building_factory.dart
index 1f3035f..28b8ae0 100644
--- a/pkg/analyzer/lib/src/fasta/ast_building_factory.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_building_factory.dart
@@ -141,6 +141,45 @@
astFactory.expressionStatement(expression, semicolon);
@override
+ Statement forStatement(
+ Token forKeyword,
+ Token leftParenthesis,
+ covariant variableList,
+ covariant initialization,
+ Token leftSeparator,
+ Expression condition,
+ Token rightSeparator,
+ List<Expression> updaters,
+ Token rightParenthesis,
+ Statement body) =>
+ astFactory.forStatement(
+ forKeyword,
+ leftParenthesis,
+ variableList,
+ initialization,
+ leftSeparator,
+ condition,
+ rightSeparator,
+ updaters,
+ rightParenthesis,
+ body);
+
+ @override
+ Expression getExpressionFromExpressionStatement(Statement statement) =>
+ (statement as ExpressionStatement).expression;
+
+ @override
+ Token getSemicolon(Statement statement) {
+ if (statement is ExpressionStatement) {
+ return statement.semicolon;
+ }
+ if (statement is EmptyStatement) {
+ return statement.semicolon;
+ }
+ return null;
+ }
+
+ @override
kernel.DartType getTypeAt(TypeArgumentList typeArguments, int index) {
return null; // typeArguments.arguments[index].type.kernelType;
}
@@ -166,9 +205,24 @@
elseStatement);
@override
+ Generator<Expression, Statement, _Arguments> indexedAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+ Token token,
+ Expression receiver,
+ Expression index,
+ kernel.Procedure getter,
+ kernel.Procedure setter) {
+ // TODO(brianwilkerson): Implement this.
+ throw new UnimplementedError();
+ }
+
+ @override
bool isBlock(Object node) => node is Block;
@override
+ bool isEmptyStatement(Statement statement) => statement is EmptyStatement;
+
+ @override
bool isErroneousNode(Object node) => false /* ??? */;
@override
@@ -177,6 +231,10 @@
astFactory.isExpression(expression, isOperator, notOperator, type);
@override
+ bool isExpressionStatement(Statement statement) =>
+ statement is ExpressionStatement;
+
+ @override
bool isThisExpression(Object node) => node is ThisExpression;
@override
@@ -280,12 +338,37 @@
..staticType = _typeProvider?.boolType;
@override
+ Generator<Expression, Statement, _Arguments> nullAwarePropertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+ Token token,
+ Expression receiverExpression,
+ kernel.Name name,
+ kernel.Member getter,
+ kernel.Member setter,
+ kernel.DartType type) {
+ // TODO(brianwilkerson): Implement this.
+ throw new UnimplementedError();
+ }
+
+ @override
Object parenthesizedCondition(Token leftParenthesis, Expression expression,
Token rightParenthesis) =>
astFactory.parenthesizedExpression(
leftParenthesis, expression, rightParenthesis);
@override
+ Generator<Expression, Statement, _Arguments> propertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+ Token token,
+ Expression receiver,
+ kernel.Name name,
+ kernel.Member getter,
+ kernel.Member setter) {
+ // TODO(brianwilkerson): Implement this.
+ throw new UnimplementedError();
+ }
+
+ @override
int readOffset(AstNode node) => node.offset;
@override
@@ -319,6 +402,17 @@
astFactory.adjacentStrings(strings.cast<StringLiteral>());
@override
+ Generator<Expression, Statement, _Arguments> superPropertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+ Token token,
+ kernel.Name name,
+ kernel.Member getter,
+ kernel.Member setter) {
+ // TODO(brianwilkerson): Implement this.
+ throw new UnimplementedError();
+ }
+
+ @override
Statement syntheticLabeledStatement(Statement statement) => statement;
@override
@@ -326,6 +420,28 @@
astFactory.thisExpression(thisKeyword);
@override
+ Generator<Expression, Statement, _Arguments> thisIndexedAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+ Token token,
+ Expression index,
+ kernel.Procedure getter,
+ kernel.Procedure setter) {
+ // TODO(brianwilkerson): Implement this.
+ throw new UnimplementedError();
+ }
+
+ @override
+ Generator<Expression, Statement, _Arguments> thisPropertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+ Token location,
+ kernel.Name name,
+ kernel.Member getter,
+ kernel.Member setter) {
+ // TODO(brianwilkerson): Implement this.
+ throw new UnimplementedError();
+ }
+
+ @override
Expression throwExpression(Token throwKeyword, Expression expression) =>
astFactory.throwExpression(throwKeyword, expression);
@@ -352,6 +468,15 @@
variablesDeclaration.variables.variables;
@override
+ Generator<Expression, Statement, _Arguments> variableUseGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, _Arguments> helper,
+ Token token,
+ VariableDeclarationStatement variable,
+ kernel.DartType promotedType) {
+ // TODO(brianwilkerson) Implement this.
+ throw new UnimplementedError();
+ }
+
Statement whileStatement(Token whileKeyword,
ParenthesizedExpression condition, Statement body) =>
astFactory.whileStatement(whileKeyword, condition.leftParenthesis,
diff --git a/pkg/analyzer/lib/src/generated/package_build.dart b/pkg/analyzer/lib/src/generated/package_build.dart
new file mode 100644
index 0000000..96e2dcf
--- /dev/null
+++ b/pkg/analyzer/lib/src/generated/package_build.dart
@@ -0,0 +1,300 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// 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 'dart:collection';
+import 'dart:core';
+
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/file_system/file_system.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/generated/workspace.dart';
+import 'package:analyzer/src/source/package_map_resolver.dart';
+import 'package:package_config/packages.dart';
+import 'package:path/path.dart';
+import 'package:yaml/yaml.dart';
+
+/**
+ * Instances of the class `PackageBuildFileUriResolver` resolve `file` URI's by
+ * first resolving file uri's in the expected way, and then by looking in the
+ * corresponding generated directories.
+ */
+class PackageBuildFileUriResolver extends ResourceUriResolver {
+ final PackageBuildWorkspace workspace;
+
+ PackageBuildFileUriResolver(PackageBuildWorkspace workspace)
+ : workspace = workspace,
+ super(workspace.provider);
+
+ @override
+ Source resolveAbsolute(Uri uri, [Uri actualUri]) {
+ if (!ResourceUriResolver.isFileUri(uri)) {
+ return null;
+ }
+ String path = provider.pathContext.fromUri(uri);
+ File file = workspace.findFile(path);
+ if (file != null) {
+ return file.createSource(actualUri ?? uri);
+ }
+ return null;
+ }
+}
+
+/**
+ * The [UriResolver] that can resolve `package` URIs in [PackageBuildWorkspace].
+ */
+class PackageBuildPackageUriResolver extends UriResolver {
+ final PackageBuildWorkspace _workspace;
+ final UriResolver _normalUriResolver;
+ final Context _context;
+
+ /**
+ * The cache of absolute [Uri]s to [Source]s mappings.
+ */
+ final Map<Uri, Source> _sourceCache = new HashMap<Uri, Source>();
+
+ PackageBuildPackageUriResolver(
+ PackageBuildWorkspace workspace, this._normalUriResolver)
+ : _workspace = workspace,
+ _context = workspace.provider.pathContext;
+
+ @override
+ Source resolveAbsolute(Uri _ignore, [Uri uri]) {
+ uri ??= _ignore;
+ return _sourceCache.putIfAbsent(uri, () {
+ if (uri.scheme != 'package') {
+ return null;
+ }
+
+ Source basicResolverSource = _normalUriResolver.resolveAbsolute(uri);
+ if (basicResolverSource != null && basicResolverSource.exists()) {
+ return basicResolverSource;
+ }
+
+ String uriPath = uri.path;
+ int slash = uriPath.indexOf('/');
+
+ // If the path either starts with a slash or has no slash, it is invalid.
+ if (slash < 1) {
+ return null;
+ }
+
+ String packageName = uriPath.substring(0, slash);
+ String fileUriPart = uriPath.substring(slash + 1);
+ String filePath = fileUriPart.replaceAll('/', _context.separator);
+
+ File file = _workspace.builtFile(
+ _workspace.builtPackageSourcePath(filePath), packageName);
+ if (file != null && file.exists) {
+ return file.createSource(uri);
+ }
+ return basicResolverSource;
+ });
+ }
+
+ @override
+ Uri restoreAbsolute(Source source) {
+ Context context = _workspace.provider.pathContext;
+ String path = source.fullName;
+
+ if (context.isWithin(_workspace.root, path)) {
+ String relative = context.relative(path, from: _workspace.root);
+ List<String> components = context.split(relative);
+ if (components.length > 4 &&
+ components[0] == 'build' &&
+ components[1] == 'generated' &&
+ components[3] == 'lib') {
+ String packageName = components[2];
+ String pathInLib = components.skip(4).join('/');
+ return Uri.parse('package:$packageName/$pathInLib');
+ }
+ }
+ return source.uri;
+ }
+}
+
+/**
+ * Information about a package:build workspace.
+ */
+class PackageBuildWorkspace extends Workspace {
+ /**
+ * The name of the directory that identifies the root of the workspace. Note,
+ * the presence of this file does not show package:build is used. For that,
+ * the subdirectory [_dartToolBuildName] must exist. A `pub` subdirectory
+ * will usually exist in non-package:build projects too.
+ */
+ static const String _dartToolRootName = '.dart_tool';
+
+ /**
+ * The name of the subdirectory in [_dartToolName] that distinguishes projects
+ * built with package:build.
+ */
+ static const String _dartToolBuildName = 'build';
+
+ /**
+ * We use pubspec.yaml to get the package name to be consistent with how
+ * package:build does it.
+ */
+ static const String _pubspecName = 'pubspec.yaml';
+
+ /**
+ * The resource provider used to access the file system.
+ */
+ final ResourceProvider provider;
+
+ /**
+ * The absolute workspace root path (the directory containing the `.dart_tool`
+ * directory).
+ */
+ final String root;
+
+ /**
+ * The name of the package under development as defined in pubspec.yaml. This
+ * matches the behavior of package:build.
+ */
+ final String projectPackageName;
+
+ final ContextBuilder _builder;
+
+ /**
+ * The map of package locations indexed by package name.
+ *
+ * This is a cached field.
+ */
+ Map<String, List<Folder>> _packageMap;
+
+ /**
+ * The package location strategy.
+ *
+ * This is a cached field.
+ */
+ Packages _packages;
+
+ PackageBuildWorkspace._(
+ this.provider, this.root, this.projectPackageName, this._builder);
+
+ @override
+ Map<String, List<Folder>> get packageMap {
+ _packageMap ??= _builder.convertPackagesToMap(packages);
+ return _packageMap;
+ }
+
+ Packages get packages {
+ _packages ??= _builder.createPackageMap(root);
+ return _packages;
+ }
+
+ @override
+ UriResolver get packageUriResolver => new PackageBuildPackageUriResolver(
+ this, new PackageMapUriResolver(provider, packageMap));
+
+ /**
+ * For some package file, which may or may not be a package source (it could
+ * be in `bin/`, `web/`, etc), find where its built counterpart will exist if
+ * its a generated source.
+ *
+ * To get a [builtPath] for a package source file to use in this method,
+ * use [builtPackageSourcePath]. For `bin/`, `web/`, etc, it must be relative
+ * to the project root.
+ */
+ File builtFile(String builtPath, String packageName) {
+ if (!packageMap.containsKey(packageName)) {
+ return null;
+ }
+ String path = context.join(
+ root, _dartToolRootName, 'build', 'generated', packageName, builtPath);
+ return provider.getFile(path);
+ }
+
+ /**
+ * Unlike the way that sources are resolved against `.packages` (if foo points
+ * to folder bar, then `foo:baz.dart` is found at `bar/baz.dart`), the built
+ * sources for a package require the `lib/` prefix first. This is because
+ * `bin/`, `web/`, and `test/` etc can all be built as well. This method
+ * exists to give a name to that prefix processing step.
+ */
+ String builtPackageSourcePath(String path) {
+ assert(context.isRelative(path));
+ return context.join('lib', path);
+ }
+
+ @override
+ SourceFactory createSourceFactory(DartSdk sdk) {
+ List<UriResolver> resolvers = <UriResolver>[];
+ if (sdk != null) {
+ resolvers.add(new DartUriResolver(sdk));
+ }
+ resolvers.add(packageUriResolver);
+ resolvers.add(new PackageBuildFileUriResolver(this));
+ return new SourceFactory(resolvers, packages, provider);
+ }
+
+ /**
+ * Return the file with the given [path], looking first into directories for
+ * source files, and then in the generated directory
+ * `.dart_tool/build/generated/$projectPackageName/$FILE`. The file in the
+ * workspace root is returned even if it does not exist. Return `null` if the
+ * given [path] is not in the workspace [root].
+ */
+ File findFile(String path) {
+ assert(context.isAbsolute(path));
+ try {
+ final String builtPath = context.relative(path, from: root);
+ final File file = builtFile(builtPath, projectPackageName);
+
+ if (file.exists) {
+ return file;
+ }
+
+ return provider.getFile(path);
+ } catch (_) {
+ return null;
+ }
+ }
+
+ /**
+ * Find the package:build workspace that contains the given [path].
+ *
+ * Return `null` if the path is not in a package:build workspace.
+ */
+ static PackageBuildWorkspace find(
+ ResourceProvider provider, String path, ContextBuilder builder) {
+ Context context = provider.pathContext;
+
+ // Ensure that the path is absolute and normalized.
+ if (!context.isAbsolute(path)) {
+ throw new ArgumentError('Not an absolute path: $path');
+ }
+ path = context.normalize(path);
+
+ Folder folder = provider.getFolder(path);
+ while (true) {
+ Folder parent = folder.parent;
+ if (parent == null) {
+ return null;
+ }
+
+ final File pubspec = folder.getChildAssumingFile(_pubspecName);
+ final Folder dartToolDir =
+ folder.getChildAssumingFolder(_dartToolRootName);
+ final Folder dartToolBuildDir =
+ dartToolDir.getChildAssumingFolder(_dartToolBuildName);
+
+ // Found the .dart_tool file, that's our project root. We also require a
+ // pubspec, to know the package name that package:build will assume.
+ if (dartToolBuildDir.exists && pubspec.exists) {
+ try {
+ final yaml = loadYaml(pubspec.readAsStringSync());
+ return new PackageBuildWorkspace._(
+ provider, folder.path, yaml['name'], builder);
+ } on Exception {}
+ }
+
+ // Go up the folder.
+ folder = parent;
+ }
+ }
+}
diff --git a/pkg/analyzer/test/generated/package_build_test.dart b/pkg/analyzer/test/generated/package_build_test.dart
new file mode 100644
index 0000000..1b2dedd
--- /dev/null
+++ b/pkg/analyzer/test/generated/package_build_test.dart
@@ -0,0 +1,479 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// 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/file_system/file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/generated/package_build.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:mockito/mockito.dart';
+import 'package:package_config/packages.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(PackageBuildFileUriResolverTest);
+ defineReflectiveTests(PackageBuildPackageUriResolverTest);
+ defineReflectiveTests(PackageBuildWorkspaceTest);
+ });
+}
+
+class MockContextBuilder extends Mock implements ContextBuilder {}
+
+class MockPackages extends Mock implements Packages {}
+
+class MockUriResolver extends Mock implements UriResolver {}
+
+@reflectiveTest
+class PackageBuildFileUriResolverTest extends _BaseTest {
+ PackageBuildWorkspace workspace;
+ PackageBuildFileUriResolver resolver;
+
+ void setUp() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ final ContextBuilder contextBuilder = new MockContextBuilder();
+ final Packages packages = new MockPackages();
+ when(contextBuilder.createPackageMap(_p('/workspace')))
+ .thenReturn(packages);
+ when(contextBuilder.convertPackagesToMap(packages))
+ .thenReturn({'project': []});
+ workspace =
+ PackageBuildWorkspace.find(provider, _p('/workspace'), contextBuilder);
+ resolver = new PackageBuildFileUriResolver(workspace);
+ provider.newFile(_p('/workspace/test.dart'), '');
+ provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/project/gen.dart'), '');
+ }
+
+ void test_resolveAbsolute_doesNotExist() {
+ Source source = _resolvePath('/workspace/foo.dart');
+ expect(source, isNotNull);
+ expect(source.exists(), isFalse);
+ expect(source.fullName, _p('/workspace/foo.dart'));
+ }
+
+ void test_resolveAbsolute_file() {
+ Source source = _resolvePath('/workspace/test.dart');
+ expect(source, isNotNull);
+ expect(source.exists(), isTrue);
+ expect(source.fullName, _p('/workspace/test.dart'));
+ }
+
+ void test_resolveAbsolute_folder() {
+ Source source = _resolvePath('/workspace');
+ expect(source, isNotNull);
+ expect(source.exists(), isFalse);
+ expect(source.fullName, _p('/workspace'));
+ }
+
+ void test_resolveAbsolute_generated_file_exists_one() {
+ Source source = _resolvePath('/workspace/gen.dart');
+ expect(source, isNotNull);
+ expect(source.exists(), isTrue);
+ expect(source.fullName,
+ _p('/workspace/.dart_tool/build/generated/project/gen.dart'));
+ }
+
+ void test_resolveAbsolute_notFile_dartUri() {
+ Uri uri = new Uri(scheme: 'dart', path: 'core');
+ Source source = resolver.resolveAbsolute(uri);
+ expect(source, isNull);
+ }
+
+ void test_resolveAbsolute_notFile_httpsUri() {
+ Uri uri = new Uri(scheme: 'https', path: '127.0.0.1/test.dart');
+ Source source = resolver.resolveAbsolute(uri);
+ expect(source, isNull);
+ }
+
+ void test_restoreAbsolute() {
+ Uri uri = provider.pathContext.toUri(_p('/workspace/test.dart'));
+ Source source = resolver.resolveAbsolute(uri);
+ expect(source, isNotNull);
+ expect(resolver.restoreAbsolute(source), uri);
+ expect(
+ resolver.restoreAbsolute(
+ new NonExistingSource(source.fullName, null, null)),
+ uri);
+ }
+
+ Source _resolvePath(String absolutePosixPath) {
+ String absolutePath = provider.convertPath(absolutePosixPath);
+ Uri uri = provider.pathContext.toUri(absolutePath);
+ return resolver.resolveAbsolute(uri);
+ }
+}
+
+@reflectiveTest
+class PackageBuildPackageUriResolverTest extends _BaseTest {
+ PackageBuildWorkspace workspace;
+ PackageBuildPackageUriResolver resolver;
+ UriResolver packageUriResolver;
+
+ Uri addPackageSource(String path, String uriStr, {bool create: true}) {
+ Uri uri = Uri.parse(uriStr);
+ final File file =
+ create ? provider.newFile(_p(path), '') : provider.getResource(path);
+ final Source source = file.createSource(uri);
+ when(packageUriResolver.resolveAbsolute(uri)).thenReturn(source);
+ return uri;
+ }
+
+ void setUp() {
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ }
+
+ void test_resolveAbsolute_generated() {
+ _addResources([
+ '/workspace/.dart_tool/build/generated/project/lib/generated_file.dart',
+ ]);
+ final Uri sourceUri = addPackageSource('/workspace/lib/generated_file.dart',
+ 'package:project/generated_file.dart',
+ create: false);
+ _assertResolveUri(sourceUri,
+ '/workspace/.dart_tool/build/generated/project/lib/generated_file.dart',
+ exists: true);
+ }
+
+ void test_resolveAbsolute_null_notPackage() {
+ _addResources([
+ '/workspace/.dart_tool/build/generated',
+ ]);
+ Source source = resolver.resolveAbsolute(Uri.parse('dart:async'));
+ expect(source, isNull);
+ }
+
+ void test_resolveAbsolute_null_startsWithSlash() {
+ _addResources([
+ '/workspace/.dart_tool/build/generated',
+ ]);
+ Source source =
+ resolver.resolveAbsolute(Uri.parse('package:/foo/bar.dart'));
+ expect(source, isNull);
+ }
+
+ void test_resolveAbsolute_source() {
+ _addResources([
+ '/workspace/.dart_tool/build/generated/project/lib/source_file.dart',
+ ]);
+ final Uri sourceUri = addPackageSource(
+ '/workspace/lib/source_file.dart', 'package:project/source_file.dart');
+ _assertResolveUri(sourceUri, '/workspace/lib/source_file.dart',
+ exists: true);
+ }
+
+ void test_resolveAbsolute_workspace_doesNotExist() {
+ _addResources([
+ '/workspace/.dart_tool/build/generated',
+ ]);
+ final Uri sourceUri = addPackageSource(
+ '/workspace/lib/doesNotExist.dart', 'package:project/doesNotExist.dart',
+ create: false);
+ _assertResolveUri(sourceUri, '/workspace/lib/doesNotExist.dart',
+ exists: false);
+ }
+
+ void _addResources(List<String> paths, {String workspacePath: '/workspace'}) {
+ for (String path in paths) {
+ if (path.endsWith('/')) {
+ provider.newFolder(_p(path.substring(0, path.length - 1)));
+ } else {
+ provider.newFile(_p(path), '');
+ }
+ }
+ final contextBuilder = new MockContextBuilder();
+ final packages = new MockPackages();
+ when(contextBuilder.createPackageMap(_p(workspacePath)))
+ .thenReturn(packages);
+ when(contextBuilder.convertPackagesToMap(packages))
+ .thenReturn({'project': []});
+ workspace =
+ PackageBuildWorkspace.find(provider, _p(workspacePath), contextBuilder);
+ packageUriResolver = new MockUriResolver();
+ resolver =
+ new PackageBuildPackageUriResolver(workspace, packageUriResolver);
+ }
+
+ Source _assertResolveUri(Uri uri, String posixPath,
+ {bool exists: true, bool restore: true}) {
+ Source source = resolver.resolveAbsolute(uri);
+ expect(source, isNotNull);
+ expect(source.fullName, _p(posixPath));
+ expect(source.uri, uri);
+ expect(source.exists(), exists);
+ // If enabled, test also "restoreAbsolute".
+ if (restore) {
+ Uri restoredUri = resolver.restoreAbsolute(source);
+ expect(restoredUri.toString(), uri.toString());
+ }
+ return source;
+ }
+}
+
+@reflectiveTest
+class PackageBuildWorkspaceTest extends _BaseTest {
+ void test_builtFile_currentProject() {
+ provider.newFolder(_p('/workspace/.dart_tool/build'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final libFile = provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/project/lib/file.dart'), '');
+ expect(workspace.builtFile('lib/file.dart', 'project'), libFile);
+ }
+
+ void test_builtFile_importedPackage() {
+ provider.newFolder(_p('/workspace/.dart_tool/build'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project', 'foo']);
+
+ final libFile = provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/foo/lib/file.dart'), '');
+ expect(workspace.builtFile('lib/file.dart', 'foo'), libFile);
+ }
+
+ void test_builtFile_notInPackagesGetsHidden() {
+ provider.newFolder(_p('/workspace/.dart_tool/build'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+
+ // Ensure package:bar is not configured.
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project', 'foo']);
+
+ // Create a generated file in package:bar.
+ provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/bar/lib/file.dart'), '');
+
+ // Bar not in packages, file should not be returned.
+ expect(workspace.builtFile('lib/file.dart', 'bar'), isNull);
+ }
+
+ void test_find_fail_notAbsolute() {
+ expect(
+ () => PackageBuildWorkspace.find(
+ provider, _p('not_absolute'), new MockContextBuilder()),
+ throwsArgumentError);
+ }
+
+ void test_find_hasDartToolAndPubspec() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+ provider, _p('/workspace'), new MockContextBuilder());
+ expect(workspace.root, _p('/workspace'));
+ expect(workspace.projectPackageName, 'project');
+ }
+
+ void test_find_hasDartToolAndPubspec_inParentDirectory() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFolder(_p('/workspace/opened/up/a/child/dir/.dart_tool/build'));
+ provider.newFileWithBytes(
+ _p('/workspace/opened/up/a/child/dir/pubspec.yaml'),
+ 'name: subproject'.codeUnits);
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(provider,
+ _p('/workspace/opened/up/a/child/dir'), new MockContextBuilder());
+ expect(workspace.root, _p('/workspace/opened/up/a/child/dir'));
+ expect(workspace.projectPackageName, 'subproject');
+ }
+
+ void
+ test_find_hasDartToolAndPubspec_inParentDirectory_ignoresMalformedPubspec() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFolder(_p('/workspace/opened/up/a/child/dir/.dart_tool/build'));
+ provider.newFileWithBytes(
+ _p('/workspace/opened/up/a/child/dir/pubspec.yaml'),
+ 'not: yaml: here!!! 111'.codeUnits);
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(provider,
+ _p('/workspace/opened/up/a/child/dir'), new MockContextBuilder());
+ expect(workspace.root, _p('/workspace'));
+ expect(workspace.projectPackageName, 'project');
+ }
+
+ void test_find_hasDartToolAndPubspec_inParentDirectory_ignoresSoloDartTool() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFolder(_p('/workspace/opened/up/a/child/dir'));
+ provider.newFolder(_p('/workspace/opened/up/a/child/dir/.dart_tool/build'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(provider,
+ _p('/workspace/opened/up/a/child/dir'), new MockContextBuilder());
+ expect(workspace.root, _p('/workspace'));
+ expect(workspace.projectPackageName, 'project');
+ }
+
+ void test_find_hasDartToolAndPubspec_inParentDirectory_ignoresSoloPubspec() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFolder(_p('/workspace/opened/up/a/child/dir'));
+ provider.newFileWithBytes(
+ _p('/workspace/opened/up/a/child/dir/pubspec.yaml'),
+ 'name: subproject'.codeUnits);
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(provider,
+ _p('/workspace/opened/up/a/child/dir'), new MockContextBuilder());
+ expect(workspace.root, _p('/workspace'));
+ expect(workspace.projectPackageName, 'project');
+ }
+
+ void test_find_hasDartToolNoBuild() {
+ // Edge case: an empty .dart_tool directory. Don't assume package:build.
+ provider.newFolder(_p('/workspace/.dart_tool'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+ provider, _p('/workspace'), new MockContextBuilder());
+ expect(workspace, isNull);
+ }
+
+ void test_find_hasDartToolNoPubspec() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+ provider, _p('/workspace'), new MockContextBuilder());
+ expect(workspace, isNull);
+ }
+
+ void test_find_hasDartToolPubButNotBuild() {
+ // Dart projects will have this directory, that don't use package:build.
+ provider.newFolder(_p('/workspace/.dart_tool/pub'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+ provider, _p('/workspace'), new MockContextBuilder());
+ expect(workspace, isNull);
+ }
+
+ void test_find_hasMalformedPubspec() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'not: yaml: here! 1111'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+ provider, _p('/workspace'), new MockContextBuilder());
+ expect(workspace, isNull);
+ }
+
+ void test_find_hasPubspecNoDartTool() {
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace = PackageBuildWorkspace.find(
+ provider, _p('/workspace'), new MockContextBuilder());
+ expect(workspace, isNull);
+ }
+
+ void test_findFile_bin() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/bin'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final binFile = provider.newFile(_p('/workspace/bin/file.dart'), '');
+ expect(workspace.findFile('/workspace/bin/file.dart'), binFile);
+ }
+
+ void test_findFile_binGenerated() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/bin'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final binFile = provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/project/bin/file.dart'), '');
+ expect(workspace.findFile('/workspace/bin/file.dart'), binFile);
+ }
+
+ void test_findFile_libGenerated() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/lib'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final libFile = provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/project/lib/file.dart'), '');
+ expect(workspace.findFile('/workspace/lib/file.dart'), libFile);
+ }
+
+ void test_findFile_test() {
+ provider
+ .newFolder(_p('/workspace/.dart_tool/build/generated/project/test'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final testFile = provider.newFile(_p('/workspace/test/file.dart'), '');
+ expect(workspace.findFile('/workspace/test/file.dart'), testFile);
+ }
+
+ void test_findFile_testGenerated() {
+ provider
+ .newFolder(_p('/workspace/.dart_tool/build/generated/project/test'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final testFile = provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/project/test/file.dart'), '');
+ expect(workspace.findFile('/workspace/test/file.dart'), testFile);
+ }
+
+ void test_findFile_web() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/web'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final webFile = provider.newFile(_p('/workspace/web/file.dart'), '');
+ expect(workspace.findFile('/workspace/web/file.dart'), webFile);
+ }
+
+ void test_findFile_webGenerated() {
+ provider.newFolder(_p('/workspace/.dart_tool/build/generated/project/web'));
+ provider.newFileWithBytes(
+ _p('/workspace/pubspec.yaml'), 'name: project'.codeUnits);
+ PackageBuildWorkspace workspace =
+ _createWorkspace('/workspace', ['project']);
+
+ final webFile = provider.newFile(
+ _p('/workspace/.dart_tool/build/generated/project/web/file.dart'), '');
+ expect(workspace.findFile('/workspace/web/file.dart'), webFile);
+ }
+
+ PackageBuildWorkspace _createWorkspace(
+ String root, List<String> packageNames) {
+ final contextBuilder = new MockContextBuilder();
+ final packages = new MockPackages();
+ final packageMap = new Map.fromIterable(packageNames, value: ((_) => []));
+ when(contextBuilder.createPackageMap(_p(root))).thenReturn(packages);
+ when(contextBuilder.convertPackagesToMap(packages)).thenReturn(packageMap);
+ when(packages.asMap()).thenReturn(packageMap);
+ return PackageBuildWorkspace.find(provider, _p(root), contextBuilder);
+ }
+}
+
+class _BaseTest {
+ final MemoryResourceProvider provider = new MemoryResourceProvider();
+
+ /**
+ * Return the [provider] specific path for the given Posix [path].
+ */
+ String _p(String path) => provider.convertPath(path);
+}
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 56f90ba..7b529d3 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -4495,12 +4495,12 @@
// being reported in code that cannot actually be reached), but that hasn't
// been proven yet.
createParser('(int a, int b ;',
- expectedEndOffset: 0 /* ErrorToken at end of token stream */);
+ expectedEndOffset: 14 /* ErrorToken at end of token stream */);
FormalParameterList list = parser.parseFormalParameterList();
expectNotNullIfNoErrors(list);
if (usingFastaParser) {
- listener
- .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 14, 1)]);
+ // Fasta scanner reports missing `)` error
+ listener.assertNoErrors();
} else if (fe.Scanner.useFasta) {
listener.errors
.contains(expectedError(ParserErrorCode.EXPECTED_TOKEN, 14, 1));
diff --git a/pkg/analyzer/test/src/fasta/recovery/partial_code/method_declaration_test.dart b/pkg/analyzer/test/src/fasta/recovery/partial_code/method_declaration_test.dart
index a2c8624..aacff92 100644
--- a/pkg/analyzer/test/src/fasta/recovery/partial_code/method_declaration_test.dart
+++ b/pkg/analyzer/test/src/fasta/recovery/partial_code/method_declaration_test.dart
@@ -12,6 +12,15 @@
class MethodTest extends PartialCodeTest {
buildAll() {
+ const allExceptEof = const [
+ 'field',
+ 'fieldConst',
+ 'fieldFinal',
+ 'methodNonVoid',
+ 'methodVoid',
+ 'getter',
+ 'setter'
+ ];
buildTests(
'method_declaration',
[
@@ -21,44 +30,52 @@
new TestDescriptor(
'noType_leftParen',
'm(',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'm();',
- allFailing: true,
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'm() {}',
+ failing: allExceptEof,
),
new TestDescriptor(
'noType_paramName',
'm(B',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'm(B);',
- allFailing: true,
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'm(B) {}',
+ failing: ['methodNonVoid', 'getter', 'setter'],
),
new TestDescriptor(
- 'noType_paramTypeAndName',
- 'm(B b',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'm(B b);',
- allFailing: true,
- ),
+ 'noType_paramTypeAndName',
+ 'm(B b',
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'm(B b) {}'),
new TestDescriptor(
'noType_paramAndComma',
'm(B b,',
- [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN],
- 'm(B b, _s_);',
- allFailing: true,
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'm(B b) {}',
+ failing: allExceptEof,
),
new TestDescriptor(
'noType_noParams',
'm()',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'm();',
- allFailing: true,
+ [ParserErrorCode.MISSING_FUNCTION_BODY],
+ 'm() {}',
),
new TestDescriptor(
'noType_params',
'm(b, c)',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'm(b, c);',
- allFailing: true,
+ [ParserErrorCode.MISSING_FUNCTION_BODY],
+ 'm(b, c) {}',
),
new TestDescriptor(
'noType_emptyOptional',
@@ -84,44 +101,53 @@
new TestDescriptor(
'type_leftParen',
'A m(',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'A m();',
- allFailing: true,
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'A m() {}',
+ failing: allExceptEof,
),
new TestDescriptor(
'type_paramName',
'A m(B',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'A m(B);',
- allFailing: true,
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'A m(B) {}',
+ failing: ['methodNonVoid', 'getter', 'setter'],
),
new TestDescriptor(
'type_paramTypeAndName',
'A m(B b',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'A m(B b);',
- allFailing: true,
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'A m(B b) {}',
),
new TestDescriptor(
'type_paramAndComma',
'A m(B b,',
- [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN],
- 'A m(B b, _s_);',
- allFailing: true,
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'A m(B b) {}',
+ failing: allExceptEof,
),
new TestDescriptor(
'type_noParams',
'A m()',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'A m();',
- allFailing: true,
+ [ParserErrorCode.MISSING_FUNCTION_BODY],
+ 'A m() {}',
),
new TestDescriptor(
'type_params',
'A m(b, c)',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'A m(b, c);',
- allFailing: true,
+ [ParserErrorCode.MISSING_FUNCTION_BODY],
+ 'A m(b, c) {}',
),
new TestDescriptor(
'type_emptyOptional',
@@ -147,50 +173,53 @@
new TestDescriptor(
'static_noType_leftParen',
'static m(',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'static m();',
- allFailing: true,
- expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'static m() {}',
+ failing: allExceptEof,
),
new TestDescriptor(
'static_noType_paramName',
'static m(B',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'static m(B);',
- allFailing: true,
- expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'static m(B) {}',
+ failing: ['methodNonVoid', 'getter', 'setter'],
),
new TestDescriptor(
'static_noType_paramTypeAndName',
'static m(B b',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'static m(B b);',
- allFailing: true,
- expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'static m(B b) {}',
),
new TestDescriptor(
'static_noType_paramAndComma',
'static m(B b,',
- [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN],
- 'static m(B b, _s_);',
- allFailing: true,
- expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'static m(B b) {}',
+ failing: allExceptEof,
),
new TestDescriptor(
'static_noType_noParams',
'static m()',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'static m();',
- allFailing: true,
- expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+ [ParserErrorCode.MISSING_FUNCTION_BODY],
+ 'static m() {}',
),
new TestDescriptor(
'static_noType_params',
'static m(b, c)',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'static m(b, c);',
- allFailing: true,
- expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+ [ParserErrorCode.MISSING_FUNCTION_BODY],
+ 'static m(b, c) {}',
),
new TestDescriptor(
'static_noType_emptyOptional',
@@ -216,50 +245,53 @@
new TestDescriptor(
'static_type_leftParen',
'static A m(',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'static A m();',
- allFailing: true,
- expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'static A m() {}',
+ failing: allExceptEof,
),
new TestDescriptor(
'static_type_paramName',
'static A m(B',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'static A m(B);',
- allFailing: true,
- expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'static A m(B) {}',
+ failing: ['methodNonVoid', 'getter', 'setter'],
),
new TestDescriptor(
'static_type_paramTypeAndName',
'static A m(B b',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'static A m(B b);',
- allFailing: true,
- expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'static A m(B b) {}',
),
new TestDescriptor(
'static_type_paramAndComma',
'static A m(B b,',
- [ParserErrorCode.MISSING_IDENTIFIER, ParserErrorCode.EXPECTED_TOKEN],
- 'static A m(B b, _s_);',
- allFailing: true,
- expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+ [
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_FUNCTION_BODY
+ ],
+ 'static A m(B b) {}',
+ failing: allExceptEof,
),
new TestDescriptor(
'static_type_noParams',
'static A m()',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'static A m();',
- allFailing: true,
- expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+ [ParserErrorCode.MISSING_FUNCTION_BODY],
+ 'static A m() {}',
),
new TestDescriptor(
'static_type_params',
'static A m(b, c)',
- [ParserErrorCode.EXPECTED_TOKEN],
- 'static A m(b, c);',
- allFailing: true,
- expectedErrorsInValidCode: [ParserErrorCode.MISSING_FUNCTION_BODY],
+ [ParserErrorCode.MISSING_FUNCTION_BODY],
+ 'static A m(b, c) {}',
),
new TestDescriptor(
'static_type_emptyOptional',
diff --git a/pkg/front_end/lib/src/api_prototype/dependency_grapher.dart b/pkg/front_end/lib/src/api_prototype/dependency_grapher.dart
deleted file mode 100644
index fed5df9..0000000
--- a/pkg/front_end/lib/src/api_prototype/dependency_grapher.dart
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
-// 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 'dart:async';
-
-import 'package:front_end/src/api_prototype/compiler_options.dart';
-import 'package:front_end/src/base/processed_options.dart';
-import 'package:front_end/src/dependency_grapher_impl.dart' as impl;
-
-/// Generates a representation of the dependency graph of a program.
-///
-/// Given the Uri of one or more files, this function follows `import`,
-/// `export`, and `part` declarations to discover a graph of all files involved
-/// in the program.
-Future<Graph> graphForProgram(List<Uri> sources, CompilerOptions options) {
- var processedOptions = new ProcessedOptions(options);
- return impl.graphForProgram(sources, processedOptions);
-}
-
-/// A representation of the dependency graph of a program.
-///
-/// Not intended to be extended, implemented, or mixed in by clients.
-class Graph {
- /// A list of all library cycles in the program, in topologically sorted order
- /// (each cycle only depends on libraries in the cycles that precede it).
- final topologicallySortedCycles = <LibraryCycleNode>[];
-}
-
-/// A representation of a single library cycle in the dependency graph of a
-/// program.
-///
-/// Not intended to be extended, implemented, or mixed in by clients.
-class LibraryCycleNode {
- /// A map of all the libraries in the cycle, keyed by the URI of their
- /// defining compilation unit.
- final libraries = <Uri, LibraryNode>{};
-}
-
-/// A representation of a single library in the dependency graph of a program.
-///
-/// Not intended to be extended, implemented, or mixed in by clients.
-class LibraryNode {
- /// The URI of this library's defining compilation unit.
- final Uri uri;
-
- /// A list of the URIs of all of this library's "part" files.
- final parts = <Uri>[];
-
- /// A list of all the other libraries this library directly depends on.
- final dependencies = <LibraryNode>[];
-
- LibraryNode(this.uri);
-}
diff --git a/pkg/front_end/lib/src/async_dependency_walker.dart b/pkg/front_end/lib/src/async_dependency_walker.dart
deleted file mode 100644
index b0c6535..0000000
--- a/pkg/front_end/lib/src/async_dependency_walker.dart
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
-// 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 'dart:async';
-
-/**
- * An instance of [AsyncDependencyWalker] contains the core algorithms for
- * walking a dependency graph and evaluating nodes in a safe order.
- *
- * Computation of dependencies and evaluation of nodes may be asynchronous.
- */
-abstract class AsyncDependencyWalker<NodeType extends Node<NodeType>> {
- /**
- * Called by [walk] to evaluate a single non-cyclical node, after
- * all that node's dependencies have been evaluated.
- */
- Future<Null> evaluate(NodeType v);
-
- /**
- * Called by [walk] to evaluate a strongly connected component
- * containing one or more nodes. All dependencies of the strongly
- * connected component have been evaluated.
- */
- Future<Null> evaluateScc(List<NodeType> scc);
-
- /**
- * Walk the dependency graph starting at [startingPoint], finding
- * strongly connected components and evaluating them in a safe order
- * by calling [evaluate] and [evaluateScc].
- *
- * This is an implementation of Tarjan's strongly connected
- * components algorithm
- * (https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm).
- *
- * TODO(paulberry): Consider switching to an algorithm that allows
- * dependencies to be computed in parallel, and nodes to be evaluated in
- * parallel.
- */
- Future<Null> walk(NodeType startingPoint) async {
- // TODO(paulberry): consider rewriting in a non-recursive way so
- // that long dependency chains don't cause stack overflow.
-
- // TODO(paulberry): in the event that an exception occurs during
- // the walk, restore the state of the [Node] data structures so
- // that further evaluation will be safe.
-
- // The index which will be assigned to the next node that is
- // freshly visited.
- int index = 1;
-
- // Stack of nodes which have been seen so far and whose strongly
- // connected component is still being determined. Nodes are only
- // popped off the stack when they are evaluated, so sometimes the
- // stack contains nodes that were visited after the current node.
- List<NodeType> stack = <NodeType>[];
-
- Future strongConnect(NodeType node) async {
- bool hasTrivialCycle = false;
-
- // Assign the current node an index and add it to the stack. We
- // haven't seen any of its dependencies yet, so set its lowLink
- // to its index, indicating that so far it is the only node in
- // its strongly connected component.
- node._index = node._lowLink = index++;
- stack.add(node);
-
- // Consider the node's dependencies one at a time.
- var dependencies =
- node._dependencies ??= await node.computeDependencies();
- for (NodeType dependency in dependencies) {
- // If the dependency has already been evaluated, it can't be
- // part of this node's strongly connected component, so we can
- // skip it.
- if (dependency._isEvaluated) {
- continue;
- }
- if (identical(node, dependency)) {
- // If a node includes itself as a dependency, there is no need to
- // explore the dependency further.
- hasTrivialCycle = true;
- } else if (dependency._index == 0) {
- // The dependency hasn't been seen yet, so recurse on it.
- await strongConnect(dependency);
- // If the dependency's lowLink refers to a node that was
- // visited before the current node, that means that the
- // current node, the dependency, and the node referred to by
- // the dependency's lowLink are all part of the same
- // strongly connected component, so we need to update the
- // current node's lowLink accordingly.
- if (dependency._lowLink < node._lowLink) {
- node._lowLink = dependency._lowLink;
- }
- } else {
- // The dependency has already been seen, so it is part of
- // the current node's strongly connected component. If it
- // was visited earlier than the current node's lowLink, then
- // it is a new addition to the current node's strongly
- // connected component, so we need to update the current
- // node's lowLink accordingly.
- if (dependency._index < node._lowLink) {
- node._lowLink = dependency._index;
- }
- }
- }
-
- // If the current node's lowLink is the same as its index, then
- // we have finished visiting a strongly connected component, so
- // pop the stack and evaluate it before moving on.
- if (node._lowLink == node._index) {
- // The strongly connected component has only one node. If there is a
- // cycle, it's a trivial one.
- if (identical(stack.last, node)) {
- stack.removeLast();
- node._isEvaluated = true;
- if (hasTrivialCycle) {
- await evaluateScc(<NodeType>[node]);
- } else {
- await evaluate(node);
- }
- } else {
- // There are multiple nodes in the strongly connected
- // component.
- List<NodeType> scc = <NodeType>[];
- while (true) {
- NodeType otherNode = stack.removeLast();
- scc.add(otherNode);
- otherNode._isEvaluated = true;
- if (identical(otherNode, node)) {
- break;
- }
- }
- await evaluateScc(scc);
- }
- }
- }
-
- // Kick off the algorithm starting with the starting point.
- await strongConnect(startingPoint);
- }
-}
-
-/**
- * Instances of [Node] represent nodes in a dependency graph. The
- * type parameter, [NodeType], is the derived type (this affords some
- * extra type safety by making it difficult to accidentally construct
- * bridges between unrelated dependency graphs).
- */
-abstract class Node<NodeType> {
- /**
- * Index used by Tarjan's strongly connected components algorithm.
- * Zero means the node has not been visited yet; a nonzero value
- * counts the order in which the node was visited.
- */
- int _index = 0;
-
- /**
- * Low link used by Tarjan's strongly connected components
- * algorithm. This represents the smallest [_index] of all the nodes
- * in the strongly connected component to which this node belongs.
- */
- int _lowLink = 0;
-
- List<NodeType> _dependencies;
-
- bool _isEvaluated = false;
-
- /**
- * Compute the dependencies of this node.
- */
- Future<List<NodeType>> computeDependencies();
-}
diff --git a/pkg/front_end/lib/src/dependency_grapher_impl.dart b/pkg/front_end/lib/src/dependency_grapher_impl.dart
deleted file mode 100644
index f22f992..0000000
--- a/pkg/front_end/lib/src/dependency_grapher_impl.dart
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
-// 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 'dart:async';
-
-import 'package:front_end/src/api_prototype/dependency_grapher.dart';
-import 'package:front_end/src/async_dependency_walker.dart';
-import 'package:front_end/src/base/processed_options.dart';
-import 'package:front_end/src/fasta/parser.dart';
-import 'package:front_end/src/fasta/scanner.dart';
-import 'package:front_end/src/fasta/source/directive_listener.dart';
-import 'package:front_end/src/fasta/uri_translator.dart';
-
-/// Generates a representation of the dependency graph of a program.
-///
-/// Given the Uri of one or more files, this function follows `import`,
-/// `export`, and `part` declarations to discover a graph of all files involved
-/// in the program.
-///
-/// If a [fileReader] is supplied, it is used to read file contents; otherwise
-/// they are read directly from `options.fileSystem`.
-///
-/// This is intended for internal use by the front end. Clients should use
-/// package:front_end/src/api_prototype/dependency_grapher.dart.
-Future<Graph> graphForProgram(List<Uri> sources, ProcessedOptions options,
- {FileReader fileReader}) async {
- UriTranslator uriTranslator = await options.getUriTranslator();
- fileReader ??= (originalUri, resolvedUri) =>
- options.fileSystem.entityForUri(resolvedUri).readAsString();
- var walker = new _Walker(fileReader, uriTranslator, options.compileSdk);
- var startingPoint = new _StartingPoint(walker, sources);
- await walker.walk(startingPoint);
- return walker.graph;
-}
-
-/// Type of the callback function used by [graphForProgram] to read file
-/// contents.
-typedef Future<String> FileReader(Uri originalUri, Uri resolvedUri);
-
-class _StartingPoint extends _WalkerNode {
- final List<Uri> sources;
-
- _StartingPoint(_Walker walker, this.sources) : super(walker, null);
-
- @override
- Future<List<_WalkerNode>> computeDependencies() async =>
- sources.map(walker.nodeForUri).toList();
-}
-
-class _Walker extends AsyncDependencyWalker<_WalkerNode> {
- final FileReader fileReader;
- final UriTranslator uriTranslator;
- final _nodesByUri = <Uri, _WalkerNode>{};
- final graph = new Graph();
- final bool compileSdk;
-
- _Walker(this.fileReader, this.uriTranslator, this.compileSdk);
-
- @override
- Future<Null> evaluate(_WalkerNode v) {
- if (v is _StartingPoint) return new Future.value();
- return evaluateScc([v]);
- }
-
- @override
- Future<Null> evaluateScc(List<_WalkerNode> scc) {
- var cycle = new LibraryCycleNode();
- for (var walkerNode in scc) {
- cycle.libraries[walkerNode.uri] = walkerNode.library;
- }
- graph.topologicallySortedCycles.add(cycle);
- return new Future.value();
- }
-
- _WalkerNode nodeForUri(Uri referencedUri) {
- var dependencyNode = _nodesByUri.putIfAbsent(
- referencedUri, () => new _WalkerNode(this, referencedUri));
- return dependencyNode;
- }
-}
-
-class _WalkerNode extends Node<_WalkerNode> {
- static final dartCoreUri = Uri.parse('dart:core');
- final _Walker walker;
- final Uri uri;
- final LibraryNode library;
-
- _WalkerNode(this.walker, Uri uri)
- : uri = uri,
- library = new LibraryNode(uri);
-
- @override
- Future<List<_WalkerNode>> computeDependencies() async {
- var dependencies = <_WalkerNode>[];
- // TODO(paulberry): add error recovery if the file can't be read.
- var resolvedUri = uri.scheme == 'dart' || uri.scheme == 'package'
- ? walker.uriTranslator.translate(uri)
- : uri;
- if (resolvedUri == null) {
- // TODO(paulberry): If an error reporter was provided, report the error
- // in the proper way and continue.
- throw new StateError('Invalid URI: $uri');
- }
- var contents = await walker.fileReader(uri, resolvedUri);
- var scannerResults = scanString(contents);
- // TODO(paulberry): report errors.
- var listener = new DirectiveListener();
- new TopLevelParser(listener).parseUnit(scannerResults.tokens);
- bool coreUriFound = false;
- void handleDependency(Uri referencedUri) {
- _WalkerNode dependencyNode = walker.nodeForUri(referencedUri);
- library.dependencies.add(dependencyNode.library);
- if (referencedUri.scheme != 'dart' || walker.compileSdk) {
- dependencies.add(dependencyNode);
- }
- if (referencedUri == dartCoreUri) {
- coreUriFound = true;
- }
- }
-
- for (var part in listener.parts) {
- // TODO(paulberry): when we support SDK libraries, we'll need more
- // complex logic here to find SDK parts correctly.
- library.parts.add(uri.resolve(part));
- }
-
- for (var dep in listener.imports) {
- handleDependency(uri.resolve(dep.uri));
- }
-
- for (var dep in listener.exports) {
- handleDependency(uri.resolve(dep.uri));
- }
-
- if (!coreUriFound) {
- handleDependency(dartCoreUri);
- }
- return dependencies;
- }
-}
diff --git a/pkg/front_end/lib/src/fasta/builder/builder.dart b/pkg/front_end/lib/src/fasta/builder/builder.dart
index 9a49fd8..65fc3cd 100644
--- a/pkg/front_end/lib/src/fasta/builder/builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/builder.dart
@@ -14,8 +14,6 @@
export '../scope.dart' show AccessErrorBuilder, Scope, ScopeBuilder;
-export '../source/unhandled_listener.dart' show Unhandled;
-
export 'builtin_type_builder.dart' show BuiltinTypeBuilder;
export 'class_builder.dart' show ClassBuilder;
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index abcc818..2fc31e8 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -6,6 +6,8 @@
import 'dart:core' hide MapEntry;
+import 'package:kernel/ast.dart' as kernel show Expression, Statement;
+
import '../constant_context.dart' show ConstantContext;
import '../fasta_codes.dart' as fasta;
@@ -19,22 +21,7 @@
import '../modifier.dart' show Modifier, constMask, covariantMask, finalMask;
import '../names.dart'
- show
- ampersandName,
- barName,
- callName,
- caretName,
- divisionName,
- emptyName,
- indexGetName,
- indexSetName,
- leftShiftName,
- minusName,
- multiplyName,
- mustacheName,
- percentName,
- plusName,
- rightShiftName;
+ show callName, emptyName, indexGetName, indexSetName, minusName, plusName;
import '../parser.dart'
show
@@ -85,6 +72,8 @@
import 'expression_generator.dart'
show
DeferredAccessGenerator,
+ DelayedAssignment,
+ DelayedPostfixIncrement,
ErroneousExpressionGenerator,
Generator,
IncompleteErrorGenerator,
@@ -118,8 +107,6 @@
import 'kernel_ast_api.dart' hide Expression, Statement;
-import 'kernel_ast_api.dart' as kernel show Expression, Statement;
-
import 'kernel_builder.dart';
import 'type_algorithms.dart' show calculateBounds;
@@ -325,10 +312,6 @@
Statement popStatement() => forest.wrapVariables(pop());
- void ignore(Unhandled value) {
- pop();
- }
-
void enterSwitchScope() {
push(switchScope ?? NullValue.SwitchScope);
switchScope = scope;
@@ -654,8 +637,11 @@
}
@override
- void finishFunction(List annotations, FormalParameters<Arguments> formals,
- AsyncMarker asyncModifier, kernel.Statement body) {
+ void finishFunction(
+ List annotations,
+ FormalParameters<Expression, Statement, Arguments> formals,
+ AsyncMarker asyncModifier,
+ kernel.Statement body) {
debugEvent("finishFunction");
typePromoter.finished();
@@ -753,7 +739,7 @@
enterLocalScope(
null,
- new FormalParameters<Arguments>(
+ new FormalParameters<Expression, Statement, Arguments>(
parameters.positionalParameters, null, -1)
.computeFormalParameterScope(scope, member, this));
@@ -925,7 +911,8 @@
if (arguments == null) {
push(new IncompletePropertyAccessGenerator(this, beginToken, name));
} else {
- push(new SendAccessGenerator(this, beginToken, name, arguments));
+ push(new SendAccessGenerator(
+ this, beginToken, name, forest.castArguments(arguments)));
}
} else if (arguments == null) {
push(receiver);
@@ -1852,14 +1839,6 @@
Statement body = popStatement();
List<Expression> updates = popListForEffect(updateExpressionCount);
Statement conditionStatement = popStatement();
- kernel.Statement kernelConditionStatement =
- toKernelStatement(conditionStatement);
- Expression condition = null;
- if (kernelConditionStatement is ExpressionStatement) {
- condition = toExpression(kernelConditionStatement.expression);
- } else {
- assert(kernelConditionStatement is EmptyStatement);
- }
dynamic variableOrExpression = pop();
List<VariableDeclaration> variables =
buildVariableDeclarations(variableOrExpression);
@@ -1870,22 +1849,36 @@
exitLocalScope();
JumpTarget continueTarget = exitContinueTarget();
JumpTarget breakTarget = exitBreakTarget();
- kernel.Statement kernelBody = toKernelStatement(body);
if (continueTarget.hasUsers) {
- kernelBody = new ShadowLabeledStatement(kernelBody);
- continueTarget.resolveContinues(forest, kernelBody);
+ body = forest.syntheticLabeledStatement(body);
+ continueTarget.resolveContinues(forest, body);
}
- kernel.Statement result = new ShadowForStatement(
+ Expression condition;
+ Token rightSeparator;
+ if (forest.isExpressionStatement(conditionStatement)) {
+ condition =
+ forest.getExpressionFromExpressionStatement(conditionStatement);
+ rightSeparator = forest.getSemicolon(conditionStatement);
+ } else {
+ assert(forest.isEmptyStatement(conditionStatement));
+ rightSeparator = forest.getSemicolon(conditionStatement);
+ }
+ Statement result = forest.forStatement(
+ forKeyword,
+ leftParen,
variables,
- toKernelExpression(condition),
- toKernelExpressionList(updates),
- kernelBody)
- ..fileOffset = forKeyword.charOffset;
+ variables,
+ leftSeparator,
+ condition,
+ rightSeparator,
+ updates,
+ leftParen.endGroup,
+ body);
if (breakTarget.hasUsers) {
- result = new ShadowLabeledStatement(result);
+ result = forest.syntheticLabeledStatement(result);
breakTarget.resolveBreaks(forest, result);
}
- exitLoopOrSwitch(toStatement(result));
+ exitLoopOrSwitch(result);
}
@override
@@ -2094,7 +2087,7 @@
@override
void endFunctionType(Token functionToken, Token endToken) {
debugEvent("FunctionType");
- FormalParameters<Arguments> formals = pop();
+ FormalParameters<Expression, Statement, Arguments> formals = pop();
DartType returnType = pop();
List<TypeParameter> typeVariables = typeVariableBuildersToKernel(pop());
FunctionType type = formals.toFunctionType(returnType, typeVariables);
@@ -2268,7 +2261,7 @@
if (inCatchClause || functionNestingLevel != 0) {
exitLocalScope();
}
- FormalParameters<Arguments> formals = pop();
+ FormalParameters<Expression, Statement, Arguments> formals = pop();
DartType returnType = pop();
List<TypeParameter> typeVariables = typeVariableBuildersToKernel(pop());
FunctionType type = formals.toFunctionType(returnType, typeVariables);
@@ -2323,8 +2316,8 @@
List<VariableDeclaration> variables =
new List<VariableDeclaration>.filled(count, null, growable: true);
popList(count, variables);
- FormalParameters<Arguments> formals =
- new FormalParameters(variables, optional, beginToken.charOffset);
+ var formals = new FormalParameters<Expression, Statement, Arguments>(
+ variables, optional, beginToken.charOffset);
constantContext = pop();
push(formals);
if ((inCatchClause || functionNestingLevel != 0) &&
@@ -2358,7 +2351,8 @@
if (catchKeyword != null) {
exitLocalScope();
}
- FormalParameters<Arguments> catchParameters = popIfNotNull(catchKeyword);
+ FormalParameters<Expression, Statement, Arguments> catchParameters =
+ popIfNotNull(catchKeyword);
DartType type = popIfNotNull(onKeyword) ?? const DynamicType();
VariableDeclaration exception;
VariableDeclaration stackTrace;
@@ -2421,13 +2415,8 @@
lookupInstanceMember(indexGetName, isSuper: true),
lookupInstanceMember(indexSetName, isSuper: true)));
} else {
- push(IndexedAccessGenerator.make<Arguments>(
- this,
- openSquareBracket,
- toKernelExpression(toValue(receiver)),
- toKernelExpression(index),
- null,
- null));
+ push(IndexedAccessGenerator.make(
+ this, openSquareBracket, toValue(receiver), index, null, null));
}
}
@@ -2492,7 +2481,7 @@
debugEvent("UnaryPostfixAssignmentExpression");
var generator = pop();
if (generator is Generator) {
- push(new DelayedPostfixIncrement<Arguments>(
+ push(new DelayedPostfixIncrement(
this, token, generator, incrementOperator(token), null));
} else {
push(
@@ -2794,7 +2783,7 @@
? wrapInDeferredCheck(expression, deferredPrefix, checkOffset)
: expression);
} else if (type is ErroneousExpressionGenerator) {
- push(type.buildError(arguments));
+ push(type.buildError(forest.castArguments(arguments)));
} else {
push(throwNoSuchMethodError(storeOffset(forest.literalNull(null), offset),
debugName(getNodeName(type), name), arguments, nameToken.charOffset));
@@ -3018,7 +3007,7 @@
Statement body = popStatement();
AsyncMarker asyncModifier = pop();
exitLocalScope();
- FormalParameters<Arguments> formals = pop();
+ FormalParameters<Expression, Statement, Arguments> formals = pop();
var declaration = pop();
var returnType = pop();
var hasImplicitReturnType = returnType == null;
@@ -3115,7 +3104,7 @@
Statement body = popStatement();
AsyncMarker asyncModifier = pop();
exitLocalScope();
- FormalParameters<Arguments> formals = pop();
+ FormalParameters<Expression, Statement, Arguments> formals = pop();
exitFunction();
List<TypeParameter> typeParameters = typeVariableBuildersToKernel(pop());
FunctionNode function = formals.addToFunction(new FunctionNode(
@@ -4209,203 +4198,6 @@
String toString() => "label($name)";
}
-abstract class ContextAwareGenerator<Arguments> extends Generator<Arguments> {
- final Generator generator;
-
- ContextAwareGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- this.generator)
- : super(helper, token);
-
- String get plainNameForRead {
- return unsupported("plainNameForRead", token.charOffset, helper.uri);
- }
-
- kernel.Expression doInvocation(int charOffset, Arguments arguments) {
- return unhandled("${runtimeType}", "doInvocation", charOffset, uri);
- }
-
- kernel.Expression buildSimpleRead();
-
- kernel.Expression buildForEffect();
-
- kernel.Expression buildAssignment(kernel.Expression value,
- {bool voidContext: false}) {
- return makeInvalidWrite(value);
- }
-
- kernel.Expression buildNullAwareAssignment(
- kernel.Expression value, DartType type, int offset,
- {bool voidContext: false}) {
- return makeInvalidWrite(value);
- }
-
- kernel.Expression buildCompoundAssignment(
- Name binaryOperator, kernel.Expression value,
- {int offset: TreeNode.noOffset,
- bool voidContext: false,
- Procedure interfaceTarget,
- bool isPreIncDec: false}) {
- return makeInvalidWrite(value);
- }
-
- kernel.Expression buildPrefixIncrement(Name binaryOperator,
- {int offset: TreeNode.noOffset,
- bool voidContext: false,
- Procedure interfaceTarget}) {
- return makeInvalidWrite(null);
- }
-
- kernel.Expression buildPostfixIncrement(Name binaryOperator,
- {int offset: TreeNode.noOffset,
- bool voidContext: false,
- Procedure interfaceTarget}) {
- return makeInvalidWrite(null);
- }
-
- makeInvalidRead() {
- return unsupported("makeInvalidRead", token.charOffset, helper.uri);
- }
-
- kernel.Expression makeInvalidWrite(kernel.Expression value) {
- return helper.deprecated_buildCompileTimeError(
- "Can't be used as left-hand side of assignment.",
- offsetForToken(token));
- }
-}
-
-class DelayedAssignment<Arguments> extends ContextAwareGenerator<Arguments> {
- final kernel.Expression value;
-
- final String assignmentOperator;
-
- DelayedAssignment(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- Generator generator,
- this.value,
- this.assignmentOperator)
- : super(helper, token, generator);
-
- String get debugName => "DelayedAssignment";
-
- kernel.Expression buildSimpleRead() {
- return handleAssignment(false);
- }
-
- kernel.Expression buildForEffect() {
- return handleAssignment(true);
- }
-
- kernel.Expression handleAssignment(bool voidContext) {
- if (helper.constantContext != ConstantContext.none) {
- return helper.deprecated_buildCompileTimeError(
- "Not a constant expression.", offsetForToken(token));
- }
- if (identical("=", assignmentOperator)) {
- return generator.buildAssignment(value, voidContext: voidContext);
- } else if (identical("+=", assignmentOperator)) {
- return generator.buildCompoundAssignment(plusName, value,
- offset: offsetForToken(token), voidContext: voidContext);
- } else if (identical("-=", assignmentOperator)) {
- return generator.buildCompoundAssignment(minusName, value,
- offset: offsetForToken(token), voidContext: voidContext);
- } else if (identical("*=", assignmentOperator)) {
- return generator.buildCompoundAssignment(multiplyName, value,
- offset: offsetForToken(token), voidContext: voidContext);
- } else if (identical("%=", assignmentOperator)) {
- return generator.buildCompoundAssignment(percentName, value,
- offset: offsetForToken(token), voidContext: voidContext);
- } else if (identical("&=", assignmentOperator)) {
- return generator.buildCompoundAssignment(ampersandName, value,
- offset: offsetForToken(token), voidContext: voidContext);
- } else if (identical("/=", assignmentOperator)) {
- return generator.buildCompoundAssignment(divisionName, value,
- offset: offsetForToken(token), voidContext: voidContext);
- } else if (identical("<<=", assignmentOperator)) {
- return generator.buildCompoundAssignment(leftShiftName, value,
- offset: offsetForToken(token), voidContext: voidContext);
- } else if (identical(">>=", assignmentOperator)) {
- return generator.buildCompoundAssignment(rightShiftName, value,
- offset: offsetForToken(token), voidContext: voidContext);
- } else if (identical("??=", assignmentOperator)) {
- return generator.buildNullAwareAssignment(
- value, const DynamicType(), offsetForToken(token),
- voidContext: voidContext);
- } else if (identical("^=", assignmentOperator)) {
- return generator.buildCompoundAssignment(caretName, value,
- offset: offsetForToken(token), voidContext: voidContext);
- } else if (identical("|=", assignmentOperator)) {
- return generator.buildCompoundAssignment(barName, value,
- offset: offsetForToken(token), voidContext: voidContext);
- } else if (identical("~/=", assignmentOperator)) {
- return generator.buildCompoundAssignment(mustacheName, value,
- offset: offsetForToken(token), voidContext: voidContext);
- } else {
- return unhandled(
- assignmentOperator, "handleAssignment", token.charOffset, helper.uri);
- }
- }
-
- @override
- Initializer buildFieldInitializer(Map<String, int> initializedFields) {
- if (!identical("=", assignmentOperator) ||
- !generator.isThisPropertyAccess) {
- return generator.buildFieldInitializer(initializedFields);
- }
- return helper.buildFieldInitializer(
- false, generator.plainNameForRead, offsetForToken(token), value);
- }
-
- @override
- void printOn(StringSink sink) {
- sink.write(", value: ");
- printNodeOn(value, sink);
- sink.write(", assignmentOperator: ");
- sink.write(assignmentOperator);
- }
-}
-
-class DelayedPostfixIncrement<Arguments>
- extends ContextAwareGenerator<Arguments> {
- final Name binaryOperator;
-
- final Procedure interfaceTarget;
-
- DelayedPostfixIncrement(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- Generator generator,
- this.binaryOperator,
- this.interfaceTarget)
- : super(helper, token, generator);
-
- String get debugName => "DelayedPostfixIncrement";
-
- kernel.Expression buildSimpleRead() {
- return generator.buildPostfixIncrement(binaryOperator,
- offset: offsetForToken(token),
- voidContext: false,
- interfaceTarget: interfaceTarget);
- }
-
- kernel.Expression buildForEffect() {
- return generator.buildPostfixIncrement(binaryOperator,
- offset: offsetForToken(token),
- voidContext: true,
- interfaceTarget: interfaceTarget);
- }
-
- @override
- void printOn(StringSink sink) {
- sink.write(", binaryOperator: ");
- sink.write(binaryOperator.name);
- sink.write(", interfaceTarget: ");
- printQualifiedNameOn(interfaceTarget, sink);
- }
-}
-
class JumpTarget<Statement> extends Builder {
final List<Statement> users = <Statement>[];
@@ -4536,7 +4328,7 @@
OptionalFormals(this.kind, this.formals);
}
-class FormalParameters<Arguments> {
+class FormalParameters<Expression, Statement, Arguments> {
final List<VariableDeclaration> required;
final OptionalFormals optional;
final int charOffset;
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index b644d94..92b3ac2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -10,90 +10,113 @@
import '../constant_context.dart' show ConstantContext;
import '../fasta_codes.dart'
- show
- LocatedMessage,
- messageInvalidInitializer,
- messageLoadLibraryTakesNoArguments,
- messageSuperAsExpression,
- templateDeferredTypeAnnotation,
- templateIntegerLiteralIsOutOfRange,
- templateNotAPrefixInTypeAnnotation,
- templateNotAType,
- templateUnresolvedPrefixInTypeAnnotation;
+ show LocatedMessage, messageInvalidInitializer, templateNotAType;
-import '../messages.dart' show Message, noLength;
+import '../names.dart' show lengthName;
-import '../names.dart'
- show callName, equalsName, indexGetName, indexSetName, lengthName;
+import '../parser.dart' show lengthForToken, offsetForToken;
-import '../parser.dart' show lengthForToken, lengthOfSpan, offsetForToken;
-
-import '../problems.dart' show unhandled, unsupported;
-
-import '../scope.dart' show AccessErrorBuilder;
-
-import 'body_builder.dart' show Identifier, noLocation;
-
-import 'constness.dart' show Constness;
+import '../problems.dart' show unsupported;
import 'expression_generator_helper.dart' show ExpressionGeneratorHelper;
import 'forest.dart' show Forest;
-import 'kernel_builder.dart' show LoadLibraryBuilder, PrefixBuilder;
-
-import 'kernel_api.dart' show NameSystem, printNodeOn, printQualifiedNameOn;
-
import 'kernel_ast_api.dart'
show
- Constructor,
DartType,
- Field,
Initializer,
InvalidType,
- Let,
Member,
Name,
Procedure,
- PropertySet,
- ShadowComplexAssignment,
- ShadowIllegalAssignment,
- ShadowIndexAssign,
- ShadowMethodInvocation,
- ShadowNullAwarePropertyGet,
- ShadowPropertyAssign,
- ShadowPropertyGet,
- ShadowStaticAssignment,
- ShadowSuperMethodInvocation,
- ShadowSuperPropertyGet,
- ShadowVariableAssignment,
- ShadowVariableDeclaration,
- ShadowVariableGet,
- StaticSet,
- SuperMethodInvocation,
- SuperPropertySet,
- Throw,
- TreeNode,
- TypeParameter,
- TypeParameterType,
- VariableDeclaration,
- VariableGet,
- VariableSet;
+ VariableDeclaration;
-import 'kernel_ast_api.dart' as kernel show Expression, Node, Statement;
+import 'kernel_expression_generator.dart'
+ show IncompleteSendGenerator, SendAccessGenerator;
-import 'kernel_builder.dart'
+export 'kernel_expression_generator.dart'
show
- Builder,
- BuiltinTypeBuilder,
- FunctionTypeAliasBuilder,
- KernelClassBuilder,
- KernelFunctionTypeAliasBuilder,
- KernelInvalidTypeBuilder,
- KernelTypeVariableBuilder,
- LoadLibraryBuilder,
- PrefixBuilder,
- TypeDeclarationBuilder;
+ DeferredAccessGenerator,
+ DelayedAssignment,
+ DelayedPostfixIncrement,
+ ErroneousExpressionGenerator,
+ IncompleteErrorGenerator,
+ IncompletePropertyAccessGenerator,
+ IncompleteSendGenerator,
+ LargeIntAccessGenerator,
+ LoadLibraryGenerator,
+ ParenthesizedExpressionGenerator,
+ ReadOnlyAccessGenerator,
+ SendAccessGenerator,
+ StaticAccessGenerator,
+ SuperIndexedAccessGenerator,
+ ThisAccessGenerator,
+ TypeDeclarationAccessGenerator,
+ UnresolvedNameGenerator,
+ buildIsNull;
+
+abstract class ExpressionGenerator<Expression, Statement, Arguments> {
+ /// Builds a [Expression] representing a read from the generator.
+ Expression buildSimpleRead();
+
+ /// Builds a [Expression] representing an assignment with the generator on
+ /// the LHS and [value] on the RHS.
+ ///
+ /// The returned expression evaluates to the assigned value, unless
+ /// [voidContext] is true, in which case it may evaluate to anything.
+ Expression buildAssignment(Expression value, {bool voidContext});
+
+ /// Returns a [Expression] representing a null-aware assignment (`??=`) with
+ /// the generator on the LHS and [value] on the RHS.
+ ///
+ /// The returned expression evaluates to the assigned value, unless
+ /// [voidContext] is true, in which case it may evaluate to anything.
+ ///
+ /// [type] is the static type of the RHS.
+ Expression buildNullAwareAssignment(
+ Expression value, DartType type, int offset,
+ {bool voidContext});
+
+ /// Returns a [Expression] representing a compound assignment (e.g. `+=`)
+ /// with the generator on the LHS and [value] on the RHS.
+ Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+ {int offset,
+ bool voidContext,
+ Procedure interfaceTarget,
+ bool isPreIncDec});
+
+ /// Returns a [Expression] representing a pre-increment or pre-decrement of
+ /// the generator.
+ Expression buildPrefixIncrement(Name binaryOperator,
+ {int offset, bool voidContext, Procedure interfaceTarget});
+
+ /// Returns a [Expression] representing a post-increment or post-decrement of
+ /// the generator.
+ Expression buildPostfixIncrement(Name binaryOperator,
+ {int offset, bool voidContext, Procedure interfaceTarget});
+
+ /// Returns a [Expression] representing a compile-time error.
+ ///
+ /// At runtime, an exception will be thrown.
+ Expression makeInvalidRead();
+
+ /// Returns a [Expression] representing a compile-time error wrapping
+ /// [value].
+ ///
+ /// At runtime, [value] will be evaluated before throwing an exception.
+ Expression makeInvalidWrite(Expression value);
+
+ /* Expression | Generator */ buildThrowNoSuchMethodError(
+ Expression receiver, Arguments arguments,
+ {bool isSuper,
+ bool isGetter,
+ bool isSetter,
+ bool isStatic,
+ String name,
+ int offset,
+ LocatedMessage argMessage});
+}
/// A generator represents a subexpression for which we can't yet build an
/// expression because we don't yet know the context in which it's used.
@@ -106,15 +129,15 @@
/// generate an invocation of `operator[]` or `operator[]=`, so we create a
/// [Generator] object. Later, after `= b` is parsed, [buildAssignment] will
/// be called.
-abstract class Generator<Arguments> {
- final ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper;
+abstract class Generator<Expression, Statement, Arguments>
+ implements ExpressionGenerator<Expression, Statement, Arguments> {
+ final ExpressionGeneratorHelper<Expression, Statement, Arguments> helper;
+
final Token token;
Generator(this.helper, this.token);
- // TODO(ahe): Change type arguments.
- Forest<kernel.Expression, kernel.Statement, Token, Arguments> get forest =>
- helper.forest;
+ Forest<Expression, Statement, Token, Arguments> get forest => helper.forest;
String get plainNameForRead;
@@ -126,168 +149,12 @@
bool get isInitializer => false;
- /// Builds a [kernel.Expression] representing a read from the generator.
- kernel.Expression buildSimpleRead() {
- return _finish(_makeSimpleRead(), null);
- }
-
- /// Builds a [kernel.Expression] representing an assignment with the
- /// generator on the LHS and [value] on the RHS.
- ///
- /// The returned expression evaluates to the assigned value, unless
- /// [voidContext] is true, in which case it may evaluate to anything.
- kernel.Expression buildAssignment(kernel.Expression value,
- {bool voidContext: false}) {
- var complexAssignment = startComplexAssignment(value);
- return _finish(_makeSimpleWrite(value, voidContext, complexAssignment),
- complexAssignment);
- }
-
- /// Returns a [kernel.Expression] representing a null-aware assignment
- /// (`??=`) with the generator on the LHS and [value] on the RHS.
- ///
- /// The returned expression evaluates to the assigned value, unless
- /// [voidContext] is true, in which case it may evaluate to anything.
- ///
- /// [type] is the static type of the RHS.
- kernel.Expression buildNullAwareAssignment(
- kernel.Expression value, DartType type, int offset,
- {bool voidContext: false}) {
- var complexAssignment = startComplexAssignment(value);
- if (voidContext) {
- var nullAwareCombiner = helper.storeOffset(
- forest.conditionalExpression(
- buildIsNull(_makeRead(complexAssignment), offset, helper),
- null,
- _makeWrite(value, false, complexAssignment),
- null,
- helper.storeOffset(forest.literalNull(null), offset)),
- offset);
- complexAssignment?.nullAwareCombiner = nullAwareCombiner;
- return _finish(nullAwareCombiner, complexAssignment);
- }
- var tmp = new VariableDeclaration.forValue(_makeRead(complexAssignment));
- var nullAwareCombiner = helper.storeOffset(
- forest.conditionalExpression(
- buildIsNull(new VariableGet(tmp), offset, helper),
- null,
- _makeWrite(value, false, complexAssignment),
- null,
- new VariableGet(tmp)),
- offset);
- complexAssignment?.nullAwareCombiner = nullAwareCombiner;
- return _finish(makeLet(tmp, nullAwareCombiner), complexAssignment);
- }
-
- /// Returns a [kernel.Expression] representing a compound assignment
- /// (e.g. `+=`) with the generator on the LHS and [value] on the RHS.
- kernel.Expression buildCompoundAssignment(
- Name binaryOperator, kernel.Expression value,
- {int offset: TreeNode.noOffset,
- bool voidContext: false,
- Procedure interfaceTarget,
- bool isPreIncDec: false}) {
- var complexAssignment = startComplexAssignment(value);
- complexAssignment?.isPreIncDec = isPreIncDec;
- var combiner = makeBinary(_makeRead(complexAssignment), binaryOperator,
- interfaceTarget, value, helper,
- offset: offset);
- complexAssignment?.combiner = combiner;
- return _finish(_makeWrite(combiner, voidContext, complexAssignment),
- complexAssignment);
- }
-
- /// Returns a [kernel.Expression] representing a pre-increment or
- /// pre-decrement of the generator.
- kernel.Expression buildPrefixIncrement(Name binaryOperator,
- {int offset: TreeNode.noOffset,
- bool voidContext: false,
- Procedure interfaceTarget}) {
- return buildCompoundAssignment(
- binaryOperator, helper.storeOffset(forest.literalInt(1, null), offset),
- offset: offset,
- voidContext: voidContext,
- interfaceTarget: interfaceTarget,
- isPreIncDec: true);
- }
-
- /// Returns a [kernel.Expression] representing a post-increment or
- /// post-decrement of the generator.
- kernel.Expression buildPostfixIncrement(Name binaryOperator,
- {int offset: TreeNode.noOffset,
- bool voidContext: false,
- Procedure interfaceTarget}) {
- if (voidContext) {
- return buildPrefixIncrement(binaryOperator,
- offset: offset, voidContext: true, interfaceTarget: interfaceTarget);
- }
- var rhs = helper.storeOffset(forest.literalInt(1, null), offset);
- var complexAssignment = startComplexAssignment(rhs);
- var value = new VariableDeclaration.forValue(_makeRead(complexAssignment));
- valueAccess() => new VariableGet(value);
- var combiner = makeBinary(
- valueAccess(), binaryOperator, interfaceTarget, rhs, helper,
- offset: offset);
- complexAssignment?.combiner = combiner;
- complexAssignment?.isPostIncDec = true;
- var dummy = new ShadowVariableDeclaration.forValue(
- _makeWrite(combiner, true, complexAssignment),
- helper.functionNestingLevel);
- return _finish(
- makeLet(value, makeLet(dummy, valueAccess())), complexAssignment);
- }
-
- kernel.Expression _makeSimpleRead() => _makeRead(null);
-
- kernel.Expression _makeSimpleWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- return _makeWrite(value, voidContext, complexAssignment);
- }
-
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment);
-
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment);
-
- kernel.Expression _finish(
- kernel.Expression body, ShadowComplexAssignment complexAssignment) {
- if (complexAssignment != null) {
- complexAssignment.desugared = body;
- return complexAssignment;
- } else {
- return body;
- }
- }
-
- /// Returns a [kernel.Expression] representing a compile-time error.
- ///
- /// At runtime, an exception will be thrown.
- kernel.Expression makeInvalidRead() {
- return buildThrowNoSuchMethodError(
- forest.literalNull(token), forest.argumentsEmpty(noLocation),
- isGetter: true);
- }
-
- /// Returns a [kernel.Expression] representing a compile-time error wrapping
- /// [value].
- ///
- /// At runtime, [value] will be evaluated before throwing an exception.
- kernel.Expression makeInvalidWrite(kernel.Expression value) {
- return buildThrowNoSuchMethodError(forest.literalNull(token),
- forest.arguments(<kernel.Expression>[value], noLocation),
- isSetter: true);
- }
-
- /// Creates a data structure for tracking the desugaring of a complex
- /// assignment expression whose right hand side is [rhs].
- ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
- new ShadowIllegalAssignment(rhs);
-
+ // TODO(ahe): Remove this method.
T storeOffset<T>(T node, int offset) {
return helper.storeOffset(node, offset);
}
- kernel.Expression buildForEffect() => buildSimpleRead();
+ Expression buildForEffect() => buildSimpleRead();
Initializer buildFieldInitializer(Map<String, int> initializedFields) {
int offset = offsetForToken(token);
@@ -303,8 +170,11 @@
/* kernel.Expression | Generator */ buildPropertyAccess(
IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
if (send is SendAccessGenerator) {
- return helper.buildMethodInvocation(buildSimpleRead(), send.name,
- send.arguments, offsetForToken(send.token),
+ return helper.buildMethodInvocation(
+ buildSimpleRead(),
+ send.name,
+ send.arguments as dynamic /* TODO(ahe): Remove this cast. */,
+ offsetForToken(send.token),
isNullAware: isNullAware);
} else {
if (helper.constantContext != ConstantContext.none &&
@@ -312,8 +182,14 @@
helper.deprecated_addCompileTimeError(
offsetForToken(token), "Not a constant expression.");
}
- return PropertyAccessGenerator.make(helper, send.token, buildSimpleRead(),
- send.name, null, null, isNullAware);
+ return PropertyAccessGenerator.make<Expression, Statement, Arguments>(
+ helper,
+ send.token,
+ buildSimpleRead(),
+ send.name,
+ null,
+ null,
+ isNullAware);
}
}
@@ -324,8 +200,9 @@
return const InvalidType();
}
+ @override
/* kernel.Expression | Generator */ buildThrowNoSuchMethodError(
- kernel.Expression receiver, Arguments arguments,
+ Expression receiver, Arguments arguments,
{bool isSuper: false,
bool isGetter: false,
bool isSetter: false,
@@ -357,447 +234,143 @@
}
}
-class VariableUseGenerator<Arguments> extends Generator<Arguments> {
- final VariableDeclaration variable;
-
- final DartType promotedType;
-
- VariableUseGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+abstract class VariableUseGenerator<Expression, Statement, Arguments>
+ implements Generator<Expression, Statement, Arguments> {
+ factory VariableUseGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
Token token,
- this.variable,
- [this.promotedType])
- : super(helper, token);
+ VariableDeclaration variable,
+ [DartType promotedType]) {
+ return helper.forest
+ .variableUseGenerator(helper, token, variable, promotedType);
+ }
- String get plainNameForRead => variable.name;
-
+ @override
String get debugName => "VariableUseGenerator";
-
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- var fact = helper.typePromoter
- .getFactForAccess(variable, helper.functionNestingLevel);
- var scope = helper.typePromoter.currentScope;
- var read = new ShadowVariableGet(variable, fact, scope)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.read = read;
- return read;
- }
-
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- helper.typePromoter.mutateVariable(variable, helper.functionNestingLevel);
- var write = variable.isFinal || variable.isConst
- ? makeInvalidWrite(value)
- : new VariableSet(variable, value)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.write = write;
- return write;
- }
-
- @override
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- return helper.buildMethodInvocation(buildSimpleRead(), callName, arguments,
- adjustForImplicitCall(plainNameForRead, offset),
- isImplicitCall: true);
- }
-
- @override
- ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
- new ShadowVariableAssignment(rhs);
-
- @override
- void printOn(StringSink sink) {
- NameSystem syntheticNames = new NameSystem();
- sink.write(", variable: ");
- printNodeOn(variable, sink, syntheticNames: syntheticNames);
- sink.write(", promotedType: ");
- printNodeOn(promotedType, sink, syntheticNames: syntheticNames);
- }
}
-class PropertyAccessGenerator<Arguments> extends Generator<Arguments> {
- final kernel.Expression receiver;
-
- final Name name;
-
- final Member getter;
-
- final Member setter;
-
- VariableDeclaration _receiverVariable;
-
- PropertyAccessGenerator.internal(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+abstract class PropertyAccessGenerator<Expression, Statement, Arguments>
+ implements Generator<Expression, Statement, Arguments> {
+ factory PropertyAccessGenerator.internal(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
Token token,
- this.receiver,
- this.name,
- this.getter,
- this.setter)
- : super(helper, token);
-
- static Generator<Arguments> make<Arguments>(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- kernel.Expression receiver,
+ Expression receiver,
Name name,
Member getter,
- Member setter,
- bool isNullAware) {
+ Member setter) {
+ return helper.forest
+ .propertyAccessGenerator(helper, token, receiver, name, getter, setter);
+ }
+
+ static Generator<Expression, Statement, Arguments>
+ make<Expression, Statement, Arguments>(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Token token,
+ Expression receiver,
+ Name name,
+ Member getter,
+ Member setter,
+ bool isNullAware) {
if (helper.forest.isThisExpression(receiver)) {
return unsupported("ThisExpression", offsetForToken(token), helper.uri);
} else {
return isNullAware
? new NullAwarePropertyAccessGenerator(
- helper, token, receiver, name, getter, setter, null)
+ helper,
+ token,
+ receiver as dynamic /* TODO(ahe): Remove this cast. */,
+ name,
+ getter,
+ setter,
+ null)
: new PropertyAccessGenerator.internal(
helper, token, receiver, name, getter, setter);
}
}
- String get plainNameForRead => name.name;
-
+ @override
String get debugName => "PropertyAccessGenerator";
- bool get isThisPropertyAccess => forest.isThisExpression(receiver);
-
- kernel.Expression _makeSimpleRead() =>
- new ShadowPropertyGet(receiver, name, getter)
- ..fileOffset = offsetForToken(token);
-
- kernel.Expression _makeSimpleWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- var write = new PropertySet(receiver, name, value, setter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.write = write;
- return write;
- }
-
- receiverAccess() {
- _receiverVariable ??= new VariableDeclaration.forValue(receiver);
- return new VariableGet(_receiverVariable)
- ..fileOffset = offsetForToken(token);
- }
-
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- var read = new ShadowPropertyGet(receiverAccess(), name, getter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.read = read;
- return read;
- }
-
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- var write = new PropertySet(receiverAccess(), name, value, setter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.write = write;
- return write;
- }
-
- kernel.Expression _finish(
- kernel.Expression body, ShadowComplexAssignment complexAssignment) {
- return super._finish(makeLet(_receiverVariable, body), complexAssignment);
- }
-
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- return helper.buildMethodInvocation(receiver, name, arguments, offset);
- }
-
@override
- ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
- new ShadowPropertyAssign(receiver, rhs);
-
- @override
- void printOn(StringSink sink) {
- NameSystem syntheticNames = new NameSystem();
- sink.write(", _receiverVariable: ");
- printNodeOn(_receiverVariable, sink, syntheticNames: syntheticNames);
- sink.write(", receiver: ");
- printNodeOn(receiver, sink, syntheticNames: syntheticNames);
- sink.write(", name: ");
- sink.write(name.name);
- sink.write(", getter: ");
- printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
- sink.write(", setter: ");
- printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
- }
+ bool get isThisPropertyAccess => false;
}
/// Special case of [PropertyAccessGenerator] to avoid creating an indirect
/// access to 'this'.
-class ThisPropertyAccessGenerator<Arguments> extends Generator<Arguments> {
- final Name name;
-
- final Member getter;
-
- final Member setter;
-
- ThisPropertyAccessGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+abstract class ThisPropertyAccessGenerator<Expression, Statement, Arguments>
+ implements Generator<Expression, Statement, Arguments> {
+ factory ThisPropertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
Token token,
- this.name,
- this.getter,
- this.setter)
- : super(helper, token);
+ Name name,
+ Member getter,
+ Member setter) {
+ return helper.forest
+ .thisPropertyAccessGenerator(helper, token, name, getter, setter);
+ }
- String get plainNameForRead => name.name;
-
+ @override
String get debugName => "ThisPropertyAccessGenerator";
+ @override
bool get isThisPropertyAccess => true;
-
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- if (getter == null) {
- helper.warnUnresolvedGet(name, offsetForToken(token));
- }
- var read = new ShadowPropertyGet(forest.thisExpression(token), name, getter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.read = read;
- return read;
- }
-
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- if (setter == null) {
- helper.warnUnresolvedSet(name, offsetForToken(token));
- }
- var write =
- new PropertySet(forest.thisExpression(token), name, value, setter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.write = write;
- return write;
- }
-
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- Member interfaceTarget = getter;
- if (interfaceTarget == null) {
- helper.warnUnresolvedMethod(name, offset);
- }
- if (interfaceTarget is Field) {
- // TODO(ahe): In strong mode we should probably rewrite this to
- // `this.name.call(arguments)`.
- interfaceTarget = null;
- }
- return helper.buildMethodInvocation(
- forest.thisExpression(null), name, arguments, offset,
- interfaceTarget: interfaceTarget);
- }
-
- @override
- ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
- new ShadowPropertyAssign(null, rhs);
-
- @override
- void printOn(StringSink sink) {
- NameSystem syntheticNames = new NameSystem();
- sink.write(", name: ");
- sink.write(name.name);
- sink.write(", getter: ");
- printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
- sink.write(", setter: ");
- printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
- }
}
-class NullAwarePropertyAccessGenerator<Arguments> extends Generator<Arguments> {
- final VariableDeclaration receiver;
-
- final kernel.Expression receiverExpression;
-
- final Name name;
-
- final Member getter;
-
- final Member setter;
-
- final DartType type;
-
- NullAwarePropertyAccessGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+abstract class NullAwarePropertyAccessGenerator<Expression, Statement,
+ Arguments> implements Generator<Expression, Statement, Arguments> {
+ factory NullAwarePropertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
Token token,
- this.receiverExpression,
- this.name,
- this.getter,
- this.setter,
- this.type)
- : this.receiver = makeOrReuseVariable(receiverExpression),
- super(helper, token);
+ Expression receiverExpression,
+ Name name,
+ Member getter,
+ Member setter,
+ DartType type) {
+ return helper.forest.nullAwarePropertyAccessGenerator(
+ helper, token, receiverExpression, name, getter, setter, type);
+ }
- String get plainNameForRead => name.name;
-
+ @override
String get debugName => "NullAwarePropertyAccessGenerator";
-
- kernel.Expression receiverAccess() => new VariableGet(receiver);
-
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- var read = new ShadowPropertyGet(receiverAccess(), name, getter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.read = read;
- return read;
- }
-
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- var write = new PropertySet(receiverAccess(), name, value, setter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.write = write;
- return write;
- }
-
- kernel.Expression _finish(
- kernel.Expression body, ShadowComplexAssignment complexAssignment) {
- var offset = offsetForToken(token);
- var nullAwareGuard = helper.storeOffset(
- forest.conditionalExpression(
- buildIsNull(receiverAccess(), offset, helper),
- null,
- helper.storeOffset(forest.literalNull(null), offset),
- null,
- body),
- offset);
- if (complexAssignment != null) {
- body = makeLet(receiver, nullAwareGuard);
- ShadowPropertyAssign kernelPropertyAssign = complexAssignment;
- kernelPropertyAssign.nullAwareGuard = nullAwareGuard;
- kernelPropertyAssign.desugared = body;
- return kernelPropertyAssign;
- } else {
- return new ShadowNullAwarePropertyGet(receiver, nullAwareGuard)
- ..fileOffset = offset;
- }
- }
-
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- return unsupported("doInvocation", offset, uri);
- }
-
- @override
- ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
- new ShadowPropertyAssign(receiverExpression, rhs);
-
- @override
- void printOn(StringSink sink) {
- NameSystem syntheticNames = new NameSystem();
- sink.write(", receiver: ");
- printNodeOn(receiver, sink, syntheticNames: syntheticNames);
- sink.write(", receiverExpression: ");
- printNodeOn(receiverExpression, sink, syntheticNames: syntheticNames);
- sink.write(", name: ");
- sink.write(name.name);
- sink.write(", getter: ");
- printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
- sink.write(", setter: ");
- printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
- sink.write(", type: ");
- printNodeOn(type, sink, syntheticNames: syntheticNames);
- }
}
-class SuperPropertyAccessGenerator<Arguments> extends Generator<Arguments> {
- final Name name;
-
- final Member getter;
-
- final Member setter;
-
- SuperPropertyAccessGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+abstract class SuperPropertyAccessGenerator<Expression, Statement, Arguments>
+ implements Generator<Expression, Statement, Arguments> {
+ factory SuperPropertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
Token token,
- this.name,
- this.getter,
- this.setter)
- : super(helper, token);
+ Name name,
+ Member getter,
+ Member setter) {
+ return helper.forest
+ .superPropertyAccessGenerator(helper, token, name, getter, setter);
+ }
- String get plainNameForRead => name.name;
-
+ @override
String get debugName => "SuperPropertyAccessGenerator";
-
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- if (getter == null) {
- helper.warnUnresolvedGet(name, offsetForToken(token), isSuper: true);
- }
- // TODO(ahe): Use [DirectPropertyGet] when possible.
- var read = new ShadowSuperPropertyGet(name, getter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.read = read;
- return read;
- }
-
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- if (setter == null) {
- helper.warnUnresolvedSet(name, offsetForToken(token), isSuper: true);
- }
- // TODO(ahe): Use [DirectPropertySet] when possible.
- var write = new SuperPropertySet(name, value, setter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.write = write;
- return write;
- }
-
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- if (helper.constantContext != ConstantContext.none) {
- helper.deprecated_addCompileTimeError(
- offset, "Not a constant expression.");
- }
- if (getter == null || isFieldOrGetter(getter)) {
- return helper.buildMethodInvocation(
- buildSimpleRead(), callName, arguments, offset,
- // This isn't a constant expression, but we have checked if a
- // constant expression error should be emitted already.
- isConstantExpression: true,
- isImplicitCall: true);
- } else {
- // TODO(ahe): This could be something like "super.property(...)" where
- // property is a setter.
- return unhandled("${getter.runtimeType}", "doInvocation", offset, uri);
- }
- }
-
- @override
- ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
- new ShadowPropertyAssign(null, rhs, isSuper: true);
-
- @override
- void printOn(StringSink sink) {
- NameSystem syntheticNames = new NameSystem();
- sink.write(", name: ");
- sink.write(name.name);
- sink.write(", getter: ");
- printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
- sink.write(", setter: ");
- printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
- }
}
-class IndexedAccessGenerator<Arguments> extends Generator<Arguments> {
- final kernel.Expression receiver;
-
- final kernel.Expression index;
-
- final Procedure getter;
-
- final Procedure setter;
-
- VariableDeclaration receiverVariable;
-
- VariableDeclaration indexVariable;
-
- IndexedAccessGenerator.internal(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+abstract class IndexedAccessGenerator<Expression, Statement, Arguments>
+ implements Generator<Expression, Statement, Arguments> {
+ factory IndexedAccessGenerator.internal(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
Token token,
- this.receiver,
- this.index,
- this.getter,
- this.setter)
- : super(helper, token);
-
- static Generator<Arguments> make<Arguments>(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- kernel.Expression receiver,
- kernel.Expression index,
+ Expression receiver,
+ Expression index,
Procedure getter,
Procedure setter) {
+ return helper.forest
+ .indexedAccessGenerator(helper, token, receiver, index, getter, setter);
+ }
+
+ static Generator<Expression, Statement, Arguments>
+ make<Expression, Statement, Arguments>(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Token token,
+ Expression receiver,
+ Expression index,
+ Procedure getter,
+ Procedure setter) {
if (helper.forest.isThisExpression(receiver)) {
return new ThisIndexedAccessGenerator(
helper, token, index, getter, setter);
@@ -807,1525 +380,36 @@
}
}
+ @override
String get plainNameForRead => "[]";
+ @override
String get plainNameForWrite => "[]=";
+ @override
String get debugName => "IndexedAccessGenerator";
-
- kernel.Expression _makeSimpleRead() {
- var read = new ShadowMethodInvocation(
- receiver,
- indexGetName,
- forest
- .castArguments(forest.arguments(<kernel.Expression>[index], token)),
- interfaceTarget: getter)
- ..fileOffset = offsetForToken(token);
- return read;
- }
-
- kernel.Expression _makeSimpleWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
- var write = new ShadowMethodInvocation(
- receiver,
- indexSetName,
- forest.castArguments(
- forest.arguments(<kernel.Expression>[index, value], token)),
- interfaceTarget: setter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.write = write;
- return write;
- }
-
- receiverAccess() {
- // We cannot reuse the receiver if it is a variable since it might be
- // reassigned in the index expression.
- receiverVariable ??= new VariableDeclaration.forValue(receiver);
- return new VariableGet(receiverVariable)
- ..fileOffset = offsetForToken(token);
- }
-
- indexAccess() {
- indexVariable ??= new VariableDeclaration.forValue(index);
- return new VariableGet(indexVariable)..fileOffset = offsetForToken(token);
- }
-
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- var read = new ShadowMethodInvocation(
- receiverAccess(),
- indexGetName,
- forest.castArguments(
- forest.arguments(<kernel.Expression>[indexAccess()], token)),
- interfaceTarget: getter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.read = read;
- return read;
- }
-
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
- var write = new ShadowMethodInvocation(
- receiverAccess(),
- indexSetName,
- forest.castArguments(
- forest.arguments(<kernel.Expression>[indexAccess(), value], token)),
- interfaceTarget: setter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.write = write;
- return write;
- }
-
- // TODO(dmitryas): remove this method after the "[]=" operator of the Context
- // class is made to return a value.
- _makeWriteAndReturn(
- kernel.Expression value, ShadowComplexAssignment complexAssignment) {
- // The call to []= does not return the value like direct-style assignments
- // do. We need to bind the value in a let.
- var valueVariable = new VariableDeclaration.forValue(value);
- var write = new ShadowMethodInvocation(
- receiverAccess(),
- indexSetName,
- forest.castArguments(forest.arguments(
- <kernel.Expression>[indexAccess(), new VariableGet(valueVariable)],
- token)),
- interfaceTarget: setter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.write = write;
- var dummy = new ShadowVariableDeclaration.forValue(
- write, helper.functionNestingLevel);
- return makeLet(
- valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
- }
-
- kernel.Expression _finish(
- kernel.Expression body, ShadowComplexAssignment complexAssignment) {
- return super._finish(
- makeLet(receiverVariable, makeLet(indexVariable, body)),
- complexAssignment);
- }
-
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- return helper.buildMethodInvocation(
- buildSimpleRead(), callName, arguments, forest.readOffset(arguments),
- isImplicitCall: true);
- }
-
- @override
- ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
- new ShadowIndexAssign(receiver, index, rhs);
-
- @override
- void printOn(StringSink sink) {
- NameSystem syntheticNames = new NameSystem();
- sink.write(", receiver: ");
- printNodeOn(receiver, sink, syntheticNames: syntheticNames);
- sink.write(", index: ");
- printNodeOn(index, sink, syntheticNames: syntheticNames);
- sink.write(", getter: ");
- printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
- sink.write(", setter: ");
- printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
- sink.write(", receiverVariable: ");
- printNodeOn(receiverVariable, sink, syntheticNames: syntheticNames);
- sink.write(", indexVariable: ");
- printNodeOn(indexVariable, sink, syntheticNames: syntheticNames);
- }
}
/// Special case of [IndexedAccessGenerator] to avoid creating an indirect
/// access to 'this'.
-class ThisIndexedAccessGenerator<Arguments> extends Generator<Arguments> {
- final kernel.Expression index;
-
- final Procedure getter;
-
- final Procedure setter;
-
- VariableDeclaration indexVariable;
-
- ThisIndexedAccessGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+abstract class ThisIndexedAccessGenerator<Expression, Statement, Arguments>
+ implements Generator<Expression, Statement, Arguments> {
+ factory ThisIndexedAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
Token token,
- this.index,
- this.getter,
- this.setter)
- : super(helper, token);
+ Expression index,
+ Procedure getter,
+ Procedure setter) {
+ return helper.forest
+ .thisIndexedAccessGenerator(helper, token, index, getter, setter);
+ }
+ @override
String get plainNameForRead => "[]";
+ @override
String get plainNameForWrite => "[]=";
+ @override
String get debugName => "ThisIndexedAccessGenerator";
-
- kernel.Expression _makeSimpleRead() {
- return new ShadowMethodInvocation(
- forest.thisExpression(token),
- indexGetName,
- forest
- .castArguments(forest.arguments(<kernel.Expression>[index], token)),
- interfaceTarget: getter)
- ..fileOffset = offsetForToken(token);
- }
-
- kernel.Expression _makeSimpleWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
- var write = new ShadowMethodInvocation(
- forest.thisExpression(token),
- indexSetName,
- forest.castArguments(
- forest.arguments(<kernel.Expression>[index, value], token)),
- interfaceTarget: setter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.write = write;
- return write;
- }
-
- indexAccess() {
- indexVariable ??= new VariableDeclaration.forValue(index);
- return new VariableGet(indexVariable);
- }
-
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- var read = new ShadowMethodInvocation(
- forest.thisExpression(token),
- indexGetName,
- forest.castArguments(
- forest.arguments(<kernel.Expression>[indexAccess()], token)),
- interfaceTarget: getter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.read = read;
- return read;
- }
-
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
- var write = new ShadowMethodInvocation(
- forest.thisExpression(token),
- indexSetName,
- forest.castArguments(
- forest.arguments(<kernel.Expression>[indexAccess(), value], token)),
- interfaceTarget: setter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.write = write;
- return write;
- }
-
- _makeWriteAndReturn(
- kernel.Expression value, ShadowComplexAssignment complexAssignment) {
- var valueVariable = new VariableDeclaration.forValue(value);
- var write = new ShadowMethodInvocation(
- forest.thisExpression(token),
- indexSetName,
- forest.castArguments(forest.arguments(
- <kernel.Expression>[indexAccess(), new VariableGet(valueVariable)],
- token)),
- interfaceTarget: setter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.write = write;
- var dummy = new VariableDeclaration.forValue(write);
- return makeLet(
- valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
- }
-
- kernel.Expression _finish(
- kernel.Expression body, ShadowComplexAssignment complexAssignment) {
- return super._finish(makeLet(indexVariable, body), complexAssignment);
- }
-
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- return helper.buildMethodInvocation(
- buildSimpleRead(), callName, arguments, offset,
- isImplicitCall: true);
- }
-
- @override
- ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
- new ShadowIndexAssign(null, index, rhs);
-
- @override
- void printOn(StringSink sink) {
- NameSystem syntheticNames = new NameSystem();
- sink.write(", index: ");
- printNodeOn(index, sink, syntheticNames: syntheticNames);
- sink.write(", getter: ");
- printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
- sink.write(", setter: ");
- printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
- sink.write(", indexVariable: ");
- printNodeOn(indexVariable, sink, syntheticNames: syntheticNames);
- }
-}
-
-class SuperIndexedAccessGenerator<Arguments> extends Generator<Arguments> {
- final kernel.Expression index;
-
- final Member getter;
-
- final Member setter;
-
- VariableDeclaration indexVariable;
-
- SuperIndexedAccessGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- this.index,
- this.getter,
- this.setter)
- : super(helper, token);
-
- String get plainNameForRead => "[]";
-
- String get plainNameForWrite => "[]=";
-
- String get debugName => "SuperIndexedAccessGenerator";
-
- indexAccess() {
- indexVariable ??= new VariableDeclaration.forValue(index);
- return new VariableGet(indexVariable);
- }
-
- kernel.Expression _makeSimpleRead() {
- if (getter == null) {
- helper.warnUnresolvedMethod(indexGetName, offsetForToken(token),
- isSuper: true);
- }
- // TODO(ahe): Use [DirectMethodInvocation] when possible.
- return new ShadowSuperMethodInvocation(
- indexGetName,
- forest
- .castArguments(forest.arguments(<kernel.Expression>[index], token)),
- getter)
- ..fileOffset = offsetForToken(token);
- }
-
- kernel.Expression _makeSimpleWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
- if (setter == null) {
- helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
- isSuper: true);
- }
- var write = new SuperMethodInvocation(
- indexSetName,
- forest.castArguments(
- forest.arguments(<kernel.Expression>[index, value], token)),
- setter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.write = write;
- return write;
- }
-
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- if (getter == null) {
- helper.warnUnresolvedMethod(indexGetName, offsetForToken(token),
- isSuper: true);
- }
- var read = new SuperMethodInvocation(
- indexGetName,
- forest.castArguments(
- forest.arguments(<kernel.Expression>[indexAccess()], token)),
- getter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.read = read;
- return read;
- }
-
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
- if (setter == null) {
- helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
- isSuper: true);
- }
- var write = new SuperMethodInvocation(
- indexSetName,
- forest.castArguments(
- forest.arguments(<kernel.Expression>[indexAccess(), value], token)),
- setter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.write = write;
- return write;
- }
-
- _makeWriteAndReturn(
- kernel.Expression value, ShadowComplexAssignment complexAssignment) {
- var valueVariable = new VariableDeclaration.forValue(value);
- if (setter == null) {
- helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
- isSuper: true);
- }
- var write = new SuperMethodInvocation(
- indexSetName,
- forest.castArguments(forest.arguments(
- <kernel.Expression>[indexAccess(), new VariableGet(valueVariable)],
- token)),
- setter)
- ..fileOffset = offsetForToken(token);
- complexAssignment?.write = write;
- var dummy = new VariableDeclaration.forValue(write);
- return makeLet(
- valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
- }
-
- kernel.Expression _finish(
- kernel.Expression body, ShadowComplexAssignment complexAssignment) {
- return super._finish(makeLet(indexVariable, body), complexAssignment);
- }
-
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- return helper.buildMethodInvocation(
- buildSimpleRead(), callName, arguments, offset,
- isImplicitCall: true);
- }
-
- @override
- ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
- new ShadowIndexAssign(null, index, rhs, isSuper: true);
-
- @override
- void printOn(StringSink sink) {
- NameSystem syntheticNames = new NameSystem();
- sink.write(", index: ");
- printNodeOn(index, sink, syntheticNames: syntheticNames);
- sink.write(", getter: ");
- printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
- sink.write(", setter: ");
- printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
- sink.write(", indexVariable: ");
- printNodeOn(indexVariable, sink, syntheticNames: syntheticNames);
- }
-}
-
-class StaticAccessGenerator<Arguments> extends Generator<Arguments> {
- final Member readTarget;
-
- final Member writeTarget;
-
- StaticAccessGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- this.readTarget,
- this.writeTarget)
- : assert(readTarget != null || writeTarget != null),
- super(helper, token);
-
- factory StaticAccessGenerator.fromBuilder(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Builder builder,
- Token token,
- Builder builderSetter) {
- if (builder is AccessErrorBuilder) {
- AccessErrorBuilder error = builder;
- builder = error.builder;
- // We should only see an access error here if we've looked up a setter
- // when not explicitly looking for a setter.
- assert(builder.isSetter);
- } else if (builder.target == null) {
- return unhandled(
- "${builder.runtimeType}",
- "StaticAccessGenerator.fromBuilder",
- offsetForToken(token),
- helper.uri);
- }
- Member getter = builder.target.hasGetter ? builder.target : null;
- Member setter = builder.target.hasSetter ? builder.target : null;
- if (setter == null) {
- if (builderSetter?.target?.hasSetter ?? false) {
- setter = builderSetter.target;
- }
- }
- return new StaticAccessGenerator(helper, token, getter, setter);
- }
-
- String get plainNameForRead => (readTarget ?? writeTarget).name.name;
-
- String get debugName => "StaticAccessGenerator";
-
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- if (readTarget == null) {
- return makeInvalidRead();
- } else {
- var read = helper.makeStaticGet(readTarget, token);
- complexAssignment?.read = read;
- return read;
- }
- }
-
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- kernel.Expression write;
- if (writeTarget == null) {
- write = makeInvalidWrite(value);
- } else {
- write = new StaticSet(writeTarget, value);
- complexAssignment?.write = write;
- }
- write.fileOffset = offsetForToken(token);
- return write;
- }
-
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- if (helper.constantContext != ConstantContext.none &&
- !helper.isIdentical(readTarget)) {
- helper.deprecated_addCompileTimeError(
- offset, "Not a constant expression.");
- }
- if (readTarget == null || isFieldOrGetter(readTarget)) {
- return helper.buildMethodInvocation(buildSimpleRead(), callName,
- arguments, offset + (readTarget?.name?.name?.length ?? 0),
- // This isn't a constant expression, but we have checked if a
- // constant expression error should be emitted already.
- isConstantExpression: true,
- isImplicitCall: true);
- } else {
- return helper.buildStaticInvocation(readTarget, arguments,
- charOffset: offset);
- }
- }
-
- @override
- ShadowComplexAssignment startComplexAssignment(kernel.Expression rhs) =>
- new ShadowStaticAssignment(rhs);
-
- @override
- void printOn(StringSink sink) {
- NameSystem syntheticNames = new NameSystem();
- sink.write(", readTarget: ");
- printQualifiedNameOn(readTarget, sink, syntheticNames: syntheticNames);
- sink.write(", writeTarget: ");
- printQualifiedNameOn(writeTarget, sink, syntheticNames: syntheticNames);
- }
-}
-
-class LoadLibraryGenerator<Arguments> extends Generator<Arguments> {
- final LoadLibraryBuilder builder;
-
- LoadLibraryGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- this.builder)
- : super(helper, token);
-
- String get plainNameForRead => 'loadLibrary';
-
- String get debugName => "LoadLibraryGenerator";
-
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- var read =
- helper.makeStaticGet(builder.createTearoffMethod(helper.forest), token);
- complexAssignment?.read = read;
- return read;
- }
-
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- kernel.Expression write = makeInvalidWrite(value);
- write.fileOffset = offsetForToken(token);
- return write;
- }
-
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- if (forest.argumentsPositional(arguments).length > 0 ||
- forest.argumentsNamed(arguments).length > 0) {
- helper.addProblemErrorIfConst(
- messageLoadLibraryTakesNoArguments, offset, 'loadLibrary'.length);
- }
- return builder.createLoadLibrary(offset, forest);
- }
-
- @override
- void printOn(StringSink sink) {
- sink.write(", builder: ");
- sink.write(builder);
- }
-}
-
-class DeferredAccessGenerator<Arguments> extends Generator<Arguments> {
- final PrefixBuilder builder;
-
- final Generator generator;
-
- DeferredAccessGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- this.builder,
- this.generator)
- : super(helper, token);
-
- String get plainNameForRead {
- return unsupported(
- "deferredAccessor.plainNameForRead", offsetForToken(token), uri);
- }
-
- String get debugName => "DeferredAccessGenerator";
-
- kernel.Expression _makeSimpleRead() {
- return helper.wrapInDeferredCheck(
- generator._makeSimpleRead(), builder, token.charOffset);
- }
-
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- return helper.wrapInDeferredCheck(
- generator._makeRead(complexAssignment), builder, token.charOffset);
- }
-
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- return helper.wrapInDeferredCheck(
- generator._makeWrite(value, voidContext, complexAssignment),
- builder,
- token.charOffset);
- }
-
- buildPropertyAccess(
- IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
- var propertyAccess =
- generator.buildPropertyAccess(send, operatorOffset, isNullAware);
- if (propertyAccess is Generator) {
- return new DeferredAccessGenerator(
- helper, token, builder, propertyAccess);
- } else {
- kernel.Expression expression = propertyAccess;
- return helper.wrapInDeferredCheck(expression, builder, token.charOffset);
- }
- }
-
- @override
- DartType buildTypeWithBuiltArguments(List<DartType> arguments,
- {bool nonInstanceAccessIsError: false}) {
- helper.addProblem(
- templateDeferredTypeAnnotation.withArguments(
- generator.buildTypeWithBuiltArguments(arguments,
- nonInstanceAccessIsError: nonInstanceAccessIsError),
- builder.name),
- offsetForToken(token),
- lengthForToken(token));
- return const InvalidType();
- }
-
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- return helper.wrapInDeferredCheck(
- generator.doInvocation(offset, arguments), builder, token.charOffset);
- }
-
- @override
- void printOn(StringSink sink) {
- sink.write(", builder: ");
- sink.write(builder);
- sink.write(", generator: ");
- sink.write(generator);
- }
-}
-
-class ReadOnlyAccessGenerator<Arguments> extends Generator<Arguments> {
- final String plainNameForRead;
-
- kernel.Expression expression;
-
- VariableDeclaration value;
-
- ReadOnlyAccessGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- this.expression,
- this.plainNameForRead)
- : super(helper, token);
-
- String get debugName => "ReadOnlyAccessGenerator";
-
- kernel.Expression _makeSimpleRead() => expression;
-
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- value ??= new VariableDeclaration.forValue(expression);
- return new VariableGet(value);
- }
-
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- var write = makeInvalidWrite(value);
- complexAssignment?.write = write;
- return write;
- }
-
- kernel.Expression _finish(
- kernel.Expression body, ShadowComplexAssignment complexAssignment) =>
- super._finish(makeLet(value, body), complexAssignment);
-
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- return helper.buildMethodInvocation(buildSimpleRead(), callName, arguments,
- adjustForImplicitCall(plainNameForRead, offset),
- isImplicitCall: true);
- }
-
- @override
- void printOn(StringSink sink) {
- NameSystem syntheticNames = new NameSystem();
- sink.write(", expression: ");
- printNodeOn(expression, sink, syntheticNames: syntheticNames);
- sink.write(", plainNameForRead: ");
- sink.write(plainNameForRead);
- sink.write(", value: ");
- printNodeOn(value, sink, syntheticNames: syntheticNames);
- }
-}
-
-class LargeIntAccessGenerator<Arguments> extends Generator<Arguments> {
- LargeIntAccessGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token)
- : super(helper, token);
-
- // TODO(ahe): This should probably be calling unhandled.
- String get plainNameForRead => null;
-
- String get debugName => "LargeIntAccessGenerator";
-
- @override
- kernel.Expression _makeSimpleRead() => buildError();
-
- @override
- kernel.Expression _makeSimpleWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- return buildError();
- }
-
- @override
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- return buildError();
- }
-
- @override
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- return buildError();
- }
-
- kernel.Expression buildError() {
- return helper.buildCompileTimeError(
- templateIntegerLiteralIsOutOfRange.withArguments(token),
- offsetForToken(token),
- lengthForToken(token));
- }
-
- @override
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- return buildError();
- }
-
- @override
- void printOn(StringSink sink) {
- sink.write(", lexeme: ");
- sink.write(token.lexeme);
- }
-}
-
-abstract class ErroneousExpressionGenerator<Arguments>
- implements Generator<Arguments> {
- /// Pass [arguments] that must be evaluated before throwing an error. At
- /// most one of [isGetter] and [isSetter] should be true and they're passed
- /// to [ExpressionGeneratorHelper.buildThrowNoSuchMethodError] if it is used.
- kernel.Expression buildError(Arguments arguments,
- {bool isGetter: false, bool isSetter: false, int offset});
-
- DartType buildErroneousTypeNotAPrefix(Identifier suffix);
-
- Name get name => unsupported("name", offsetForToken(token), uri);
-
- @override
- String get plainNameForRead => name.name;
-
- withReceiver(Object receiver, int operatorOffset, {bool isNullAware}) => this;
-
- @override
- Initializer buildFieldInitializer(Map<String, int> initializedFields) {
- return helper.buildInvalidInitializer(
- buildError(forest.argumentsEmpty(noLocation), isSetter: true));
- }
-
- @override
- doInvocation(int offset, Arguments arguments) {
- return buildError(arguments, offset: offset);
- }
-
- @override
- buildPropertyAccess(
- IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
- return this;
- }
-
- @override
- buildThrowNoSuchMethodError(kernel.Expression receiver, Arguments arguments,
- {bool isSuper: false,
- bool isGetter: false,
- bool isSetter: false,
- bool isStatic: false,
- String name,
- int offset,
- LocatedMessage argMessage}) {
- return this;
- }
-
- @override
- kernel.Expression buildAssignment(kernel.Expression value,
- {bool voidContext: false}) {
- return buildError(forest.arguments(<kernel.Expression>[value], noLocation),
- isSetter: true);
- }
-
- @override
- kernel.Expression buildCompoundAssignment(
- Name binaryOperator, kernel.Expression value,
- {int offset: TreeNode.noOffset,
- bool voidContext: false,
- Procedure interfaceTarget,
- bool isPreIncDec: false}) {
- return buildError(forest.arguments(<kernel.Expression>[value], token),
- isGetter: true);
- }
-
- @override
- kernel.Expression buildPrefixIncrement(Name binaryOperator,
- {int offset: TreeNode.noOffset,
- bool voidContext: false,
- Procedure interfaceTarget}) {
- // TODO(ahe): For the Analyzer, we probably need to build a prefix
- // increment node that wraps an error.
- return buildError(
- forest.arguments(<kernel.Expression>[
- storeOffset(forest.literalInt(1, null), offset)
- ], noLocation),
- isGetter: true);
- }
-
- @override
- kernel.Expression buildPostfixIncrement(Name binaryOperator,
- {int offset: TreeNode.noOffset,
- bool voidContext: false,
- Procedure interfaceTarget}) {
- // TODO(ahe): For the Analyzer, we probably need to build a post increment
- // node that wraps an error.
- return buildError(
- forest.arguments(<kernel.Expression>[
- storeOffset(forest.literalInt(1, null), offset)
- ], noLocation),
- isGetter: true);
- }
-
- @override
- kernel.Expression buildNullAwareAssignment(
- kernel.Expression value, DartType type, int offset,
- {bool voidContext: false}) {
- return buildError(forest.arguments(<kernel.Expression>[value], noLocation),
- isSetter: true);
- }
-
- @override
- kernel.Expression buildSimpleRead() =>
- buildError(forest.argumentsEmpty(noLocation), isGetter: true);
-
- @override
- kernel.Expression makeInvalidRead() =>
- buildError(forest.argumentsEmpty(noLocation), isGetter: true);
-
- @override
- kernel.Expression makeInvalidWrite(kernel.Expression value) {
- return buildError(forest.arguments(<kernel.Expression>[value], noLocation),
- isSetter: true);
- }
-}
-
-class ThisAccessGenerator<Arguments> extends Generator<Arguments> {
- final bool isInitializer;
-
- final bool isSuper;
-
- ThisAccessGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- this.isInitializer,
- {this.isSuper: false})
- : super(helper, token);
-
- String get plainNameForRead {
- return unsupported("${isSuper ? 'super' : 'this'}.plainNameForRead",
- offsetForToken(token), uri);
- }
-
- String get debugName => "ThisAccessGenerator";
-
- kernel.Expression buildSimpleRead() {
- if (!isSuper) {
- return forest.thisExpression(token);
- } else {
- return helper.buildCompileTimeError(messageSuperAsExpression,
- offsetForToken(token), lengthForToken(token));
- }
- }
-
- @override
- Initializer buildFieldInitializer(Map<String, int> initializedFields) {
- String keyword = isSuper ? "super" : "this";
- int offset = offsetForToken(token);
- return helper.buildInvalidInitializer(
- helper.deprecated_buildCompileTimeError(
- "Can't use '$keyword' here, did you mean '$keyword()'?", offset),
- offset);
- }
-
- buildPropertyAccess(
- IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
- Name name = send.name;
- Arguments arguments = send.arguments;
- int offset = offsetForToken(send.token);
- if (isInitializer && send is SendAccessGenerator) {
- if (isNullAware) {
- helper.deprecated_addCompileTimeError(
- operatorOffset, "Expected '.'\nTry removing '?'.");
- }
- return buildConstructorInitializer(offset, name, arguments);
- }
- Member getter = helper.lookupInstanceMember(name, isSuper: isSuper);
- if (send is SendAccessGenerator) {
- // Notice that 'this' or 'super' can't be null. So we can ignore the
- // value of [isNullAware].
- if (getter == null) {
- helper.warnUnresolvedMethod(name, offsetForToken(send.token),
- isSuper: isSuper);
- }
- return helper.buildMethodInvocation(forest.thisExpression(null), name,
- send.arguments, offsetForToken(send.token),
- isSuper: isSuper, interfaceTarget: getter);
- } else {
- Member setter =
- helper.lookupInstanceMember(name, isSuper: isSuper, isSetter: true);
- if (isSuper) {
- return new SuperPropertyAccessGenerator(
- helper, send.token, name, getter, setter);
- } else {
- return new ThisPropertyAccessGenerator(
- helper, send.token, name, getter, setter);
- }
- }
- }
-
- doInvocation(int offset, Arguments arguments) {
- if (isInitializer) {
- return buildConstructorInitializer(offset, new Name(""), arguments);
- } else if (isSuper) {
- return helper.buildCompileTimeError(
- messageSuperAsExpression, offset, noLength);
- } else {
- return helper.buildMethodInvocation(
- forest.thisExpression(null), callName, arguments, offset,
- isImplicitCall: true);
- }
- }
-
- Initializer buildConstructorInitializer(
- int offset, Name name, Arguments arguments) {
- Constructor constructor = helper.lookupConstructor(name, isSuper: isSuper);
- LocatedMessage argMessage;
- if (constructor != null) {
- argMessage = helper.checkArgumentsForFunction(
- constructor.function, arguments, offset, <TypeParameter>[]);
- }
- if (constructor == null || argMessage != null) {
- return helper.buildInvalidInitializer(
- buildThrowNoSuchMethodError(
- storeOffset(forest.literalNull(null), offset), arguments,
- isSuper: isSuper,
- name: name.name,
- offset: offset,
- argMessage: argMessage),
- offset);
- } else if (isSuper) {
- return helper.buildSuperInitializer(
- false, constructor, arguments, offset);
- } else {
- return helper.buildRedirectingInitializer(constructor, arguments, offset);
- }
- }
-
- kernel.Expression buildAssignment(kernel.Expression value,
- {bool voidContext: false}) {
- return buildAssignmentError();
- }
-
- kernel.Expression buildNullAwareAssignment(
- kernel.Expression value, DartType type, int offset,
- {bool voidContext: false}) {
- return buildAssignmentError();
- }
-
- kernel.Expression buildCompoundAssignment(
- Name binaryOperator, kernel.Expression value,
- {int offset: TreeNode.noOffset,
- bool voidContext: false,
- Procedure interfaceTarget,
- bool isPreIncDec: false}) {
- return buildAssignmentError();
- }
-
- kernel.Expression buildPrefixIncrement(Name binaryOperator,
- {int offset: TreeNode.noOffset,
- bool voidContext: false,
- Procedure interfaceTarget}) {
- return buildAssignmentError();
- }
-
- kernel.Expression buildPostfixIncrement(Name binaryOperator,
- {int offset: TreeNode.noOffset,
- bool voidContext: false,
- Procedure interfaceTarget}) {
- return buildAssignmentError();
- }
-
- kernel.Expression buildAssignmentError() {
- String message =
- isSuper ? "Can't assign to 'super'." : "Can't assign to 'this'.";
- return helper.deprecated_buildCompileTimeError(
- message, offsetForToken(token));
- }
-
- @override
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- return unsupported("_makeRead", offsetForToken(token), uri);
- }
-
- @override
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- return unsupported("_makeWrite", offsetForToken(token), uri);
- }
-
- @override
- void printOn(StringSink sink) {
- sink.write(", isInitializer: ");
- sink.write(isInitializer);
- sink.write(", isSuper: ");
- sink.write(isSuper);
- }
-}
-
-abstract class IncompleteSendGenerator<Arguments> extends Generator<Arguments> {
- final Name name;
-
- IncompleteSendGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- this.name)
- : super(helper, token);
-
- withReceiver(Object receiver, int operatorOffset, {bool isNullAware});
-
- Arguments get arguments => null;
-
- @override
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- return unsupported("_makeRead", offsetForToken(token), uri);
- }
-
- @override
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- return unsupported("_makeWrite", offsetForToken(token), uri);
- }
-
- @override
- void printOn(StringSink sink) {
- sink.write(", name: ");
- sink.write(name.name);
- }
-}
-
-class UnresolvedNameGenerator<Arguments> extends Generator<Arguments>
- with ErroneousExpressionGenerator<Arguments> {
- @override
- final Name name;
-
- UnresolvedNameGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- this.name)
- : super(helper, token);
-
- String get debugName => "UnresolvedNameGenerator";
-
- kernel.Expression doInvocation(int charOffset, Arguments arguments) {
- return buildError(arguments, offset: charOffset);
- }
-
- @override
- DartType buildErroneousTypeNotAPrefix(Identifier suffix) {
- helper.addProblem(
- templateUnresolvedPrefixInTypeAnnotation.withArguments(
- name.name, suffix.name),
- offsetForToken(token),
- lengthOfSpan(token, suffix.token));
- return const InvalidType();
- }
-
- @override
- kernel.Expression buildError(Arguments arguments,
- {bool isGetter: false, bool isSetter: false, int offset}) {
- offset ??= offsetForToken(this.token);
- return helper.throwNoSuchMethodError(
- storeOffset(forest.literalNull(null), offset),
- plainNameForRead,
- arguments,
- offset,
- isGetter: isGetter,
- isSetter: isSetter);
- }
-
- @override
- kernel.Expression _makeRead(ShadowComplexAssignment complexAssignment) {
- return unsupported("_makeRead", offsetForToken(token), uri);
- }
-
- @override
- kernel.Expression _makeWrite(kernel.Expression value, bool voidContext,
- ShadowComplexAssignment complexAssignment) {
- return unsupported("_makeWrite", offsetForToken(token), uri);
- }
-
- @override
- void printOn(StringSink sink) {
- sink.write(", name: ");
- sink.write(name.name);
- }
-}
-
-class IncompleteErrorGenerator<Arguments>
- extends IncompleteSendGenerator<Arguments>
- with ErroneousExpressionGenerator<Arguments> {
- final Message message;
-
- IncompleteErrorGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- this.message)
- : super(helper, token, null);
-
- String get debugName => "IncompleteErrorGenerator";
-
- @override
- kernel.Expression buildError(Arguments arguments,
- {bool isGetter: false, bool isSetter: false, int offset}) {
- int length = noLength;
- if (offset == null) {
- offset = offsetForToken(token);
- length = lengthForToken(token);
- }
- return helper.buildCompileTimeError(message, offset, length);
- }
-
- @override
- DartType buildErroneousTypeNotAPrefix(Identifier suffix) {
- helper.addProblem(
- templateNotAPrefixInTypeAnnotation.withArguments(
- token.lexeme, suffix.name),
- offsetForToken(token),
- lengthOfSpan(token, suffix.token));
- return const InvalidType();
- }
-
- @override
- doInvocation(int offset, Arguments arguments) => this;
-
- @override
- void printOn(StringSink sink) {
- sink.write(", message: ");
- sink.write(message.code.name);
- }
-}
-
-class SendAccessGenerator<Arguments>
- extends IncompleteSendGenerator<Arguments> {
- @override
- final Arguments arguments;
-
- SendAccessGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- Name name,
- this.arguments)
- : super(helper, token, name) {
- assert(arguments != null);
- }
-
- String get plainNameForRead => name.name;
-
- String get debugName => "SendAccessGenerator";
-
- kernel.Expression buildSimpleRead() {
- return unsupported("buildSimpleRead", offsetForToken(token), uri);
- }
-
- kernel.Expression buildAssignment(kernel.Expression value,
- {bool voidContext: false}) {
- return unsupported("buildAssignment", offsetForToken(token), uri);
- }
-
- withReceiver(Object receiver, int operatorOffset, {bool isNullAware: false}) {
- if (receiver is Generator) {
- return receiver.buildPropertyAccess(this, operatorOffset, isNullAware);
- }
- if (receiver is PrefixBuilder) {
- PrefixBuilder prefix = receiver;
- if (isNullAware) {
- helper.deprecated_addCompileTimeError(
- offsetForToken(token),
- "Library prefix '${prefix.name}' can't be used with null-aware "
- "operator.\nTry removing '?'.");
- }
- receiver = helper.scopeLookup(prefix.exportScope, name.name, token,
- isQualified: true, prefix: prefix);
- return helper.finishSend(receiver, arguments, offsetForToken(token));
- }
- return helper.buildMethodInvocation(
- helper.toValue(receiver), name, arguments, offsetForToken(token),
- isNullAware: isNullAware);
- }
-
- kernel.Expression buildNullAwareAssignment(
- kernel.Expression value, DartType type, int offset,
- {bool voidContext: false}) {
- return unsupported("buildNullAwareAssignment", offset, uri);
- }
-
- kernel.Expression buildCompoundAssignment(
- Name binaryOperator, kernel.Expression value,
- {int offset,
- bool voidContext: false,
- Procedure interfaceTarget,
- bool isPreIncDec: false}) {
- return unsupported(
- "buildCompoundAssignment", offset ?? offsetForToken(token), uri);
- }
-
- kernel.Expression buildPrefixIncrement(Name binaryOperator,
- {int offset, bool voidContext: false, Procedure interfaceTarget}) {
- return unsupported(
- "buildPrefixIncrement", offset ?? offsetForToken(token), uri);
- }
-
- kernel.Expression buildPostfixIncrement(Name binaryOperator,
- {int offset, bool voidContext: false, Procedure interfaceTarget}) {
- return unsupported(
- "buildPostfixIncrement", offset ?? offsetForToken(token), uri);
- }
-
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- return unsupported("doInvocation", offset, uri);
- }
-
- @override
- void printOn(StringSink sink) {
- super.printOn(sink);
- sink.write(", arguments: ");
- var node = arguments;
- if (node is kernel.Node) {
- printNodeOn(node, sink);
- } else {
- sink.write(node);
- }
- }
-}
-
-class IncompletePropertyAccessGenerator<Arguments>
- extends IncompleteSendGenerator<Arguments> {
- IncompletePropertyAccessGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- Name name)
- : super(helper, token, name);
-
- String get plainNameForRead => name.name;
-
- String get debugName => "IncompletePropertyAccessGenerator";
-
- kernel.Expression buildSimpleRead() {
- return unsupported("buildSimpleRead", offsetForToken(token), uri);
- }
-
- kernel.Expression buildAssignment(kernel.Expression value,
- {bool voidContext: false}) {
- return unsupported("buildAssignment", offsetForToken(token), uri);
- }
-
- withReceiver(Object receiver, int operatorOffset, {bool isNullAware: false}) {
- if (receiver is Generator) {
- return receiver.buildPropertyAccess(this, operatorOffset, isNullAware);
- }
- if (receiver is PrefixBuilder) {
- PrefixBuilder prefix = receiver;
- if (isNullAware) {
- helper.deprecated_addCompileTimeError(
- offsetForToken(token),
- "Library prefix '${prefix.name}' can't be used with null-aware "
- "operator.\nTry removing '?'.");
- }
- return helper.scopeLookup(prefix.exportScope, name.name, token,
- isQualified: true, prefix: prefix);
- }
-
- return PropertyAccessGenerator.make(
- helper, token, helper.toValue(receiver), name, null, null, isNullAware);
- }
-
- kernel.Expression buildNullAwareAssignment(
- kernel.Expression value, DartType type, int offset,
- {bool voidContext: false}) {
- return unsupported("buildNullAwareAssignment", offset, uri);
- }
-
- kernel.Expression buildCompoundAssignment(
- Name binaryOperator, kernel.Expression value,
- {int offset,
- bool voidContext: false,
- Procedure interfaceTarget,
- bool isPreIncDec: false}) {
- return unsupported(
- "buildCompoundAssignment", offset ?? offsetForToken(token), uri);
- }
-
- kernel.Expression buildPrefixIncrement(Name binaryOperator,
- {int offset, bool voidContext: false, Procedure interfaceTarget}) {
- return unsupported(
- "buildPrefixIncrement", offset ?? offsetForToken(token), uri);
- }
-
- kernel.Expression buildPostfixIncrement(Name binaryOperator,
- {int offset, bool voidContext: false, Procedure interfaceTarget}) {
- return unsupported(
- "buildPostfixIncrement", offset ?? offsetForToken(token), uri);
- }
-
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- return unsupported("doInvocation", offset, uri);
- }
-}
-
-class ParenthesizedExpressionGenerator<Arguments>
- extends ReadOnlyAccessGenerator<Arguments> {
- ParenthesizedExpressionGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- kernel.Expression expression)
- : super(helper, token, expression, null);
-
- String get debugName => "ParenthesizedExpressionGenerator";
-
- kernel.Expression makeInvalidWrite(kernel.Expression value) {
- return helper.deprecated_buildCompileTimeError(
- "Can't assign to a parenthesized expression.", offsetForToken(token));
- }
-}
-
-class TypeDeclarationAccessGenerator<Arguments>
- extends ReadOnlyAccessGenerator<Arguments> {
- /// The import prefix preceding the [declaration] reference, or `null` if
- /// the reference is not prefixed.
- final PrefixBuilder prefix;
-
- /// The offset at which the [declaration] is referenced by this generator,
- /// or `-1` if the reference is implicit.
- final int declarationReferenceOffset;
-
- final TypeDeclarationBuilder declaration;
-
- TypeDeclarationAccessGenerator(
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- Token token,
- this.prefix,
- this.declarationReferenceOffset,
- this.declaration,
- String plainNameForRead)
- : super(helper, token, null, plainNameForRead);
-
- String get debugName => "TypeDeclarationAccessGenerator";
-
- kernel.Expression get expression {
- if (super.expression == null) {
- int offset = offsetForToken(token);
- if (declaration is KernelInvalidTypeBuilder) {
- KernelInvalidTypeBuilder declaration = this.declaration;
- helper.addProblemErrorIfConst(
- declaration.message.messageObject, offset, token.length);
- super.expression =
- new Throw(forest.literalString(declaration.message.message, token))
- ..fileOffset = offset;
- } else {
- super.expression = forest.literalType(
- buildTypeWithBuiltArguments(null, nonInstanceAccessIsError: true),
- token);
- }
- }
- return super.expression;
- }
-
- kernel.Expression makeInvalidWrite(kernel.Expression value) {
- return buildThrowNoSuchMethodError(
- forest.literalNull(token),
- storeOffset(forest.arguments(<kernel.Expression>[value], null),
- value.fileOffset),
- isSetter: true);
- }
-
- @override
- buildPropertyAccess(
- IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
- // `SomeType?.toString` is the same as `SomeType.toString`, not
- // `(SomeType).toString`.
- isNullAware = false;
-
- Name name = send.name;
- Arguments arguments = send.arguments;
-
- if (declaration is KernelClassBuilder) {
- KernelClassBuilder declaration = this.declaration;
- Builder builder = declaration.findStaticBuilder(
- name.name, offsetForToken(token), uri, helper.library);
-
- Generator generator;
- if (builder == null) {
- // If we find a setter, [builder] is an [AccessErrorBuilder], not null.
- if (send is IncompletePropertyAccessGenerator) {
- generator = new UnresolvedNameGenerator(helper, send.token, name);
- } else {
- return helper.buildConstructorInvocation(declaration, send.token,
- arguments, name.name, null, token.charOffset, Constness.implicit);
- }
- } else {
- Builder setter;
- if (builder.isSetter) {
- setter = builder;
- } else if (builder.isGetter) {
- setter = declaration.findStaticBuilder(
- name.name, offsetForToken(token), uri, helper.library,
- isSetter: true);
- } else if (builder.isField && !builder.isFinal) {
- setter = builder;
- }
- generator = new StaticAccessGenerator.fromBuilder(
- helper, builder, send.token, setter);
- }
-
- return arguments == null
- ? generator
- : generator.doInvocation(offsetForToken(send.token), arguments);
- } else {
- return super.buildPropertyAccess(send, operatorOffset, isNullAware);
- }
- }
-
- @override
- DartType buildTypeWithBuiltArguments(List<DartType> arguments,
- {bool nonInstanceAccessIsError: false}) {
- if (arguments != null) {
- int expected = 0;
- if (declaration is KernelClassBuilder) {
- expected = declaration.target.typeParameters.length;
- } else if (declaration is FunctionTypeAliasBuilder) {
- expected = declaration.target.typeParameters.length;
- } else if (declaration is KernelTypeVariableBuilder) {
- // Type arguments on a type variable - error reported elsewhere.
- } else if (declaration is BuiltinTypeBuilder) {
- // Type arguments on a built-in type, for example, dynamic or void.
- expected = 0;
- } else {
- return unhandled(
- "${declaration.runtimeType}",
- "TypeDeclarationAccessGenerator.buildType",
- offsetForToken(token),
- helper.uri);
- }
- if (arguments.length != expected) {
- helper.warnTypeArgumentsMismatch(
- declaration.name, expected, offsetForToken(token));
- // We ignore the provided arguments, which will in turn return the
- // raw type below.
- // TODO(sigmund): change to use an InvalidType and include the raw type
- // as a recovery node once the IR can represent it (Issue #29840).
- arguments = null;
- }
- }
-
- DartType type;
- if (arguments == null) {
- TypeDeclarationBuilder typeDeclaration = declaration;
- if (typeDeclaration is KernelClassBuilder) {
- type = typeDeclaration.buildType(helper.library, null);
- } else if (typeDeclaration is KernelFunctionTypeAliasBuilder) {
- type = typeDeclaration.buildType(helper.library, null);
- }
- }
- if (type == null) {
- type =
- declaration.buildTypesWithBuiltArguments(helper.library, arguments);
- }
- if (type is TypeParameterType) {
- return helper.validatedTypeVariableUse(
- type, offsetForToken(token), nonInstanceAccessIsError);
- }
- return type;
- }
-
- @override
- kernel.Expression doInvocation(int offset, Arguments arguments) {
- return helper.buildConstructorInvocation(declaration, token, arguments, "",
- null, token.charOffset, Constness.implicit);
- }
-}
-
-kernel.Expression makeLet(
- VariableDeclaration variable, kernel.Expression body) {
- if (variable == null) return body;
- return new Let(variable, body);
-}
-
-kernel.Expression makeBinary<Arguments>(
- kernel.Expression left,
- Name operator,
- Procedure interfaceTarget,
- kernel.Expression right,
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
- {int offset: TreeNode.noOffset}) {
- return new ShadowMethodInvocation(
- left,
- operator,
- helper.storeOffset(
- helper.forest.castArguments(
- helper.forest.arguments(<kernel.Expression>[right], null)),
- offset),
- interfaceTarget: interfaceTarget)
- ..fileOffset = offset;
-}
-
-kernel.Expression buildIsNull<Arguments>(kernel.Expression value, int offset,
- ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper) {
- return makeBinary(value, equalsName, null,
- helper.storeOffset(helper.forest.literalNull(null), offset), helper,
- offset: offset);
-}
-
-VariableDeclaration makeOrReuseVariable(kernel.Expression value) {
- // TODO: Devise a way to remember if a variable declaration was reused
- // or is fresh (hence needs a let binding).
- return new VariableDeclaration.forValue(value);
-}
-
-int adjustForImplicitCall(String name, int offset) {
- // Normally the offset is at the start of the token, but in this case,
- // because we insert a '.call', we want it at the end instead.
- return offset + (name?.length ?? 0);
-}
-
-bool isFieldOrGetter(Member member) {
- return member is Field || (member is Procedure && member.isGetter);
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
index 5af746c..4d3404a 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
@@ -14,6 +14,8 @@
import '../scope.dart' show ProblemBuilder, Scope;
+import '../type_inference/inference_helper.dart' show InferenceHelper;
+
import '../type_inference/type_promotion.dart' show TypePromoter;
import 'constness.dart' show Constness;
@@ -43,7 +45,8 @@
PrefixBuilder,
TypeDeclarationBuilder;
-abstract class ExpressionGeneratorHelper<Expression, Statement, Arguments> {
+abstract class ExpressionGeneratorHelper<Expression, Statement, Arguments>
+ implements InferenceHelper<Expression, Statement, Arguments> {
LibraryBuilder get library;
Uri get uri;
diff --git a/pkg/front_end/lib/src/fasta/kernel/fangorn.dart b/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
index 49330c6..1490aff 100644
--- a/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/fangorn.dart
@@ -10,8 +10,8 @@
show
Arguments,
AssertInitializer,
- BreakStatement,
Block,
+ BreakStatement,
Catch,
ContinueSwitchStatement,
DartType,
@@ -23,7 +23,10 @@
Let,
LibraryDependency,
MapEntry,
+ Member,
+ Name,
NamedExpression,
+ Procedure,
Statement,
SwitchCase,
ThisExpression,
@@ -37,6 +40,16 @@
import '../scanner.dart' show Token;
+import 'kernel_expression_generator.dart'
+ show
+ KernelIndexedAccessGenerator,
+ KernelNullAwarePropertyAccessGenerator,
+ KernelPropertyAccessGenerator,
+ KernelSuperPropertyAccessGenerator,
+ KernelThisIndexedAccessGenerator,
+ KernelThisPropertyAccessGenerator,
+ KernelVariableUseGenerator;
+
import 'kernel_shadow_ast.dart'
show
ShadowArguments,
@@ -52,6 +65,7 @@
ShadowDoStatement,
ShadowDoubleLiteral,
ShadowExpressionStatement,
+ ShadowForStatement,
ShadowIfStatement,
ShadowIntLiteral,
ShadowIsExpression,
@@ -76,7 +90,7 @@
ShadowWhileStatement,
ShadowYieldStatement;
-import 'forest.dart' show Forest;
+import 'forest.dart' show ExpressionGeneratorHelper, Forest;
/// A shadow tree factory.
class Fangorn extends Forest<Expression, Statement, Token, Arguments> {
@@ -338,6 +352,22 @@
}
@override
+ Statement forStatement(
+ Token forKeyword,
+ Token leftParenthesis,
+ List<VariableDeclaration> variableList,
+ covariant initialization,
+ Token leftSeparator,
+ Expression condition,
+ Token rightSeparator,
+ List<Expression> updaters,
+ Token rightParenthesis,
+ Statement body) {
+ return new ShadowForStatement(variableList, condition, updaters, body)
+ ..fileOffset = forKeyword.charOffset;
+ }
+
+ @override
Statement ifStatement(Token ifKeyword, Expression condition,
Statement thenStatement, Token elseKeyword, Statement elseStatement) {
return new ShadowIfStatement(condition, thenStatement, elseStatement)
@@ -454,9 +484,20 @@
}
@override
+ Expression getExpressionFromExpressionStatement(Statement statement) {
+ return (statement as ExpressionStatement).expression;
+ }
+
+ @override
+ Token getSemicolon(Statement statement) => null;
+
+ @override
bool isBlock(Object node) => node is Block;
@override
+ bool isEmptyStatement(Statement statement) => statement is EmptyStatement;
+
+ @override
bool isErroneousNode(Object node) {
if (node is ExpressionStatement) {
ExpressionStatement statement = node;
@@ -478,6 +519,10 @@
}
@override
+ bool isExpressionStatement(Statement statement) =>
+ statement is ExpressionStatement;
+
+ @override
bool isThisExpression(Object node) => node is ThisExpression;
@override
@@ -498,6 +543,86 @@
SwitchCase target, ContinueSwitchStatement user) {
user.target = target;
}
+
+ @override
+ KernelVariableUseGenerator variableUseGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Token token,
+ VariableDeclaration variable,
+ DartType promotedType) {
+ return new KernelVariableUseGenerator(
+ helper, token, variable, promotedType);
+ }
+
+ @override
+ KernelPropertyAccessGenerator propertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Token token,
+ Expression receiver,
+ Name name,
+ Member getter,
+ Member setter) {
+ return new KernelPropertyAccessGenerator.internal(
+ helper, token, receiver, name, getter, setter);
+ }
+
+ @override
+ KernelThisPropertyAccessGenerator thisPropertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Token token,
+ Name name,
+ Member getter,
+ Member setter) {
+ return new KernelThisPropertyAccessGenerator(
+ helper, token, name, getter, setter);
+ }
+
+ @override
+ KernelNullAwarePropertyAccessGenerator nullAwarePropertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Token token,
+ Expression receiverExpression,
+ Name name,
+ Member getter,
+ Member setter,
+ DartType type) {
+ return new KernelNullAwarePropertyAccessGenerator(
+ helper, token, receiverExpression, name, getter, setter, type);
+ }
+
+ @override
+ KernelSuperPropertyAccessGenerator superPropertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Token token,
+ Name name,
+ Member getter,
+ Member setter) {
+ return new KernelSuperPropertyAccessGenerator(
+ helper, token, name, getter, setter);
+ }
+
+ @override
+ KernelIndexedAccessGenerator indexedAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Token token,
+ Expression receiver,
+ Expression index,
+ Procedure getter,
+ Procedure setter) {
+ return new KernelIndexedAccessGenerator.internal(
+ helper, token, receiver, index, getter, setter);
+ }
+
+ @override
+ KernelThisIndexedAccessGenerator thisIndexedAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Token token,
+ Expression index,
+ Procedure getter,
+ Procedure setter) {
+ return new KernelThisIndexedAccessGenerator(
+ helper, token, index, getter, setter);
+ }
}
class _VariablesDeclaration extends Statement {
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index f7a8b61..2589526 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -4,13 +4,26 @@
library fasta.forest;
-// TODO(ahe): Remove this import.
-import 'package:kernel/ast.dart' as kernel show Arguments, DartType;
+import 'package:kernel/ast.dart' as kernel
+ show
+ Arguments, // TODO(ahe): Remove this import.
+ DartType,
+ Member,
+ Name,
+ Procedure;
import 'body_builder.dart' show Identifier;
+import 'expression_generator.dart' show Generator;
+
+import 'expression_generator_helper.dart' show ExpressionGeneratorHelper;
+
export 'body_builder.dart' show Identifier, Operator;
+export 'expression_generator.dart' show Generator;
+
+export 'expression_generator_helper.dart' show ExpressionGeneratorHelper;
+
/// A tree factory.
///
/// For now, the [Location] is always a token.
@@ -188,6 +201,19 @@
/// [semicolon].
Statement emptyStatement(Location semicolon);
+ /// Return a representation of a for statement.
+ Statement forStatement(
+ Location forKeyword,
+ Location leftParenthesis,
+ covariant variableList,
+ covariant initialization,
+ Location leftSeparator,
+ Expression condition,
+ Location rightSeparator,
+ List<Expression> updaters,
+ Location rightParenthesis,
+ Statement body);
+
/// Return a representation of an `if` statement.
Statement ifStatement(Location ifKeyword, covariant Expression condition,
Statement thenStatement, Location elseKeyword, Statement elseStatement);
@@ -257,10 +283,25 @@
Statement yieldStatement(Location yieldKeyword, Location star,
Expression expression, Location semicolon);
+ /// Return the expression from the given expression [statement].
+ Expression getExpressionFromExpressionStatement(Statement statement);
+
+ /// Return the semicolon at the end of the given [statement], or `null` if the
+ /// statement is not terminated by a semicolon.
+ Location getSemicolon(Statement statement);
+
bool isBlock(Object node);
+ /// Return `true` if the given [statement] is the representation of an empty
+ /// statement.
+ bool isEmptyStatement(Statement statement);
+
bool isErroneousNode(Object node);
+ /// Return `true` if the given [statement] is the representation of an
+ /// expression statement.
+ bool isExpressionStatement(Statement statement);
+
bool isThisExpression(Object node);
bool isVariablesDeclaration(Object node);
@@ -278,6 +319,58 @@
void resolveContinueInSwitch(
covariant Object target, covariant Statement user);
+ Generator<Expression, Statement, Arguments> variableUseGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Location location,
+ covariant variable,
+ kernel.DartType promotedType);
+
+ Generator<Expression, Statement, Arguments> propertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Location location,
+ Expression receiver,
+ kernel.Name name,
+ kernel.Member getter,
+ kernel.Member setter);
+
+ Generator<Expression, Statement, Arguments> thisPropertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Location location,
+ kernel.Name name,
+ kernel.Member getter,
+ kernel.Member setter);
+
+ Generator<Expression, Statement, Arguments> nullAwarePropertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Location location,
+ Expression receiverExpression,
+ kernel.Name name,
+ kernel.Member getter,
+ kernel.Member setter,
+ kernel.DartType type);
+
+ Generator<Expression, Statement, Arguments> superPropertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Location location,
+ kernel.Name name,
+ kernel.Member getter,
+ kernel.Member setter);
+
+ Generator<Expression, Statement, Arguments> indexedAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Location location,
+ Expression receiver,
+ Expression index,
+ kernel.Procedure getter,
+ kernel.Procedure setter);
+
+ Generator<Expression, Statement, Arguments> thisIndexedAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Location location,
+ Expression index,
+ kernel.Procedure getter,
+ kernel.Procedure setter);
+
// TODO(ahe): Remove this method when all users are moved here.
kernel.Arguments castArguments(Arguments arguments) {
dynamic a = arguments;
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
index 6817deb..33906b3 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
@@ -76,7 +76,6 @@
ShadowFactoryConstructorInvocation,
ShadowFieldInitializer,
ShadowForInStatement,
- ShadowForStatement,
ShadowFunctionDeclaration,
ShadowFunctionExpression,
ShadowIfNullExpression,
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator.dart
new file mode 100644
index 0000000..218f9f9
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator.dart
@@ -0,0 +1,991 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// 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:kernel/ast.dart' show Arguments, Expression, Node, Statement;
+
+import '../../scanner/token.dart' show Token;
+
+import '../constant_context.dart' show ConstantContext;
+
+import '../fasta_codes.dart'
+ show
+ LocatedMessage,
+ messageLoadLibraryTakesNoArguments,
+ messageSuperAsExpression,
+ templateDeferredTypeAnnotation,
+ templateIntegerLiteralIsOutOfRange,
+ templateNotAPrefixInTypeAnnotation,
+ templateUnresolvedPrefixInTypeAnnotation;
+
+import '../messages.dart' show Message, noLength;
+
+import '../names.dart'
+ show
+ ampersandName,
+ barName,
+ callName,
+ caretName,
+ divisionName,
+ equalsName,
+ indexGetName,
+ indexSetName,
+ leftShiftName,
+ minusName,
+ multiplyName,
+ mustacheName,
+ percentName,
+ plusName,
+ rightShiftName;
+
+import '../parser.dart' show lengthForToken, lengthOfSpan, offsetForToken;
+
+import '../problems.dart' show unhandled, unsupported;
+
+import '../scope.dart' show AccessErrorBuilder;
+
+import 'body_builder.dart' show Identifier, noLocation;
+
+import 'constness.dart' show Constness;
+
+import 'expression_generator.dart'
+ show
+ ExpressionGenerator,
+ Generator,
+ IndexedAccessGenerator,
+ NullAwarePropertyAccessGenerator,
+ PropertyAccessGenerator,
+ SuperPropertyAccessGenerator,
+ ThisIndexedAccessGenerator,
+ ThisPropertyAccessGenerator,
+ VariableUseGenerator;
+
+import 'expression_generator_helper.dart' show ExpressionGeneratorHelper;
+
+import 'forest.dart' show Forest;
+
+import 'kernel_builder.dart' show LoadLibraryBuilder, PrefixBuilder;
+
+import 'kernel_api.dart' show NameSystem, printNodeOn, printQualifiedNameOn;
+
+import 'kernel_ast_api.dart'
+ show
+ Constructor,
+ DartType,
+ DynamicType,
+ Field,
+ Initializer,
+ InvalidType,
+ Let,
+ Member,
+ Name,
+ Procedure,
+ PropertySet,
+ ShadowComplexAssignment,
+ ShadowIllegalAssignment,
+ ShadowIndexAssign,
+ ShadowMethodInvocation,
+ ShadowNullAwarePropertyGet,
+ ShadowPropertyAssign,
+ ShadowPropertyGet,
+ ShadowStaticAssignment,
+ ShadowSuperMethodInvocation,
+ ShadowSuperPropertyGet,
+ ShadowVariableAssignment,
+ ShadowVariableDeclaration,
+ ShadowVariableGet,
+ StaticSet,
+ SuperMethodInvocation,
+ SuperPropertySet,
+ Throw,
+ TreeNode,
+ TypeParameter,
+ TypeParameterType,
+ VariableDeclaration,
+ VariableGet,
+ VariableSet;
+
+import 'kernel_builder.dart'
+ show
+ Builder,
+ BuiltinTypeBuilder,
+ FunctionTypeAliasBuilder,
+ KernelClassBuilder,
+ KernelFunctionTypeAliasBuilder,
+ KernelInvalidTypeBuilder,
+ KernelTypeVariableBuilder,
+ LoadLibraryBuilder,
+ PrefixBuilder,
+ TypeDeclarationBuilder;
+
+part 'kernel_expression_generator_impl.dart';
+
+abstract class KernelExpressionGenerator
+ implements ExpressionGenerator<Expression, Statement, Arguments> {
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> get helper;
+
+ Token get token;
+
+ Forest<Expression, Statement, Token, Arguments> get forest;
+
+ @override
+ Expression buildSimpleRead() {
+ return _finish(_makeSimpleRead(), null);
+ }
+
+ @override
+ Expression buildAssignment(Expression value, {bool voidContext: false}) {
+ var complexAssignment = startComplexAssignment(value);
+ return _finish(_makeSimpleWrite(value, voidContext, complexAssignment),
+ complexAssignment);
+ }
+
+ @override
+ Expression buildNullAwareAssignment(
+ Expression value, DartType type, int offset,
+ {bool voidContext: false}) {
+ var complexAssignment = startComplexAssignment(value);
+ if (voidContext) {
+ var nullAwareCombiner = helper.storeOffset(
+ forest.conditionalExpression(
+ buildIsNull(_makeRead(complexAssignment), offset, helper),
+ null,
+ _makeWrite(value, false, complexAssignment),
+ null,
+ helper.storeOffset(forest.literalNull(null), offset)),
+ offset);
+ complexAssignment?.nullAwareCombiner = nullAwareCombiner;
+ return _finish(nullAwareCombiner, complexAssignment);
+ }
+ var tmp = new VariableDeclaration.forValue(_makeRead(complexAssignment));
+ var nullAwareCombiner = helper.storeOffset(
+ forest.conditionalExpression(
+ buildIsNull(new VariableGet(tmp), offset, helper),
+ null,
+ _makeWrite(value, false, complexAssignment),
+ null,
+ new VariableGet(tmp)),
+ offset);
+ complexAssignment?.nullAwareCombiner = nullAwareCombiner;
+ return _finish(makeLet(tmp, nullAwareCombiner), complexAssignment);
+ }
+
+ @override
+ Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+ {int offset: TreeNode.noOffset,
+ bool voidContext: false,
+ Procedure interfaceTarget,
+ bool isPreIncDec: false}) {
+ var complexAssignment = startComplexAssignment(value);
+ complexAssignment?.isPreIncDec = isPreIncDec;
+ var combiner = makeBinary(_makeRead(complexAssignment), binaryOperator,
+ interfaceTarget, value, helper,
+ offset: offset);
+ complexAssignment?.combiner = combiner;
+ return _finish(_makeWrite(combiner, voidContext, complexAssignment),
+ complexAssignment);
+ }
+
+ @override
+ Expression buildPrefixIncrement(Name binaryOperator,
+ {int offset: TreeNode.noOffset,
+ bool voidContext: false,
+ Procedure interfaceTarget}) {
+ return buildCompoundAssignment(
+ binaryOperator, helper.storeOffset(forest.literalInt(1, null), offset),
+ offset: offset,
+ voidContext: voidContext,
+ interfaceTarget: interfaceTarget,
+ isPreIncDec: true);
+ }
+
+ @override
+ Expression buildPostfixIncrement(Name binaryOperator,
+ {int offset: TreeNode.noOffset,
+ bool voidContext: false,
+ Procedure interfaceTarget}) {
+ if (voidContext) {
+ return buildPrefixIncrement(binaryOperator,
+ offset: offset, voidContext: true, interfaceTarget: interfaceTarget);
+ }
+ var rhs = helper.storeOffset(forest.literalInt(1, null), offset);
+ var complexAssignment = startComplexAssignment(rhs);
+ var value = new VariableDeclaration.forValue(_makeRead(complexAssignment));
+ valueAccess() => new VariableGet(value);
+ var combiner = makeBinary(
+ valueAccess(), binaryOperator, interfaceTarget, rhs, helper,
+ offset: offset);
+ complexAssignment?.combiner = combiner;
+ complexAssignment?.isPostIncDec = true;
+ var dummy = new ShadowVariableDeclaration.forValue(
+ _makeWrite(combiner, true, complexAssignment),
+ helper.functionNestingLevel);
+ return _finish(
+ makeLet(value, makeLet(dummy, valueAccess())), complexAssignment);
+ }
+
+ @override
+ Expression makeInvalidRead() {
+ return buildThrowNoSuchMethodError(
+ forest.literalNull(token), forest.argumentsEmpty(noLocation),
+ isGetter: true);
+ }
+
+ @override
+ Expression makeInvalidWrite(Expression value) {
+ return buildThrowNoSuchMethodError(forest.literalNull(token),
+ forest.arguments(<Expression>[value], noLocation),
+ isSetter: true);
+ }
+
+ Expression _makeSimpleRead() => _makeRead(null);
+
+ Expression _makeSimpleWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ return _makeWrite(value, voidContext, complexAssignment);
+ }
+
+ Expression _makeRead(ShadowComplexAssignment complexAssignment);
+
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment);
+
+ Expression _finish(
+ Expression body, ShadowComplexAssignment complexAssignment) {
+ if (complexAssignment != null) {
+ complexAssignment.desugared = body;
+ return complexAssignment;
+ } else {
+ return body;
+ }
+ }
+
+ /// Creates a data structure for tracking the desugaring of a complex
+ /// assignment expression whose right hand side is [rhs].
+ ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+ new ShadowIllegalAssignment(rhs);
+}
+
+abstract class KernelGenerator = Generator<Expression, Statement, Arguments>
+ with KernelExpressionGenerator;
+
+class KernelVariableUseGenerator extends KernelGenerator
+ with VariableUseGenerator<Expression, Statement, Arguments> {
+ final VariableDeclaration variable;
+
+ final DartType promotedType;
+
+ KernelVariableUseGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+ Token token,
+ this.variable,
+ this.promotedType)
+ : super(helper, token);
+
+ @override
+ String get plainNameForRead => variable.name;
+
+ @override
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ var fact = helper.typePromoter
+ .getFactForAccess(variable, helper.functionNestingLevel);
+ var scope = helper.typePromoter.currentScope;
+ var read = new ShadowVariableGet(variable, fact, scope)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.read = read;
+ return read;
+ }
+
+ @override
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ helper.typePromoter.mutateVariable(variable, helper.functionNestingLevel);
+ var write = variable.isFinal || variable.isConst
+ ? makeInvalidWrite(value)
+ : new VariableSet(variable, value)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.write = write;
+ return write;
+ }
+
+ @override
+ Expression doInvocation(int offset, Arguments arguments) {
+ return helper.buildMethodInvocation(buildSimpleRead(), callName, arguments,
+ adjustForImplicitCall(plainNameForRead, offset),
+ isImplicitCall: true);
+ }
+
+ @override
+ ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+ new ShadowVariableAssignment(rhs);
+
+ @override
+ void printOn(StringSink sink) {
+ NameSystem syntheticNames = new NameSystem();
+ sink.write(", variable: ");
+ printNodeOn(variable, sink, syntheticNames: syntheticNames);
+ sink.write(", promotedType: ");
+ printNodeOn(promotedType, sink, syntheticNames: syntheticNames);
+ }
+}
+
+class KernelPropertyAccessGenerator extends KernelGenerator
+ with PropertyAccessGenerator<Expression, Statement, Arguments> {
+ final Expression receiver;
+
+ final Name name;
+
+ final Member getter;
+
+ final Member setter;
+
+ VariableDeclaration _receiverVariable;
+
+ KernelPropertyAccessGenerator.internal(
+ ExpressionGeneratorHelper<dynamic, dynamic, Arguments> helper,
+ Token token,
+ this.receiver,
+ this.name,
+ this.getter,
+ this.setter)
+ : super(helper, token);
+
+ @override
+ String get plainNameForRead => name.name;
+
+ receiverAccess() {
+ _receiverVariable ??= new VariableDeclaration.forValue(receiver);
+ return new VariableGet(_receiverVariable)
+ ..fileOffset = offsetForToken(token);
+ }
+
+ @override
+ Expression doInvocation(int offset, Arguments arguments) {
+ return helper.buildMethodInvocation(receiver, name, arguments, offset);
+ }
+
+ @override
+ ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+ new ShadowPropertyAssign(receiver, rhs);
+
+ @override
+ void printOn(StringSink sink) {
+ NameSystem syntheticNames = new NameSystem();
+ sink.write(", _receiverVariable: ");
+ printNodeOn(_receiverVariable, sink, syntheticNames: syntheticNames);
+ sink.write(", receiver: ");
+ printNodeOn(receiver, sink, syntheticNames: syntheticNames);
+ sink.write(", name: ");
+ sink.write(name.name);
+ sink.write(", getter: ");
+ printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
+ sink.write(", setter: ");
+ printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
+ }
+
+ @override
+ Expression _makeSimpleRead() => new ShadowPropertyGet(receiver, name, getter)
+ ..fileOffset = offsetForToken(token);
+
+ @override
+ Expression _makeSimpleWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ var write = new PropertySet(receiver, name, value, setter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.write = write;
+ return write;
+ }
+
+ @override
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ var read = new ShadowPropertyGet(receiverAccess(), name, getter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.read = read;
+ return read;
+ }
+
+ @override
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ var write = new PropertySet(receiverAccess(), name, value, setter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.write = write;
+ return write;
+ }
+
+ @override
+ Expression _finish(
+ Expression body, ShadowComplexAssignment complexAssignment) {
+ return super._finish(makeLet(_receiverVariable, body), complexAssignment);
+ }
+}
+
+class KernelThisPropertyAccessGenerator extends KernelGenerator
+ with ThisPropertyAccessGenerator<Expression, Statement, Arguments> {
+ final Name name;
+
+ final Member getter;
+
+ final Member setter;
+
+ KernelThisPropertyAccessGenerator(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Token token,
+ this.name,
+ this.getter,
+ this.setter)
+ : super(helper, token);
+
+ @override
+ String get plainNameForRead => name.name;
+
+ @override
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ if (getter == null) {
+ helper.warnUnresolvedGet(name, offsetForToken(token));
+ }
+ var read = new ShadowPropertyGet(forest.thisExpression(token), name, getter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.read = read;
+ return read;
+ }
+
+ @override
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ if (setter == null) {
+ helper.warnUnresolvedSet(name, offsetForToken(token));
+ }
+ var write =
+ new PropertySet(forest.thisExpression(token), name, value, setter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.write = write;
+ return write;
+ }
+
+ @override
+ Expression doInvocation(int offset, Arguments arguments) {
+ Member interfaceTarget = getter;
+ if (interfaceTarget == null) {
+ helper.warnUnresolvedMethod(name, offset);
+ }
+ if (interfaceTarget is Field) {
+ // TODO(ahe): In strong mode we should probably rewrite this to
+ // `this.name.call(arguments)`.
+ interfaceTarget = null;
+ }
+ return helper.buildMethodInvocation(
+ forest.thisExpression(null), name, arguments, offset,
+ interfaceTarget: interfaceTarget);
+ }
+
+ @override
+ ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+ new ShadowPropertyAssign(null, rhs);
+
+ @override
+ void printOn(StringSink sink) {
+ NameSystem syntheticNames = new NameSystem();
+ sink.write(", name: ");
+ sink.write(name.name);
+ sink.write(", getter: ");
+ printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
+ sink.write(", setter: ");
+ printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
+ }
+}
+
+class KernelNullAwarePropertyAccessGenerator extends KernelGenerator
+ with NullAwarePropertyAccessGenerator<Expression, Statement, Arguments> {
+ final VariableDeclaration receiver;
+
+ final Expression receiverExpression;
+
+ final Name name;
+
+ final Member getter;
+
+ final Member setter;
+
+ final DartType type;
+
+ KernelNullAwarePropertyAccessGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ this.receiverExpression,
+ this.name,
+ this.getter,
+ this.setter,
+ this.type)
+ : this.receiver = makeOrReuseVariable(receiverExpression),
+ super(helper, token);
+
+ Expression receiverAccess() => new VariableGet(receiver);
+
+ @override
+ String get plainNameForRead => name.name;
+
+ @override
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ var read = new ShadowPropertyGet(receiverAccess(), name, getter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.read = read;
+ return read;
+ }
+
+ @override
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ var write = new PropertySet(receiverAccess(), name, value, setter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.write = write;
+ return write;
+ }
+
+ @override
+ Expression _finish(
+ Expression body, ShadowComplexAssignment complexAssignment) {
+ var offset = offsetForToken(token);
+ var nullAwareGuard = helper.storeOffset(
+ forest.conditionalExpression(
+ buildIsNull(receiverAccess(), offset, helper),
+ null,
+ helper.storeOffset(forest.literalNull(null), offset),
+ null,
+ body),
+ offset);
+ if (complexAssignment != null) {
+ body = makeLet(receiver, nullAwareGuard);
+ ShadowPropertyAssign kernelPropertyAssign = complexAssignment;
+ kernelPropertyAssign.nullAwareGuard = nullAwareGuard;
+ kernelPropertyAssign.desugared = body;
+ return kernelPropertyAssign;
+ } else {
+ return new ShadowNullAwarePropertyGet(receiver, nullAwareGuard)
+ ..fileOffset = offset;
+ }
+ }
+
+ @override
+ Expression doInvocation(int offset, Arguments arguments) {
+ return unsupported("doInvocation", offset, uri);
+ }
+
+ @override
+ ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+ new ShadowPropertyAssign(receiverExpression, rhs);
+
+ @override
+ void printOn(StringSink sink) {
+ NameSystem syntheticNames = new NameSystem();
+ sink.write(", receiver: ");
+ printNodeOn(receiver, sink, syntheticNames: syntheticNames);
+ sink.write(", receiverExpression: ");
+ printNodeOn(receiverExpression, sink, syntheticNames: syntheticNames);
+ sink.write(", name: ");
+ sink.write(name.name);
+ sink.write(", getter: ");
+ printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
+ sink.write(", setter: ");
+ printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
+ sink.write(", type: ");
+ printNodeOn(type, sink, syntheticNames: syntheticNames);
+ }
+}
+
+class KernelSuperPropertyAccessGenerator extends KernelGenerator
+ with SuperPropertyAccessGenerator<Expression, Statement, Arguments> {
+ final Name name;
+
+ final Member getter;
+
+ final Member setter;
+
+ KernelSuperPropertyAccessGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ this.name,
+ this.getter,
+ this.setter)
+ : super(helper, token);
+
+ @override
+ String get plainNameForRead => name.name;
+
+ @override
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ if (getter == null) {
+ helper.warnUnresolvedGet(name, offsetForToken(token), isSuper: true);
+ }
+ // TODO(ahe): Use [DirectPropertyGet] when possible.
+ var read = new ShadowSuperPropertyGet(name, getter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.read = read;
+ return read;
+ }
+
+ @override
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ if (setter == null) {
+ helper.warnUnresolvedSet(name, offsetForToken(token), isSuper: true);
+ }
+ // TODO(ahe): Use [DirectPropertySet] when possible.
+ var write = new SuperPropertySet(name, value, setter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.write = write;
+ return write;
+ }
+
+ @override
+ Expression doInvocation(int offset, Arguments arguments) {
+ if (helper.constantContext != ConstantContext.none) {
+ helper.deprecated_addCompileTimeError(
+ offset, "Not a constant expression.");
+ }
+ if (getter == null || isFieldOrGetter(getter)) {
+ return helper.buildMethodInvocation(
+ buildSimpleRead(), callName, arguments, offset,
+ // This isn't a constant expression, but we have checked if a
+ // constant expression error should be emitted already.
+ isConstantExpression: true,
+ isImplicitCall: true);
+ } else {
+ // TODO(ahe): This could be something like "super.property(...)" where
+ // property is a setter.
+ return unhandled("${getter.runtimeType}", "doInvocation", offset, uri);
+ }
+ }
+
+ @override
+ ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+ new ShadowPropertyAssign(null, rhs, isSuper: true);
+
+ @override
+ void printOn(StringSink sink) {
+ NameSystem syntheticNames = new NameSystem();
+ sink.write(", name: ");
+ sink.write(name.name);
+ sink.write(", getter: ");
+ printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
+ sink.write(", setter: ");
+ printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
+ }
+}
+
+class KernelIndexedAccessGenerator extends KernelGenerator
+ with IndexedAccessGenerator<Expression, Statement, Arguments> {
+ final Expression receiver;
+
+ final Expression index;
+
+ final Procedure getter;
+
+ final Procedure setter;
+
+ VariableDeclaration receiverVariable;
+
+ VariableDeclaration indexVariable;
+
+ KernelIndexedAccessGenerator.internal(
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ Token token,
+ this.receiver,
+ this.index,
+ this.getter,
+ this.setter)
+ : super(helper, token);
+
+ Expression indexAccess() {
+ indexVariable ??= new VariableDeclaration.forValue(index);
+ return new VariableGet(indexVariable)..fileOffset = offsetForToken(token);
+ }
+
+ Expression receiverAccess() {
+ // We cannot reuse the receiver if it is a variable since it might be
+ // reassigned in the index expression.
+ receiverVariable ??= new VariableDeclaration.forValue(receiver);
+ return new VariableGet(receiverVariable)
+ ..fileOffset = offsetForToken(token);
+ }
+
+ @override
+ Expression _makeSimpleRead() {
+ var read = new ShadowMethodInvocation(receiver, indexGetName,
+ forest.castArguments(forest.arguments(<Expression>[index], token)),
+ interfaceTarget: getter)
+ ..fileOffset = offsetForToken(token);
+ return read;
+ }
+
+ @override
+ Expression _makeSimpleWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
+ var write = new ShadowMethodInvocation(
+ receiver,
+ indexSetName,
+ forest
+ .castArguments(forest.arguments(<Expression>[index, value], token)),
+ interfaceTarget: setter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.write = write;
+ return write;
+ }
+
+ @override
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ var read = new ShadowMethodInvocation(
+ receiverAccess(),
+ indexGetName,
+ forest.castArguments(
+ forest.arguments(<Expression>[indexAccess()], token)),
+ interfaceTarget: getter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.read = read;
+ return read;
+ }
+
+ @override
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
+ var write = new ShadowMethodInvocation(
+ receiverAccess(),
+ indexSetName,
+ forest.castArguments(
+ forest.arguments(<Expression>[indexAccess(), value], token)),
+ interfaceTarget: setter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.write = write;
+ return write;
+ }
+
+ // TODO(dmitryas): remove this method after the "[]=" operator of the Context
+ // class is made to return a value.
+ Expression _makeWriteAndReturn(
+ Expression value, ShadowComplexAssignment complexAssignment) {
+ // The call to []= does not return the value like direct-style assignments
+ // do. We need to bind the value in a let.
+ var valueVariable = new VariableDeclaration.forValue(value);
+ var write = new ShadowMethodInvocation(
+ receiverAccess(),
+ indexSetName,
+ forest.castArguments(forest.arguments(
+ <Expression>[indexAccess(), new VariableGet(valueVariable)],
+ token)),
+ interfaceTarget: setter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.write = write;
+ var dummy = new ShadowVariableDeclaration.forValue(
+ write, helper.functionNestingLevel);
+ return makeLet(
+ valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
+ }
+
+ @override
+ Expression _finish(
+ Expression body, ShadowComplexAssignment complexAssignment) {
+ return super._finish(
+ makeLet(receiverVariable, makeLet(indexVariable, body)),
+ complexAssignment);
+ }
+
+ @override
+ Expression doInvocation(int offset, Arguments arguments) {
+ return helper.buildMethodInvocation(
+ buildSimpleRead(), callName, arguments, forest.readOffset(arguments),
+ isImplicitCall: true);
+ }
+
+ @override
+ ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+ new ShadowIndexAssign(receiver, index, rhs);
+
+ @override
+ void printOn(StringSink sink) {
+ NameSystem syntheticNames = new NameSystem();
+ sink.write(", receiver: ");
+ printNodeOn(receiver, sink, syntheticNames: syntheticNames);
+ sink.write(", index: ");
+ printNodeOn(index, sink, syntheticNames: syntheticNames);
+ sink.write(", getter: ");
+ printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
+ sink.write(", setter: ");
+ printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
+ sink.write(", receiverVariable: ");
+ printNodeOn(receiverVariable, sink, syntheticNames: syntheticNames);
+ sink.write(", indexVariable: ");
+ printNodeOn(indexVariable, sink, syntheticNames: syntheticNames);
+ }
+}
+
+class KernelThisIndexedAccessGenerator extends KernelGenerator
+ with ThisIndexedAccessGenerator<Expression, Statement, Arguments> {
+ final Expression index;
+
+ final Procedure getter;
+
+ final Procedure setter;
+
+ VariableDeclaration indexVariable;
+
+ KernelThisIndexedAccessGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ this.index,
+ this.getter,
+ this.setter)
+ : super(helper, token);
+
+ Expression indexAccess() {
+ indexVariable ??= new VariableDeclaration.forValue(index);
+ return new VariableGet(indexVariable);
+ }
+
+ Expression _makeWriteAndReturn(
+ Expression value, ShadowComplexAssignment complexAssignment) {
+ var valueVariable = new VariableDeclaration.forValue(value);
+ var write = new ShadowMethodInvocation(
+ forest.thisExpression(token),
+ indexSetName,
+ forest.castArguments(forest.arguments(
+ <Expression>[indexAccess(), new VariableGet(valueVariable)],
+ token)),
+ interfaceTarget: setter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.write = write;
+ var dummy = new VariableDeclaration.forValue(write);
+ return makeLet(
+ valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
+ }
+
+ @override
+ Expression _makeSimpleRead() {
+ return new ShadowMethodInvocation(
+ forest.thisExpression(token),
+ indexGetName,
+ forest.castArguments(forest.arguments(<Expression>[index], token)),
+ interfaceTarget: getter)
+ ..fileOffset = offsetForToken(token);
+ }
+
+ @override
+ Expression _makeSimpleWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
+ var write = new ShadowMethodInvocation(
+ forest.thisExpression(token),
+ indexSetName,
+ forest
+ .castArguments(forest.arguments(<Expression>[index, value], token)),
+ interfaceTarget: setter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.write = write;
+ return write;
+ }
+
+ @override
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ var read = new ShadowMethodInvocation(
+ forest.thisExpression(token),
+ indexGetName,
+ forest.castArguments(
+ forest.arguments(<Expression>[indexAccess()], token)),
+ interfaceTarget: getter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.read = read;
+ return read;
+ }
+
+ @override
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
+ var write = new ShadowMethodInvocation(
+ forest.thisExpression(token),
+ indexSetName,
+ forest.castArguments(
+ forest.arguments(<Expression>[indexAccess(), value], token)),
+ interfaceTarget: setter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.write = write;
+ return write;
+ }
+
+ @override
+ Expression _finish(
+ Expression body, ShadowComplexAssignment complexAssignment) {
+ return super._finish(makeLet(indexVariable, body), complexAssignment);
+ }
+
+ @override
+ Expression doInvocation(int offset, Arguments arguments) {
+ return helper.buildMethodInvocation(
+ buildSimpleRead(), callName, arguments, offset,
+ isImplicitCall: true);
+ }
+
+ @override
+ ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+ new ShadowIndexAssign(null, index, rhs);
+
+ @override
+ void printOn(StringSink sink) {
+ NameSystem syntheticNames = new NameSystem();
+ sink.write(", index: ");
+ printNodeOn(index, sink, syntheticNames: syntheticNames);
+ sink.write(", getter: ");
+ printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
+ sink.write(", setter: ");
+ printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
+ sink.write(", indexVariable: ");
+ printNodeOn(indexVariable, sink, syntheticNames: syntheticNames);
+ }
+}
+
+Expression makeLet(VariableDeclaration variable, Expression body) {
+ if (variable == null) return body;
+ return new Let(variable, body);
+}
+
+Expression makeBinary(
+ Expression left,
+ Name operator,
+ Procedure interfaceTarget,
+ Expression right,
+ ExpressionGeneratorHelper<Expression, Statement, Arguments> helper,
+ {int offset: TreeNode.noOffset}) {
+ return new ShadowMethodInvocation(
+ left,
+ operator,
+ helper.storeOffset(
+ helper.forest.castArguments(
+ helper.forest.arguments(<Expression>[right], null)),
+ offset),
+ interfaceTarget: interfaceTarget)
+ ..fileOffset = offset;
+}
+
+Expression buildIsNull(Expression value, int offset,
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper) {
+ return makeBinary(value, equalsName, null,
+ helper.storeOffset(helper.forest.literalNull(null), offset), helper,
+ offset: offset);
+}
+
+VariableDeclaration makeOrReuseVariable(Expression value) {
+ // TODO: Devise a way to remember if a variable declaration was reused
+ // or is fresh (hence needs a let binding).
+ return new VariableDeclaration.forValue(value);
+}
+
+int adjustForImplicitCall(String name, int offset) {
+ // Normally the offset is at the start of the token, but in this case,
+ // because we insert a '.call', we want it at the end instead.
+ return offset + (name?.length ?? 0);
+}
+
+bool isFieldOrGetter(Member member) {
+ return member is Field || (member is Procedure && member.isGetter);
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator_impl.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator_impl.dart
new file mode 100644
index 0000000..46e7b2a
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator_impl.dart
@@ -0,0 +1,1416 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+/// All classes in this file are temporary. Each class should be split in two:
+///
+/// 1. A common superclass.
+/// 2. A kernel-specific implementation class.
+///
+/// The common superclass should keep the name of the class and be moved to
+/// [expression_generator.dart]. The kernel-specific class should be moved to
+/// [kernel_expression_generator.dart] and we can eventually delete this file.
+///
+/// Take a look at [VariableUseGenerator] for an example of how the common
+/// superclass should use the forest API in a factory method.
+part of 'kernel_expression_generator.dart';
+
+class SuperIndexedAccessGenerator extends KernelGenerator {
+ final Expression index;
+
+ final Member getter;
+
+ final Member setter;
+
+ VariableDeclaration indexVariable;
+
+ SuperIndexedAccessGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ this.index,
+ this.getter,
+ this.setter)
+ : super(helper, token);
+
+ String get plainNameForRead => "[]";
+
+ String get plainNameForWrite => "[]=";
+
+ String get debugName => "SuperIndexedAccessGenerator";
+
+ indexAccess() {
+ indexVariable ??= new VariableDeclaration.forValue(index);
+ return new VariableGet(indexVariable);
+ }
+
+ Expression _makeSimpleRead() {
+ if (getter == null) {
+ helper.warnUnresolvedMethod(indexGetName, offsetForToken(token),
+ isSuper: true);
+ }
+ // TODO(ahe): Use [DirectMethodInvocation] when possible.
+ return new ShadowSuperMethodInvocation(
+ indexGetName,
+ forest.castArguments(forest.arguments(<Expression>[index], token)),
+ getter)
+ ..fileOffset = offsetForToken(token);
+ }
+
+ Expression _makeSimpleWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
+ if (setter == null) {
+ helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
+ isSuper: true);
+ }
+ var write = new SuperMethodInvocation(
+ indexSetName,
+ forest
+ .castArguments(forest.arguments(<Expression>[index, value], token)),
+ setter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.write = write;
+ return write;
+ }
+
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ if (getter == null) {
+ helper.warnUnresolvedMethod(indexGetName, offsetForToken(token),
+ isSuper: true);
+ }
+ var read = new SuperMethodInvocation(
+ indexGetName,
+ forest.castArguments(
+ forest.arguments(<Expression>[indexAccess()], token)),
+ getter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.read = read;
+ return read;
+ }
+
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ if (!voidContext) return _makeWriteAndReturn(value, complexAssignment);
+ if (setter == null) {
+ helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
+ isSuper: true);
+ }
+ var write = new SuperMethodInvocation(
+ indexSetName,
+ forest.castArguments(
+ forest.arguments(<Expression>[indexAccess(), value], token)),
+ setter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.write = write;
+ return write;
+ }
+
+ _makeWriteAndReturn(
+ Expression value, ShadowComplexAssignment complexAssignment) {
+ var valueVariable = new VariableDeclaration.forValue(value);
+ if (setter == null) {
+ helper.warnUnresolvedMethod(indexSetName, offsetForToken(token),
+ isSuper: true);
+ }
+ var write = new SuperMethodInvocation(
+ indexSetName,
+ forest.castArguments(forest.arguments(
+ <Expression>[indexAccess(), new VariableGet(valueVariable)],
+ token)),
+ setter)
+ ..fileOffset = offsetForToken(token);
+ complexAssignment?.write = write;
+ var dummy = new VariableDeclaration.forValue(write);
+ return makeLet(
+ valueVariable, makeLet(dummy, new VariableGet(valueVariable)));
+ }
+
+ Expression _finish(
+ Expression body, ShadowComplexAssignment complexAssignment) {
+ return super._finish(makeLet(indexVariable, body), complexAssignment);
+ }
+
+ Expression doInvocation(int offset, Arguments arguments) {
+ return helper.buildMethodInvocation(
+ buildSimpleRead(), callName, arguments, offset,
+ isImplicitCall: true);
+ }
+
+ @override
+ ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+ new ShadowIndexAssign(null, index, rhs, isSuper: true);
+
+ @override
+ void printOn(StringSink sink) {
+ NameSystem syntheticNames = new NameSystem();
+ sink.write(", index: ");
+ printNodeOn(index, sink, syntheticNames: syntheticNames);
+ sink.write(", getter: ");
+ printQualifiedNameOn(getter, sink, syntheticNames: syntheticNames);
+ sink.write(", setter: ");
+ printQualifiedNameOn(setter, sink, syntheticNames: syntheticNames);
+ sink.write(", indexVariable: ");
+ printNodeOn(indexVariable, sink, syntheticNames: syntheticNames);
+ }
+}
+
+class StaticAccessGenerator extends KernelGenerator {
+ final Member readTarget;
+
+ final Member writeTarget;
+
+ StaticAccessGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ this.readTarget,
+ this.writeTarget)
+ : assert(readTarget != null || writeTarget != null),
+ super(helper, token);
+
+ factory StaticAccessGenerator.fromBuilder(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Builder builder,
+ Token token,
+ Builder builderSetter) {
+ if (builder is AccessErrorBuilder) {
+ AccessErrorBuilder error = builder;
+ builder = error.builder;
+ // We should only see an access error here if we've looked up a setter
+ // when not explicitly looking for a setter.
+ assert(builder.isSetter);
+ } else if (builder.target == null) {
+ return unhandled(
+ "${builder.runtimeType}",
+ "StaticAccessGenerator.fromBuilder",
+ offsetForToken(token),
+ helper.uri);
+ }
+ Member getter = builder.target.hasGetter ? builder.target : null;
+ Member setter = builder.target.hasSetter ? builder.target : null;
+ if (setter == null) {
+ if (builderSetter?.target?.hasSetter ?? false) {
+ setter = builderSetter.target;
+ }
+ }
+ return new StaticAccessGenerator(helper, token, getter, setter);
+ }
+
+ String get plainNameForRead => (readTarget ?? writeTarget).name.name;
+
+ String get debugName => "StaticAccessGenerator";
+
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ if (readTarget == null) {
+ return makeInvalidRead();
+ } else {
+ var read = helper.makeStaticGet(readTarget, token);
+ complexAssignment?.read = read;
+ return read;
+ }
+ }
+
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ Expression write;
+ if (writeTarget == null) {
+ write = makeInvalidWrite(value);
+ } else {
+ write = new StaticSet(writeTarget, value);
+ complexAssignment?.write = write;
+ }
+ write.fileOffset = offsetForToken(token);
+ return write;
+ }
+
+ Expression doInvocation(int offset, Arguments arguments) {
+ if (helper.constantContext != ConstantContext.none &&
+ !helper.isIdentical(readTarget)) {
+ helper.deprecated_addCompileTimeError(
+ offset, "Not a constant expression.");
+ }
+ if (readTarget == null || isFieldOrGetter(readTarget)) {
+ return helper.buildMethodInvocation(buildSimpleRead(), callName,
+ arguments, offset + (readTarget?.name?.name?.length ?? 0),
+ // This isn't a constant expression, but we have checked if a
+ // constant expression error should be emitted already.
+ isConstantExpression: true,
+ isImplicitCall: true);
+ } else {
+ return helper.buildStaticInvocation(readTarget, arguments,
+ charOffset: offset);
+ }
+ }
+
+ @override
+ ShadowComplexAssignment startComplexAssignment(Expression rhs) =>
+ new ShadowStaticAssignment(rhs);
+
+ @override
+ void printOn(StringSink sink) {
+ NameSystem syntheticNames = new NameSystem();
+ sink.write(", readTarget: ");
+ printQualifiedNameOn(readTarget, sink, syntheticNames: syntheticNames);
+ sink.write(", writeTarget: ");
+ printQualifiedNameOn(writeTarget, sink, syntheticNames: syntheticNames);
+ }
+}
+
+class LoadLibraryGenerator extends KernelGenerator {
+ final LoadLibraryBuilder builder;
+
+ LoadLibraryGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ this.builder)
+ : super(helper, token);
+
+ String get plainNameForRead => 'loadLibrary';
+
+ String get debugName => "LoadLibraryGenerator";
+
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ var read =
+ helper.makeStaticGet(builder.createTearoffMethod(helper.forest), token);
+ complexAssignment?.read = read;
+ return read;
+ }
+
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ Expression write = makeInvalidWrite(value);
+ write.fileOffset = offsetForToken(token);
+ return write;
+ }
+
+ Expression doInvocation(int offset, Arguments arguments) {
+ if (forest.argumentsPositional(arguments).length > 0 ||
+ forest.argumentsNamed(arguments).length > 0) {
+ helper.addProblemErrorIfConst(
+ messageLoadLibraryTakesNoArguments, offset, 'loadLibrary'.length);
+ }
+ return builder.createLoadLibrary(offset, forest);
+ }
+
+ @override
+ void printOn(StringSink sink) {
+ sink.write(", builder: ");
+ sink.write(builder);
+ }
+}
+
+class DeferredAccessGenerator extends KernelGenerator {
+ final PrefixBuilder builder;
+
+ final KernelGenerator generator;
+
+ DeferredAccessGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ this.builder,
+ this.generator)
+ : super(helper, token);
+
+ String get plainNameForRead {
+ return unsupported(
+ "deferredAccessor.plainNameForRead", offsetForToken(token), uri);
+ }
+
+ String get debugName => "DeferredAccessGenerator";
+
+ Expression _makeSimpleRead() {
+ return helper.wrapInDeferredCheck(
+ generator._makeSimpleRead(), builder, token.charOffset);
+ }
+
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ return helper.wrapInDeferredCheck(
+ generator._makeRead(complexAssignment), builder, token.charOffset);
+ }
+
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ return helper.wrapInDeferredCheck(
+ generator._makeWrite(value, voidContext, complexAssignment),
+ builder,
+ token.charOffset);
+ }
+
+ buildPropertyAccess(
+ IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
+ var propertyAccess =
+ generator.buildPropertyAccess(send, operatorOffset, isNullAware);
+ if (propertyAccess is Generator) {
+ return new DeferredAccessGenerator(
+ helper, token, builder, propertyAccess);
+ } else {
+ Expression expression = propertyAccess;
+ return helper.wrapInDeferredCheck(expression, builder, token.charOffset);
+ }
+ }
+
+ @override
+ DartType buildTypeWithBuiltArguments(List<DartType> arguments,
+ {bool nonInstanceAccessIsError: false}) {
+ helper.addProblem(
+ templateDeferredTypeAnnotation.withArguments(
+ generator.buildTypeWithBuiltArguments(arguments,
+ nonInstanceAccessIsError: nonInstanceAccessIsError),
+ builder.name),
+ offsetForToken(token),
+ lengthForToken(token));
+ return const InvalidType();
+ }
+
+ Expression doInvocation(int offset, Arguments arguments) {
+ return helper.wrapInDeferredCheck(
+ generator.doInvocation(offset, arguments), builder, token.charOffset);
+ }
+
+ @override
+ void printOn(StringSink sink) {
+ sink.write(", builder: ");
+ sink.write(builder);
+ sink.write(", generator: ");
+ sink.write(generator);
+ }
+}
+
+class ReadOnlyAccessGenerator extends KernelGenerator {
+ final String plainNameForRead;
+
+ Expression expression;
+
+ VariableDeclaration value;
+
+ ReadOnlyAccessGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ this.expression,
+ this.plainNameForRead)
+ : super(helper, token);
+
+ String get debugName => "ReadOnlyAccessGenerator";
+
+ Expression _makeSimpleRead() => expression;
+
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ value ??= new VariableDeclaration.forValue(expression);
+ return new VariableGet(value);
+ }
+
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ var write = makeInvalidWrite(value);
+ complexAssignment?.write = write;
+ return write;
+ }
+
+ Expression _finish(
+ Expression body, ShadowComplexAssignment complexAssignment) =>
+ super._finish(makeLet(value, body), complexAssignment);
+
+ Expression doInvocation(int offset, Arguments arguments) {
+ return helper.buildMethodInvocation(buildSimpleRead(), callName, arguments,
+ adjustForImplicitCall(plainNameForRead, offset),
+ isImplicitCall: true);
+ }
+
+ @override
+ void printOn(StringSink sink) {
+ NameSystem syntheticNames = new NameSystem();
+ sink.write(", expression: ");
+ printNodeOn(expression, sink, syntheticNames: syntheticNames);
+ sink.write(", plainNameForRead: ");
+ sink.write(plainNameForRead);
+ sink.write(", value: ");
+ printNodeOn(value, sink, syntheticNames: syntheticNames);
+ }
+}
+
+class LargeIntAccessGenerator extends KernelGenerator {
+ LargeIntAccessGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper, Token token)
+ : super(helper, token);
+
+ // TODO(ahe): This should probably be calling unhandled.
+ String get plainNameForRead => null;
+
+ String get debugName => "LargeIntAccessGenerator";
+
+ @override
+ Expression _makeSimpleRead() => buildError();
+
+ @override
+ Expression _makeSimpleWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ return buildError();
+ }
+
+ @override
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ return buildError();
+ }
+
+ @override
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ return buildError();
+ }
+
+ Expression buildError() {
+ return helper.buildCompileTimeError(
+ templateIntegerLiteralIsOutOfRange.withArguments(token),
+ offsetForToken(token),
+ lengthForToken(token));
+ }
+
+ @override
+ Expression doInvocation(int offset, Arguments arguments) {
+ return buildError();
+ }
+
+ @override
+ void printOn(StringSink sink) {
+ sink.write(", lexeme: ");
+ sink.write(token.lexeme);
+ }
+}
+
+abstract class ErroneousExpressionGenerator implements KernelGenerator {
+ /// Pass [arguments] that must be evaluated before throwing an error. At
+ /// most one of [isGetter] and [isSetter] should be true and they're passed
+ /// to [ExpressionGeneratorHelper.buildThrowNoSuchMethodError] if it is used.
+ Expression buildError(Arguments arguments,
+ {bool isGetter: false, bool isSetter: false, int offset});
+
+ DartType buildErroneousTypeNotAPrefix(Identifier suffix);
+
+ Name get name => unsupported("name", offsetForToken(token), uri);
+
+ @override
+ String get plainNameForRead => name.name;
+
+ withReceiver(Object receiver, int operatorOffset, {bool isNullAware}) => this;
+
+ @override
+ Initializer buildFieldInitializer(Map<String, int> initializedFields) {
+ return helper.buildInvalidInitializer(
+ buildError(forest.argumentsEmpty(noLocation), isSetter: true));
+ }
+
+ @override
+ doInvocation(int offset, Arguments arguments) {
+ return buildError(arguments, offset: offset);
+ }
+
+ @override
+ buildPropertyAccess(
+ IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
+ return this;
+ }
+
+ @override
+ buildThrowNoSuchMethodError(Expression receiver, Arguments arguments,
+ {bool isSuper: false,
+ bool isGetter: false,
+ bool isSetter: false,
+ bool isStatic: false,
+ String name,
+ int offset,
+ LocatedMessage argMessage}) {
+ return this;
+ }
+
+ @override
+ Expression buildAssignment(Expression value, {bool voidContext: false}) {
+ return buildError(forest.arguments(<Expression>[value], noLocation),
+ isSetter: true);
+ }
+
+ @override
+ Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+ {int offset: TreeNode.noOffset,
+ bool voidContext: false,
+ Procedure interfaceTarget,
+ bool isPreIncDec: false}) {
+ return buildError(forest.arguments(<Expression>[value], token),
+ isGetter: true);
+ }
+
+ @override
+ Expression buildPrefixIncrement(Name binaryOperator,
+ {int offset: TreeNode.noOffset,
+ bool voidContext: false,
+ Procedure interfaceTarget}) {
+ // TODO(ahe): For the Analyzer, we probably need to build a prefix
+ // increment node that wraps an error.
+ return buildError(
+ forest.arguments(
+ <Expression>[storeOffset(forest.literalInt(1, null), offset)],
+ noLocation),
+ isGetter: true);
+ }
+
+ @override
+ Expression buildPostfixIncrement(Name binaryOperator,
+ {int offset: TreeNode.noOffset,
+ bool voidContext: false,
+ Procedure interfaceTarget}) {
+ // TODO(ahe): For the Analyzer, we probably need to build a post increment
+ // node that wraps an error.
+ return buildError(
+ forest.arguments(
+ <Expression>[storeOffset(forest.literalInt(1, null), offset)],
+ noLocation),
+ isGetter: true);
+ }
+
+ @override
+ Expression buildNullAwareAssignment(
+ Expression value, DartType type, int offset,
+ {bool voidContext: false}) {
+ return buildError(forest.arguments(<Expression>[value], noLocation),
+ isSetter: true);
+ }
+
+ @override
+ Expression buildSimpleRead() =>
+ buildError(forest.argumentsEmpty(noLocation), isGetter: true);
+
+ @override
+ Expression makeInvalidRead() =>
+ buildError(forest.argumentsEmpty(noLocation), isGetter: true);
+
+ @override
+ Expression makeInvalidWrite(Expression value) {
+ return buildError(forest.arguments(<Expression>[value], noLocation),
+ isSetter: true);
+ }
+}
+
+class ThisAccessGenerator extends KernelGenerator {
+ final bool isInitializer;
+
+ final bool isSuper;
+
+ ThisAccessGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ this.isInitializer,
+ {this.isSuper: false})
+ : super(helper, token);
+
+ String get plainNameForRead {
+ return unsupported("${isSuper ? 'super' : 'this'}.plainNameForRead",
+ offsetForToken(token), uri);
+ }
+
+ String get debugName => "ThisAccessGenerator";
+
+ Expression buildSimpleRead() {
+ if (!isSuper) {
+ return forest.thisExpression(token);
+ } else {
+ return helper.buildCompileTimeError(messageSuperAsExpression,
+ offsetForToken(token), lengthForToken(token));
+ }
+ }
+
+ @override
+ Initializer buildFieldInitializer(Map<String, int> initializedFields) {
+ String keyword = isSuper ? "super" : "this";
+ int offset = offsetForToken(token);
+ return helper.buildInvalidInitializer(
+ helper.deprecated_buildCompileTimeError(
+ "Can't use '$keyword' here, did you mean '$keyword()'?", offset),
+ offset);
+ }
+
+ buildPropertyAccess(
+ IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
+ Name name = send.name;
+ Arguments arguments = send.arguments;
+ int offset = offsetForToken(send.token);
+ if (isInitializer && send is SendAccessGenerator) {
+ if (isNullAware) {
+ helper.deprecated_addCompileTimeError(
+ operatorOffset, "Expected '.'\nTry removing '?'.");
+ }
+ return buildConstructorInitializer(offset, name, arguments);
+ }
+ Member getter = helper.lookupInstanceMember(name, isSuper: isSuper);
+ if (send is SendAccessGenerator) {
+ // Notice that 'this' or 'super' can't be null. So we can ignore the
+ // value of [isNullAware].
+ if (getter == null) {
+ helper.warnUnresolvedMethod(name, offsetForToken(send.token),
+ isSuper: isSuper);
+ }
+ return helper.buildMethodInvocation(forest.thisExpression(null), name,
+ send.arguments, offsetForToken(send.token),
+ isSuper: isSuper, interfaceTarget: getter);
+ } else {
+ Member setter =
+ helper.lookupInstanceMember(name, isSuper: isSuper, isSetter: true);
+ if (isSuper) {
+ return new SuperPropertyAccessGenerator(
+ helper, send.token, name, getter, setter);
+ } else {
+ return new ThisPropertyAccessGenerator(
+ helper, send.token, name, getter, setter);
+ }
+ }
+ }
+
+ doInvocation(int offset, Arguments arguments) {
+ if (isInitializer) {
+ return buildConstructorInitializer(offset, new Name(""), arguments);
+ } else if (isSuper) {
+ return helper.buildCompileTimeError(
+ messageSuperAsExpression, offset, noLength);
+ } else {
+ return helper.buildMethodInvocation(
+ forest.thisExpression(null), callName, arguments, offset,
+ isImplicitCall: true);
+ }
+ }
+
+ Initializer buildConstructorInitializer(
+ int offset, Name name, Arguments arguments) {
+ Constructor constructor = helper.lookupConstructor(name, isSuper: isSuper);
+ LocatedMessage argMessage;
+ if (constructor != null) {
+ argMessage = helper.checkArgumentsForFunction(
+ constructor.function, arguments, offset, <TypeParameter>[]);
+ }
+ if (constructor == null || argMessage != null) {
+ return helper.buildInvalidInitializer(
+ buildThrowNoSuchMethodError(
+ storeOffset(forest.literalNull(null), offset), arguments,
+ isSuper: isSuper,
+ name: name.name,
+ offset: offset,
+ argMessage: argMessage),
+ offset);
+ } else if (isSuper) {
+ return helper.buildSuperInitializer(
+ false, constructor, arguments, offset);
+ } else {
+ return helper.buildRedirectingInitializer(constructor, arguments, offset);
+ }
+ }
+
+ Expression buildAssignment(Expression value, {bool voidContext: false}) {
+ return buildAssignmentError();
+ }
+
+ Expression buildNullAwareAssignment(
+ Expression value, DartType type, int offset,
+ {bool voidContext: false}) {
+ return buildAssignmentError();
+ }
+
+ Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+ {int offset: TreeNode.noOffset,
+ bool voidContext: false,
+ Procedure interfaceTarget,
+ bool isPreIncDec: false}) {
+ return buildAssignmentError();
+ }
+
+ Expression buildPrefixIncrement(Name binaryOperator,
+ {int offset: TreeNode.noOffset,
+ bool voidContext: false,
+ Procedure interfaceTarget}) {
+ return buildAssignmentError();
+ }
+
+ Expression buildPostfixIncrement(Name binaryOperator,
+ {int offset: TreeNode.noOffset,
+ bool voidContext: false,
+ Procedure interfaceTarget}) {
+ return buildAssignmentError();
+ }
+
+ Expression buildAssignmentError() {
+ String message =
+ isSuper ? "Can't assign to 'super'." : "Can't assign to 'this'.";
+ return helper.deprecated_buildCompileTimeError(
+ message, offsetForToken(token));
+ }
+
+ @override
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ return unsupported("_makeRead", offsetForToken(token), uri);
+ }
+
+ @override
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ return unsupported("_makeWrite", offsetForToken(token), uri);
+ }
+
+ @override
+ void printOn(StringSink sink) {
+ sink.write(", isInitializer: ");
+ sink.write(isInitializer);
+ sink.write(", isSuper: ");
+ sink.write(isSuper);
+ }
+}
+
+abstract class IncompleteSendGenerator extends KernelGenerator {
+ final Name name;
+
+ IncompleteSendGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ this.name)
+ : super(helper, token);
+
+ withReceiver(Object receiver, int operatorOffset, {bool isNullAware});
+
+ Arguments get arguments => null;
+
+ @override
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ return unsupported("_makeRead", offsetForToken(token), uri);
+ }
+
+ @override
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ return unsupported("_makeWrite", offsetForToken(token), uri);
+ }
+
+ @override
+ void printOn(StringSink sink) {
+ sink.write(", name: ");
+ sink.write(name.name);
+ }
+}
+
+class UnresolvedNameGenerator extends KernelGenerator
+ with ErroneousExpressionGenerator {
+ @override
+ final Name name;
+
+ UnresolvedNameGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ this.name)
+ : super(helper, token);
+
+ String get debugName => "UnresolvedNameGenerator";
+
+ Expression doInvocation(int charOffset, Arguments arguments) {
+ return buildError(arguments, offset: charOffset);
+ }
+
+ @override
+ DartType buildErroneousTypeNotAPrefix(Identifier suffix) {
+ helper.addProblem(
+ templateUnresolvedPrefixInTypeAnnotation.withArguments(
+ name.name, suffix.name),
+ offsetForToken(token),
+ lengthOfSpan(token, suffix.token));
+ return const InvalidType();
+ }
+
+ @override
+ Expression buildError(Arguments arguments,
+ {bool isGetter: false, bool isSetter: false, int offset}) {
+ offset ??= offsetForToken(this.token);
+ return helper.throwNoSuchMethodError(
+ storeOffset(forest.literalNull(null), offset),
+ plainNameForRead,
+ arguments,
+ offset,
+ isGetter: isGetter,
+ isSetter: isSetter);
+ }
+
+ @override
+ Expression _makeRead(ShadowComplexAssignment complexAssignment) {
+ return unsupported("_makeRead", offsetForToken(token), uri);
+ }
+
+ @override
+ Expression _makeWrite(Expression value, bool voidContext,
+ ShadowComplexAssignment complexAssignment) {
+ return unsupported("_makeWrite", offsetForToken(token), uri);
+ }
+
+ @override
+ void printOn(StringSink sink) {
+ sink.write(", name: ");
+ sink.write(name.name);
+ }
+}
+
+class IncompleteErrorGenerator extends IncompleteSendGenerator
+ with ErroneousExpressionGenerator {
+ final Message message;
+
+ IncompleteErrorGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ this.message)
+ : super(helper, token, null);
+
+ String get debugName => "IncompleteErrorGenerator";
+
+ @override
+ Expression buildError(Arguments arguments,
+ {bool isGetter: false, bool isSetter: false, int offset}) {
+ int length = noLength;
+ if (offset == null) {
+ offset = offsetForToken(token);
+ length = lengthForToken(token);
+ }
+ return helper.buildCompileTimeError(message, offset, length);
+ }
+
+ @override
+ DartType buildErroneousTypeNotAPrefix(Identifier suffix) {
+ helper.addProblem(
+ templateNotAPrefixInTypeAnnotation.withArguments(
+ token.lexeme, suffix.name),
+ offsetForToken(token),
+ lengthOfSpan(token, suffix.token));
+ return const InvalidType();
+ }
+
+ @override
+ doInvocation(int offset, Arguments arguments) => this;
+
+ @override
+ void printOn(StringSink sink) {
+ sink.write(", message: ");
+ sink.write(message.code.name);
+ }
+}
+
+// TODO(ahe): Rename to SendGenerator.
+class SendAccessGenerator extends IncompleteSendGenerator {
+ @override
+ final Arguments arguments;
+
+ SendAccessGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ Name name,
+ this.arguments)
+ : super(helper, token, name) {
+ assert(arguments != null);
+ }
+
+ String get plainNameForRead => name.name;
+
+ String get debugName => "SendAccessGenerator";
+
+ Expression buildSimpleRead() {
+ return unsupported("buildSimpleRead", offsetForToken(token), uri);
+ }
+
+ Expression buildAssignment(Expression value, {bool voidContext: false}) {
+ return unsupported("buildAssignment", offsetForToken(token), uri);
+ }
+
+ withReceiver(Object receiver, int operatorOffset, {bool isNullAware: false}) {
+ if (receiver is Generator) {
+ return receiver.buildPropertyAccess(this, operatorOffset, isNullAware);
+ }
+ if (receiver is PrefixBuilder) {
+ PrefixBuilder prefix = receiver;
+ if (isNullAware) {
+ helper.deprecated_addCompileTimeError(
+ offsetForToken(token),
+ "Library prefix '${prefix.name}' can't be used with null-aware "
+ "operator.\nTry removing '?'.");
+ }
+ receiver = helper.scopeLookup(prefix.exportScope, name.name, token,
+ isQualified: true, prefix: prefix);
+ return helper.finishSend(receiver, arguments, offsetForToken(token));
+ }
+ return helper.buildMethodInvocation(
+ helper.toValue(receiver), name, arguments, offsetForToken(token),
+ isNullAware: isNullAware);
+ }
+
+ Expression buildNullAwareAssignment(
+ Expression value, DartType type, int offset,
+ {bool voidContext: false}) {
+ return unsupported("buildNullAwareAssignment", offset, uri);
+ }
+
+ Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+ {int offset,
+ bool voidContext: false,
+ Procedure interfaceTarget,
+ bool isPreIncDec: false}) {
+ return unsupported(
+ "buildCompoundAssignment", offset ?? offsetForToken(token), uri);
+ }
+
+ Expression buildPrefixIncrement(Name binaryOperator,
+ {int offset, bool voidContext: false, Procedure interfaceTarget}) {
+ return unsupported(
+ "buildPrefixIncrement", offset ?? offsetForToken(token), uri);
+ }
+
+ Expression buildPostfixIncrement(Name binaryOperator,
+ {int offset, bool voidContext: false, Procedure interfaceTarget}) {
+ return unsupported(
+ "buildPostfixIncrement", offset ?? offsetForToken(token), uri);
+ }
+
+ Expression doInvocation(int offset, Arguments arguments) {
+ return unsupported("doInvocation", offset, uri);
+ }
+
+ @override
+ void printOn(StringSink sink) {
+ super.printOn(sink);
+ sink.write(", arguments: ");
+ var node = arguments;
+ if (node is Node) {
+ printNodeOn(node, sink);
+ } else {
+ sink.write(node);
+ }
+ }
+}
+
+class IncompletePropertyAccessGenerator extends IncompleteSendGenerator {
+ IncompletePropertyAccessGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ Name name)
+ : super(helper, token, name);
+
+ String get plainNameForRead => name.name;
+
+ String get debugName => "IncompletePropertyAccessGenerator";
+
+ Expression buildSimpleRead() {
+ return unsupported("buildSimpleRead", offsetForToken(token), uri);
+ }
+
+ Expression buildAssignment(Expression value, {bool voidContext: false}) {
+ return unsupported("buildAssignment", offsetForToken(token), uri);
+ }
+
+ withReceiver(Object receiver, int operatorOffset, {bool isNullAware: false}) {
+ if (receiver is Generator) {
+ return receiver.buildPropertyAccess(this, operatorOffset, isNullAware);
+ }
+ if (receiver is PrefixBuilder) {
+ PrefixBuilder prefix = receiver;
+ if (isNullAware) {
+ helper.deprecated_addCompileTimeError(
+ offsetForToken(token),
+ "Library prefix '${prefix.name}' can't be used with null-aware "
+ "operator.\nTry removing '?'.");
+ }
+ return helper.scopeLookup(prefix.exportScope, name.name, token,
+ isQualified: true, prefix: prefix);
+ }
+
+ return PropertyAccessGenerator.make(
+ helper, token, helper.toValue(receiver), name, null, null, isNullAware);
+ }
+
+ Expression buildNullAwareAssignment(
+ Expression value, DartType type, int offset,
+ {bool voidContext: false}) {
+ return unsupported("buildNullAwareAssignment", offset, uri);
+ }
+
+ Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+ {int offset,
+ bool voidContext: false,
+ Procedure interfaceTarget,
+ bool isPreIncDec: false}) {
+ return unsupported(
+ "buildCompoundAssignment", offset ?? offsetForToken(token), uri);
+ }
+
+ Expression buildPrefixIncrement(Name binaryOperator,
+ {int offset, bool voidContext: false, Procedure interfaceTarget}) {
+ return unsupported(
+ "buildPrefixIncrement", offset ?? offsetForToken(token), uri);
+ }
+
+ Expression buildPostfixIncrement(Name binaryOperator,
+ {int offset, bool voidContext: false, Procedure interfaceTarget}) {
+ return unsupported(
+ "buildPostfixIncrement", offset ?? offsetForToken(token), uri);
+ }
+
+ Expression doInvocation(int offset, Arguments arguments) {
+ return unsupported("doInvocation", offset, uri);
+ }
+}
+
+class ParenthesizedExpressionGenerator extends ReadOnlyAccessGenerator {
+ ParenthesizedExpressionGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ Expression expression)
+ : super(helper, token, expression, null);
+
+ String get debugName => "ParenthesizedExpressionGenerator";
+
+ Expression makeInvalidWrite(Expression value) {
+ return helper.deprecated_buildCompileTimeError(
+ "Can't assign to a parenthesized expression.", offsetForToken(token));
+ }
+}
+
+// TODO(ahe): Rename to TypeUseGenerator.
+class TypeDeclarationAccessGenerator extends ReadOnlyAccessGenerator {
+ /// The import prefix preceding the [declaration] reference, or `null` if
+ /// the reference is not prefixed.
+ final PrefixBuilder prefix;
+
+ /// The offset at which the [declaration] is referenced by this generator,
+ /// or `-1` if the reference is implicit.
+ final int declarationReferenceOffset;
+
+ final TypeDeclarationBuilder declaration;
+
+ TypeDeclarationAccessGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ this.prefix,
+ this.declarationReferenceOffset,
+ this.declaration,
+ String plainNameForRead)
+ : super(helper, token, null, plainNameForRead);
+
+ String get debugName => "TypeDeclarationAccessGenerator";
+
+ Expression get expression {
+ if (super.expression == null) {
+ int offset = offsetForToken(token);
+ if (declaration is KernelInvalidTypeBuilder) {
+ KernelInvalidTypeBuilder declaration = this.declaration;
+ helper.addProblemErrorIfConst(
+ declaration.message.messageObject, offset, token.length);
+ super.expression =
+ new Throw(forest.literalString(declaration.message.message, token))
+ ..fileOffset = offset;
+ } else {
+ super.expression = forest.literalType(
+ buildTypeWithBuiltArguments(null, nonInstanceAccessIsError: true),
+ token);
+ }
+ }
+ return super.expression;
+ }
+
+ Expression makeInvalidWrite(Expression value) {
+ return buildThrowNoSuchMethodError(
+ forest.literalNull(token),
+ storeOffset(
+ forest.arguments(<Expression>[value], null), value.fileOffset),
+ isSetter: true);
+ }
+
+ @override
+ buildPropertyAccess(
+ IncompleteSendGenerator send, int operatorOffset, bool isNullAware) {
+ // `SomeType?.toString` is the same as `SomeType.toString`, not
+ // `(SomeType).toString`.
+ isNullAware = false;
+
+ Name name = send.name;
+ Arguments arguments = send.arguments;
+
+ if (declaration is KernelClassBuilder) {
+ KernelClassBuilder declaration = this.declaration;
+ Builder builder = declaration.findStaticBuilder(
+ name.name, offsetForToken(token), uri, helper.library);
+
+ Generator generator;
+ if (builder == null) {
+ // If we find a setter, [builder] is an [AccessErrorBuilder], not null.
+ if (send is IncompletePropertyAccessGenerator) {
+ generator = new UnresolvedNameGenerator(helper, send.token, name);
+ } else {
+ return helper.buildConstructorInvocation(declaration, send.token,
+ arguments, name.name, null, token.charOffset, Constness.implicit);
+ }
+ } else {
+ Builder setter;
+ if (builder.isSetter) {
+ setter = builder;
+ } else if (builder.isGetter) {
+ setter = declaration.findStaticBuilder(
+ name.name, offsetForToken(token), uri, helper.library,
+ isSetter: true);
+ } else if (builder.isField && !builder.isFinal) {
+ setter = builder;
+ }
+ generator = new StaticAccessGenerator.fromBuilder(
+ helper, builder, send.token, setter);
+ }
+
+ return arguments == null
+ ? generator
+ : generator.doInvocation(offsetForToken(send.token), arguments);
+ } else {
+ return super.buildPropertyAccess(send, operatorOffset, isNullAware);
+ }
+ }
+
+ @override
+ DartType buildTypeWithBuiltArguments(List<DartType> arguments,
+ {bool nonInstanceAccessIsError: false}) {
+ if (arguments != null) {
+ int expected = 0;
+ if (declaration is KernelClassBuilder) {
+ expected = declaration.target.typeParameters.length;
+ } else if (declaration is FunctionTypeAliasBuilder) {
+ expected = declaration.target.typeParameters.length;
+ } else if (declaration is KernelTypeVariableBuilder) {
+ // Type arguments on a type variable - error reported elsewhere.
+ } else if (declaration is BuiltinTypeBuilder) {
+ // Type arguments on a built-in type, for example, dynamic or void.
+ expected = 0;
+ } else {
+ return unhandled(
+ "${declaration.runtimeType}",
+ "TypeDeclarationAccessGenerator.buildType",
+ offsetForToken(token),
+ helper.uri);
+ }
+ if (arguments.length != expected) {
+ helper.warnTypeArgumentsMismatch(
+ declaration.name, expected, offsetForToken(token));
+ // We ignore the provided arguments, which will in turn return the
+ // raw type below.
+ // TODO(sigmund): change to use an InvalidType and include the raw type
+ // as a recovery node once the IR can represent it (Issue #29840).
+ arguments = null;
+ }
+ }
+
+ DartType type;
+ if (arguments == null) {
+ TypeDeclarationBuilder typeDeclaration = declaration;
+ if (typeDeclaration is KernelClassBuilder) {
+ type = typeDeclaration.buildType(helper.library, null);
+ } else if (typeDeclaration is KernelFunctionTypeAliasBuilder) {
+ type = typeDeclaration.buildType(helper.library, null);
+ }
+ }
+ if (type == null) {
+ type =
+ declaration.buildTypesWithBuiltArguments(helper.library, arguments);
+ }
+ if (type is TypeParameterType) {
+ return helper.validatedTypeVariableUse(
+ type, offsetForToken(token), nonInstanceAccessIsError);
+ }
+ return type;
+ }
+
+ @override
+ Expression doInvocation(int offset, Arguments arguments) {
+ return helper.buildConstructorInvocation(declaration, token, arguments, "",
+ null, token.charOffset, Constness.implicit);
+ }
+}
+
+abstract class ContextAwareGenerator
+ extends Generator<Expression, Statement, Arguments> {
+ final Generator generator;
+
+ ContextAwareGenerator(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ this.generator)
+ : super(helper, token);
+
+ String get plainNameForRead {
+ return unsupported("plainNameForRead", token.charOffset, helper.uri);
+ }
+
+ Expression doInvocation(int charOffset, Arguments arguments) {
+ return unhandled("${runtimeType}", "doInvocation", charOffset, uri);
+ }
+
+ Expression buildSimpleRead();
+
+ Expression buildForEffect();
+
+ Expression buildAssignment(Expression value, {bool voidContext: false}) {
+ return makeInvalidWrite(value);
+ }
+
+ Expression buildNullAwareAssignment(
+ Expression value, DartType type, int offset,
+ {bool voidContext: false}) {
+ return makeInvalidWrite(value);
+ }
+
+ Expression buildCompoundAssignment(Name binaryOperator, Expression value,
+ {int offset: TreeNode.noOffset,
+ bool voidContext: false,
+ Procedure interfaceTarget,
+ bool isPreIncDec: false}) {
+ return makeInvalidWrite(value);
+ }
+
+ Expression buildPrefixIncrement(Name binaryOperator,
+ {int offset: TreeNode.noOffset,
+ bool voidContext: false,
+ Procedure interfaceTarget}) {
+ return makeInvalidWrite(null);
+ }
+
+ Expression buildPostfixIncrement(Name binaryOperator,
+ {int offset: TreeNode.noOffset,
+ bool voidContext: false,
+ Procedure interfaceTarget}) {
+ return makeInvalidWrite(null);
+ }
+
+ makeInvalidRead() {
+ return unsupported("makeInvalidRead", token.charOffset, helper.uri);
+ }
+
+ Expression makeInvalidWrite(Expression value) {
+ return helper.deprecated_buildCompileTimeError(
+ "Can't be used as left-hand side of assignment.",
+ offsetForToken(token));
+ }
+}
+
+class DelayedAssignment extends ContextAwareGenerator {
+ final Expression value;
+
+ final String assignmentOperator;
+
+ DelayedAssignment(ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token, Generator generator, this.value, this.assignmentOperator)
+ : super(helper, token, generator);
+
+ String get debugName => "DelayedAssignment";
+
+ Expression buildSimpleRead() {
+ return handleAssignment(false);
+ }
+
+ Expression buildForEffect() {
+ return handleAssignment(true);
+ }
+
+ Expression handleAssignment(bool voidContext) {
+ if (helper.constantContext != ConstantContext.none) {
+ return helper.deprecated_buildCompileTimeError(
+ "Not a constant expression.", offsetForToken(token));
+ }
+ if (identical("=", assignmentOperator)) {
+ return generator.buildAssignment(value, voidContext: voidContext);
+ } else if (identical("+=", assignmentOperator)) {
+ return generator.buildCompoundAssignment(plusName, value,
+ offset: offsetForToken(token), voidContext: voidContext);
+ } else if (identical("-=", assignmentOperator)) {
+ return generator.buildCompoundAssignment(minusName, value,
+ offset: offsetForToken(token), voidContext: voidContext);
+ } else if (identical("*=", assignmentOperator)) {
+ return generator.buildCompoundAssignment(multiplyName, value,
+ offset: offsetForToken(token), voidContext: voidContext);
+ } else if (identical("%=", assignmentOperator)) {
+ return generator.buildCompoundAssignment(percentName, value,
+ offset: offsetForToken(token), voidContext: voidContext);
+ } else if (identical("&=", assignmentOperator)) {
+ return generator.buildCompoundAssignment(ampersandName, value,
+ offset: offsetForToken(token), voidContext: voidContext);
+ } else if (identical("/=", assignmentOperator)) {
+ return generator.buildCompoundAssignment(divisionName, value,
+ offset: offsetForToken(token), voidContext: voidContext);
+ } else if (identical("<<=", assignmentOperator)) {
+ return generator.buildCompoundAssignment(leftShiftName, value,
+ offset: offsetForToken(token), voidContext: voidContext);
+ } else if (identical(">>=", assignmentOperator)) {
+ return generator.buildCompoundAssignment(rightShiftName, value,
+ offset: offsetForToken(token), voidContext: voidContext);
+ } else if (identical("??=", assignmentOperator)) {
+ return generator.buildNullAwareAssignment(
+ value, const DynamicType(), offsetForToken(token),
+ voidContext: voidContext);
+ } else if (identical("^=", assignmentOperator)) {
+ return generator.buildCompoundAssignment(caretName, value,
+ offset: offsetForToken(token), voidContext: voidContext);
+ } else if (identical("|=", assignmentOperator)) {
+ return generator.buildCompoundAssignment(barName, value,
+ offset: offsetForToken(token), voidContext: voidContext);
+ } else if (identical("~/=", assignmentOperator)) {
+ return generator.buildCompoundAssignment(mustacheName, value,
+ offset: offsetForToken(token), voidContext: voidContext);
+ } else {
+ return unhandled(
+ assignmentOperator, "handleAssignment", token.charOffset, helper.uri);
+ }
+ }
+
+ @override
+ Initializer buildFieldInitializer(Map<String, int> initializedFields) {
+ if (!identical("=", assignmentOperator) ||
+ !generator.isThisPropertyAccess) {
+ return generator.buildFieldInitializer(initializedFields);
+ }
+ return helper.buildFieldInitializer(
+ false, generator.plainNameForRead, offsetForToken(token), value);
+ }
+
+ @override
+ void printOn(StringSink sink) {
+ sink.write(", value: ");
+ printNodeOn(value, sink);
+ sink.write(", assignmentOperator: ");
+ sink.write(assignmentOperator);
+ }
+}
+
+class DelayedPostfixIncrement extends ContextAwareGenerator {
+ final Name binaryOperator;
+
+ final Procedure interfaceTarget;
+
+ DelayedPostfixIncrement(
+ ExpressionGeneratorHelper<dynamic, dynamic, dynamic> helper,
+ Token token,
+ Generator generator,
+ this.binaryOperator,
+ this.interfaceTarget)
+ : super(helper, token, generator);
+
+ String get debugName => "DelayedPostfixIncrement";
+
+ Expression buildSimpleRead() {
+ return generator.buildPostfixIncrement(binaryOperator,
+ offset: offsetForToken(token),
+ voidContext: false,
+ interfaceTarget: interfaceTarget);
+ }
+
+ Expression buildForEffect() {
+ return generator.buildPostfixIncrement(binaryOperator,
+ offset: offsetForToken(token),
+ voidContext: true,
+ interfaceTarget: interfaceTarget);
+ }
+
+ @override
+ void printOn(StringSink sink) {
+ sink.write(", binaryOperator: ");
+ sink.write(binaryOperator.name);
+ sink.write(", interfaceTarget: ");
+ printQualifiedNameOn(interfaceTarget, sink);
+ }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
index 59c4740..36b98a2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
@@ -34,7 +34,7 @@
InstrumentationValueForTypeArgs;
import '../fasta_codes.dart'
- show templateCantUseSuperBoundedTypeForInstanceCreation;
+ show noLength, templateCantUseSuperBoundedTypeForInstanceCreation;
import '../problems.dart' show unhandled, unsupported;
@@ -42,6 +42,8 @@
import '../source/source_library_builder.dart' show SourceLibraryBuilder;
+import '../type_inference/inference_helper.dart' show InferenceHelper;
+
import '../type_inference/interface_resolver.dart' show InterfaceResolver;
import '../type_inference/type_inference_engine.dart'
@@ -67,9 +69,7 @@
import 'body_builder.dart' show combineStatements;
-import 'expression_generator.dart' show makeLet;
-
-import 'expression_generator_helper.dart' show ExpressionGeneratorHelper;
+import 'kernel_expression_generator.dart' show makeLet;
/// Indicates whether type inference involving conditional expressions should
/// always use least upper bound.
@@ -618,11 +618,11 @@
if (inferrer.strongMode &&
!inferrer.isTopLevel &&
inferrer.typeSchemaEnvironment.isSuperBounded(inferredType)) {
- inferrer.helper.deprecated_addCompileTimeError(
- fileOffset,
+ inferrer.helper.addProblem(
templateCantUseSuperBoundedTypeForInstanceCreation
- .withArguments(inferredType)
- .message);
+ .withArguments(inferredType),
+ fileOffset,
+ noLength);
}
if (isRedirected(this)) {
@@ -2114,8 +2114,7 @@
}
@override
- void inferInitializer(
- ExpressionGeneratorHelper helper, Initializer initializer) {
+ void inferInitializer(InferenceHelper helper, Initializer initializer) {
assert(initializer is ShadowInitializer);
this.helper = helper;
// Use polymorphic dispatch on [KernelInitializer] to perform whatever
diff --git a/pkg/front_end/lib/src/fasta/parser/identifier_context.dart b/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
index a4075e1..787bc90 100644
--- a/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
+++ b/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
@@ -60,9 +60,8 @@
/// Identifier is a formal parameter being declared as part of a function,
/// method, or typedef declaration.
- static const formalParameterDeclaration = const IdentifierContext(
- 'formalParameterDeclaration',
- inDeclaration: true);
+ static const formalParameterDeclaration =
+ const FormalParameterDeclarationIdentifierContext();
/// Identifier is the start of a library name (e.g. `foo` in the directive
/// 'library foo;`).
@@ -146,15 +145,6 @@
static const operatorName =
const MethodDeclarationIdentifierContext.continuation();
- /// Identifier is the name being declared by a local function declaration that
- /// uses a "get" or "set" keyword.
- ///
- /// TODO(paulberry,ahe): Does this ever occur in valid Dart, or does it only
- /// occur as part of error recovery? If it's only as part of error recovery,
- /// perhaps we should just re-use localFunctionDeclaration.
- static const localAccessorDeclaration =
- const IdentifierContext('localAccessorDeclaration', inDeclaration: true);
-
/// Identifier is the start of the name being declared by a local function
/// declaration.
static const localFunctionDeclaration =
diff --git a/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart b/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
index 2beb97c..18dd095 100644
--- a/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
+++ b/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
@@ -298,6 +298,39 @@
}
}
+/// See [IdentifierContext.formalParameterDeclaration].
+class FormalParameterDeclarationIdentifierContext extends IdentifierContext {
+ const FormalParameterDeclarationIdentifierContext()
+ : super('formalParameterDeclaration', inDeclaration: true);
+
+ @override
+ Token ensureIdentifier(Token token, Parser parser) {
+ Token identifier = token.next;
+ assert(identifier.kind != IDENTIFIER_TOKEN);
+ if (identifier.isIdentifier) {
+ return identifier;
+ }
+
+ // Recovery
+ const followingValues = const [':', '=', ',', '(', ')', '[', ']', '{', '}'];
+ if (looksLikeStartOfNextClassMember(identifier) ||
+ looksLikeStartOfNextStatement(identifier) ||
+ isOneOfOrEof(identifier, followingValues)) {
+ identifier = parser.insertSyntheticIdentifier(token, this,
+ message: fasta.templateExpectedIdentifier.withArguments(identifier));
+ } else {
+ parser.reportRecoverableErrorWithToken(
+ identifier, fasta.templateExpectedIdentifier);
+ if (!identifier.isKeywordOrIdentifier) {
+ // When in doubt, consume the token to ensure we make progress
+ // but insert a synthetic identifier to satisfy listeners.
+ identifier = parser.rewriter.insertSyntheticIdentifier(identifier);
+ }
+ }
+ return identifier;
+ }
+}
+
/// See [IdentifierContext.importPrefixDeclaration].
class ImportPrefixIdentifierContext extends IdentifierContext {
const ImportPrefixIdentifierContext()
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index fc82a91..0b81640 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -21,6 +21,7 @@
Keyword,
POSTFIX_PRECEDENCE,
RELATIONAL_PRECEDENCE,
+ SELECTOR_PRECEDENCE,
SyntheticBeginToken,
SyntheticKeywordToken,
SyntheticStringToken,
@@ -1195,12 +1196,25 @@
}
token = parseFormalParameter(token, FormalParameterKind.mandatory, kind);
next = token.next;
- if (optional(',', next)) {
- token = next;
- continue;
+ if (!optional(',', next)) {
+ Token next = token.next;
+ if (optional(')', next)) {
+ token = next;
+ } else {
+ // Recovery
+ if (begin.endGroup.isSynthetic) {
+ // Scanner has already reported a missing `)` error,
+ // but placed the `)` in the wrong location, so move it.
+ token = rewriter.moveSynthetic(token, begin.endGroup);
+ } else {
+ reportRecoverableError(
+ next, fasta.templateExpectedButGot.withArguments(')'));
+ token = begin.endGroup;
+ }
+ }
+ break;
}
- token = ensureCloseParen(token, begin);
- break;
+ token = next;
}
assert(optional(')', token));
listener.endFormalParameters(parameterCount, begin, token, kind);
@@ -2013,15 +2027,11 @@
followingValues = [';'];
} else if (context == IdentifierContext.constructorReferenceContinuation) {
followingValues = ['.', ',', '(', ')', '[', ']', '}', ';'];
- } else if (context == IdentifierContext.formalParameterDeclaration) {
- followingValues = [':', '=', ',', '(', ')', '[', ']', '{', '}'];
} else if (context == IdentifierContext.labelDeclaration) {
followingValues = [':'];
} else if (context == IdentifierContext.literalSymbol ||
context == IdentifierContext.literalSymbolContinuation) {
followingValues = ['.', ';'];
- } else if (context == IdentifierContext.localAccessorDeclaration) {
- followingValues = ['(', '{', '=>'];
} else {
return false;
}
@@ -2041,8 +2051,6 @@
return false;
}
- List<String> classMemberKeywords() =>
- <String>['const', 'final', 'var', 'void'];
List<String> statementKeywords() => <String>[
'const',
'do',
@@ -2054,19 +2062,6 @@
'void',
'while'
];
- List<String> topLevelKeywords() => <String>[
- 'class',
- 'const',
- 'enum',
- 'export',
- 'final',
- 'import',
- 'library',
- 'part',
- 'typedef',
- 'var',
- 'void'
- ];
// TODO(brianwilkerson): At the moment, this test is entirely based on data
// that can be represented declaratively. If that proves to be sufficient,
@@ -2074,14 +2069,7 @@
// could create a method to test whether a given token matches one of the
// patterns.
List<String> initialKeywords;
- if (context == IdentifierContext.formalParameterDeclaration) {
- initialKeywords = topLevelKeywords()
- ..addAll(classMemberKeywords())
- ..addAll(statementKeywords())
- ..add('covariant');
- } else if (context == IdentifierContext.labelDeclaration) {
- initialKeywords = statementKeywords();
- } else if (context == IdentifierContext.localAccessorDeclaration) {
+ if (context == IdentifierContext.labelDeclaration) {
initialKeywords = statementKeywords();
} else if (context ==
IdentifierContext.localFunctionDeclarationContinuation) {
@@ -2301,32 +2289,6 @@
return token;
}
- /// Returns true if [token] could be the start of a function body.
- bool looksLikeFunctionBody(Token token) {
- return optional('{', token) ||
- optional('=>', token) ||
- optional('async', token) ||
- optional('sync', token);
- }
-
- /// Returns true if [token] could be the start of a function declaration
- /// without a return type.
- bool looksLikeFunctionDeclaration(Token token) {
- if (!token.isIdentifier) {
- return false;
- }
- token = token.next;
- if (optional('<', token)) {
- Token closeBrace = token.endGroup;
- if (closeBrace == null) return false;
- token = closeBrace.next;
- }
- if (optional('(', token)) {
- return looksLikeFunctionBody(token.endGroup.next);
- }
- return false;
- }
-
switch (continuation) {
case TypeContinuation.Required:
// If the token after the type is not an identifier,
@@ -2364,41 +2326,6 @@
case TypeContinuation.OptionalAfterVar:
hasVar = true;
continue optional;
-
- case TypeContinuation.SendOrFunctionLiteral:
- Token beforeName;
- Token name;
- bool hasReturnType;
- if (looksLikeType && looksLikeFunctionDeclaration(token)) {
- beforeName = beforeToken;
- name = token;
- hasReturnType = true;
- // Fall-through to parseNamedFunctionRest below.
- } else if (looksLikeFunctionDeclaration(begin)) {
- beforeName = beforeBegin;
- name = begin;
- hasReturnType = false;
- // Fall-through to parseNamedFunctionRest below.
- } else {
- return parseSend(beforeBegin, continuationContext);
- }
-
- Token formals = parseTypeVariablesOpt(name);
- listener.beginNamedFunctionExpression(begin);
- if (hasReturnType) {
- if (voidToken != null) {
- listener.handleVoidKeyword(voidToken);
- } else {
- commitType();
- }
- reportRecoverableError(
- begin, fasta.messageReturnTypeFunctionExpression);
- } else {
- listener.handleNoType(formals);
- }
- if (beforeName.next != name)
- throw new StateError("beforeName.next != name");
- return parseNamedFunctionRest(beforeName, begin, formals, true);
}
throw "Internal error: Unhandled continuation '$continuation'.";
@@ -3494,6 +3421,16 @@
return token;
}
+ Token parseFunctionLiteral(
+ final Token start, TypeInfo typeInfo, IdentifierContext context) {
+ Token beforeName = typeInfo.skipType(start);
+ assert(beforeName.next.isIdentifier);
+ Token formals = parseTypeVariablesOpt(beforeName.next);
+ listener.beginNamedFunctionExpression(start.next);
+ typeInfo.parseType(start, this);
+ return parseNamedFunctionRest(beforeName, start.next, formals, true);
+ }
+
/// Parses the rest of a named function declaration starting from its [name]
/// but then skips any type parameters and continue parsing from [formals]
/// (the formal parameters).
@@ -4027,7 +3964,7 @@
Token parsePrecedenceExpression(
Token token, int precedence, bool allowCascades) {
assert(precedence >= 1);
- assert(precedence <= POSTFIX_PRECEDENCE);
+ assert(precedence <= SELECTOR_PRECEDENCE);
token = parseUnaryExpression(token, allowCascades);
Token next = token.next;
TokenType type = next.type;
@@ -4058,10 +3995,16 @@
token = parsePrecedenceExpression(token.next, level, allowCascades);
listener.handleAssignmentExpression(operator);
} else if (identical(tokenLevel, POSTFIX_PRECEDENCE)) {
+ if ((identical(type, TokenType.PLUS_PLUS)) ||
+ (identical(type, TokenType.MINUS_MINUS))) {
+ listener.handleUnaryPostfixAssignmentExpression(token.next);
+ token = next;
+ }
+ } else if (identical(tokenLevel, SELECTOR_PRECEDENCE)) {
if (identical(type, TokenType.PERIOD) ||
identical(type, TokenType.QUESTION_PERIOD)) {
// Left associative, so we recurse at the next higher precedence
- // level. However, POSTFIX_PRECEDENCE is the highest level, so we
+ // level. However, SELECTOR_PRECEDENCE is the highest level, so we
// should just call [parseUnaryExpression] directly. However, a
// unary expression isn't legal after a period, so we call
// [parsePrimary] instead.
@@ -4072,10 +4015,6 @@
(identical(type, TokenType.OPEN_SQUARE_BRACKET))) {
token = parseArgumentOrIndexStar(token, typeArguments);
next = token.next;
- } else if ((identical(type, TokenType.PLUS_PLUS)) ||
- (identical(type, TokenType.MINUS_MINUS))) {
- listener.handleUnaryPostfixAssignmentExpression(token.next);
- token = next;
} else if (identical(type, TokenType.INDEX)) {
BeginToken replacement = link(
new BeginToken(TokenType.OPEN_SQUARE_BRACKET, next.charOffset,
@@ -4605,9 +4544,12 @@
Token parseSendOrFunctionLiteral(Token token, IdentifierContext context) {
if (!mayParseFunctionExpressions) {
return parseSend(token, context);
- } else {
- return parseType(token, TypeContinuation.SendOrFunctionLiteral, context);
}
+ TypeInfo typeInfo = computeType(token, false);
+ if (!looksLikeFunctionDeclaration(typeInfo.skipType(token).next)) {
+ return parseSend(token, context);
+ }
+ return parseFunctionLiteral(token, typeInfo, context);
}
Token parseRequiredArguments(Token token) {
@@ -5019,6 +4961,32 @@
return false;
}
+ /// Returns true if [token] could be the start of a function body.
+ bool looksLikeFunctionBody(Token token) {
+ return optional('{', token) ||
+ optional('=>', token) ||
+ optional('async', token) ||
+ optional('sync', token);
+ }
+
+ /// Returns true if [token] could be the start of a function declaration
+ /// without a return type.
+ bool looksLikeFunctionDeclaration(Token token) {
+ if (!token.isIdentifier) {
+ return false;
+ }
+ token = token.next;
+ if (optional('<', token)) {
+ Token closeBrace = token.endGroup;
+ if (closeBrace == null) return false;
+ token = closeBrace.next;
+ }
+ if (optional('(', token)) {
+ return looksLikeFunctionBody(token.endGroup.next);
+ }
+ return false;
+ }
+
Token parseExpressionStatementOrConstDeclaration(final Token start) {
Token constToken = start.next;
assert(optional('const', constToken));
@@ -5113,7 +5081,8 @@
listener.beginMetadataStar(start.next);
listener.endMetadataStar(0);
}
- Token beforeFormals = parseTypeVariablesOpt(next);
+ Token beforeFormals =
+ computeTypeParamOrArg(next).parseVariables(next, this);
listener.beginLocalFunctionDeclaration(start.next);
token = typeInfo.parseType(beforeType, this);
next = token.next;
diff --git a/pkg/front_end/lib/src/fasta/parser/type_continuation.dart b/pkg/front_end/lib/src/fasta/parser/type_continuation.dart
index 1f317ab..32effd3 100644
--- a/pkg/front_end/lib/src/fasta/parser/type_continuation.dart
+++ b/pkg/front_end/lib/src/fasta/parser/type_continuation.dart
@@ -24,8 +24,4 @@
/// Same as [Optional], but we have seen `var`.
OptionalAfterVar,
-
- /// Indicates that the parser is parsing an expression and has just seen an
- /// identifier.
- SendOrFunctionLiteral,
}
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
index 71ae91c..b4639f1 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -5,8 +5,15 @@
library fasta.diet_listener;
import 'package:kernel/ast.dart'
- show AsyncMarker, Class, InterfaceType, Typedef;
-import 'package:kernel/ast.dart';
+ show
+ AsyncMarker,
+ Class,
+ Expression,
+ InterfaceType,
+ Library,
+ LibraryDependency,
+ LibraryPart,
+ Typedef;
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index 1a2fa07..8244fca 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -62,7 +62,7 @@
import 'source_library_builder.dart' show SourceLibraryBuilder;
-import 'unhandled_listener.dart' show NullValue, UnhandledListener;
+import 'stack_listener.dart' show NullValue, StackListener;
import '../configuration.dart' show Configuration;
@@ -72,7 +72,7 @@
RedirectingFactoryBody,
}
-class OutlineBuilder extends UnhandledListener {
+class OutlineBuilder extends StackListener {
final SourceLibraryBuilder library;
final bool enableNative;
@@ -90,7 +90,6 @@
@override
Uri get uri => library.fileUri;
- @override
int popCharOffset() => pop();
List<String> popIdentifierList(int count) {
diff --git a/pkg/front_end/lib/src/fasta/source/scope_listener.dart b/pkg/front_end/lib/src/fasta/source/scope_listener.dart
index 5bb4fa0..e9a61e3 100644
--- a/pkg/front_end/lib/src/fasta/source/scope_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/scope_listener.dart
@@ -6,11 +6,11 @@
import '../../scanner/token.dart' show Token;
-import 'unhandled_listener.dart' show NullValue, UnhandledListener;
-
import '../scope.dart' show Scope;
-export 'unhandled_listener.dart' show NullValue, Unhandled;
+import 'stack_listener.dart' show NullValue, StackListener;
+
+export 'stack_listener.dart' show NullValue;
enum JumpTargetKind {
Break,
@@ -18,7 +18,7 @@
Goto, // Continue label in switch.
}
-abstract class ScopeListener<J> extends UnhandledListener {
+abstract class ScopeListener<J> extends StackListener {
Scope scope;
J breakTarget;
diff --git a/pkg/front_end/lib/src/fasta/source/stack_listener.dart b/pkg/front_end/lib/src/fasta/source/stack_listener.dart
index f312680..ef9eda1 100644
--- a/pkg/front_end/lib/src/fasta/source/stack_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/stack_listener.dart
@@ -111,7 +111,7 @@
if (tokenOrNull == null) stack.push(nullValue);
}
- Object peek() => stack.last;
+ Object peek() => stack.isNotEmpty ? stack.last : null;
Object pop([NullValue nullValue]) {
return stack.pop(nullValue);
diff --git a/pkg/front_end/lib/src/fasta/source/unhandled_listener.dart b/pkg/front_end/lib/src/fasta/source/unhandled_listener.dart
deleted file mode 100644
index c678a477..0000000
--- a/pkg/front_end/lib/src/fasta/source/unhandled_listener.dart
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
-// 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.
-
-library fasta.unhandled_listener;
-
-import '../../scanner/token.dart' show Token;
-
-import 'stack_listener.dart' show NullValue, StackListener;
-
-export 'stack_listener.dart' show NullValue;
-
-// TODO(ahe): Get rid of this.
-enum Unhandled {
- ConditionalUri,
- ConditionalUris,
- DottedName,
- Hide,
- Initializers,
- Interpolation,
- Metadata,
- Show,
- TypeVariables,
-}
-
-// TODO(ahe): Get rid of this class when all listeners are complete.
-abstract class UnhandledListener extends StackListener {
- int popCharOffset() => -1;
-
- List<String> popIdentifierList(int count) => popList(count);
-
- @override
- void endConditionalUri(Token ifKeyword, Token leftParen, Token equalSign) {
- debugEvent("ConditionalUri");
- popCharOffset();
- pop(); // URI.
- if (equalSign != null) popCharOffset();
- popIfNotNull(equalSign); // String.
- pop(); // DottedName.
- push(Unhandled.ConditionalUri);
- }
-
- @override
- void endConditionalUris(int count) {
- debugEvent("ConditionalUris");
- popList(count);
- push(Unhandled.ConditionalUris);
- }
-
- @override
- void endHide(Token hideKeyword) {
- debugEvent("Hide");
- pop();
- push(Unhandled.Hide);
- }
-
- @override
- void endShow(Token showKeyword) {
- debugEvent("Show");
- pop();
- push(Unhandled.Show);
- }
-
- @override
- void endCombinators(int count) {
- debugEvent("Combinators");
- push(popList(count) ?? NullValue.Combinators);
- }
-
- @override
- void handleDottedName(int count, Token firstIdentifier) {
- debugEvent("DottedName");
- popIdentifierList(count);
- push(Unhandled.DottedName);
- }
-
- @override
- void endFunctionType(Token functionToken, Token endToken) {
- pop(); // Formals.
- pop(); // Return type.
- pop(); // Type variables.
- push(NullValue.Type);
- }
-}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
new file mode 100644
index 0000000..d7c29df
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// 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:kernel/ast.dart' show FunctionType;
+
+import '../fasta_codes.dart' show LocatedMessage, Message;
+
+abstract class InferenceHelper<Expression, Statement, Arguments> {
+ Expression wrapInCompileTimeError(Expression expression, Message message);
+
+ Expression buildCompileTimeError(Message message, int charOffset, int length,
+ {List<LocatedMessage> context});
+
+ LocatedMessage checkArgumentsForType(
+ FunctionType function, Arguments arguments, int offset);
+
+ void addProblem(Message message, int charOffset, int length);
+}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 9237dcd..58c6532 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -62,10 +62,7 @@
import '../fasta_codes.dart';
-import '../kernel/expression_generator.dart' show buildIsNull;
-
-import '../kernel/expression_generator_helper.dart'
- show ExpressionGeneratorHelper;
+import '../kernel/kernel_expression_generator.dart' show buildIsNull;
import '../kernel/kernel_shadow_ast.dart'
show
@@ -85,6 +82,8 @@
import '../source/source_loader.dart' show SourceLoader;
+import 'inference_helper.dart' show InferenceHelper;
+
import 'interface_resolver.dart' show ForwardingNode, SyntheticAccessor;
import 'type_constraint_gatherer.dart' show TypeConstraintGatherer;
@@ -324,20 +323,18 @@
Uri get uri;
/// Performs full type inference on the given field initializer.
- void inferFieldInitializer(ExpressionGeneratorHelper helper,
- DartType declaredType, Expression initializer);
+ void inferFieldInitializer(
+ InferenceHelper helper, DartType declaredType, Expression initializer);
/// Performs type inference on the given function body.
- void inferFunctionBody(ExpressionGeneratorHelper helper, DartType returnType,
+ void inferFunctionBody(InferenceHelper helper, DartType returnType,
AsyncMarker asyncMarker, Statement body);
/// Performs type inference on the given constructor initializer.
- void inferInitializer(
- ExpressionGeneratorHelper helper, Initializer initializer);
+ void inferInitializer(InferenceHelper helper, Initializer initializer);
/// Performs type inference on the given metadata annotations.
- void inferMetadata(
- ExpressionGeneratorHelper helper, List<Expression> annotations);
+ void inferMetadata(InferenceHelper helper, List<Expression> annotations);
/// Performs type inference on the given metadata annotations keeping the
/// existing helper if possible.
@@ -345,8 +342,8 @@
/// Performs type inference on the given function parameter initializer
/// expression.
- void inferParameterInitializer(ExpressionGeneratorHelper helper,
- Expression initializer, DartType declaredType);
+ void inferParameterInitializer(
+ InferenceHelper helper, Expression initializer, DartType declaredType);
}
/// Implementation of [TypeInferrer] which doesn't do any type inference.
@@ -366,27 +363,25 @@
Uri get uri => null;
@override
- void inferFieldInitializer(ExpressionGeneratorHelper helper,
- DartType declaredType, Expression initializer) {}
+ void inferFieldInitializer(
+ InferenceHelper helper, DartType declaredType, Expression initializer) {}
@override
- void inferFunctionBody(ExpressionGeneratorHelper helper, DartType returnType,
+ void inferFunctionBody(InferenceHelper helper, DartType returnType,
AsyncMarker asyncMarker, Statement body) {}
@override
- void inferInitializer(
- ExpressionGeneratorHelper helper, Initializer initializer) {}
+ void inferInitializer(InferenceHelper helper, Initializer initializer) {}
@override
- void inferMetadata(
- ExpressionGeneratorHelper helper, List<Expression> annotations) {}
+ void inferMetadata(InferenceHelper helper, List<Expression> annotations) {}
@override
void inferMetadataKeepingHelper(List<Expression> annotations) {}
@override
- void inferParameterInitializer(ExpressionGeneratorHelper helper,
- Expression initializer, DartType declaredType) {}
+ void inferParameterInitializer(
+ InferenceHelper helper, Expression initializer, DartType declaredType) {}
}
/// Derived class containing generic implementations of [TypeInferrer].
@@ -424,7 +419,7 @@
final SourceLibraryBuilder library;
- ExpressionGeneratorHelper helper;
+ InferenceHelper helper;
/// Context information for the current closure, or `null` if we are not
/// inside a closure.
@@ -930,8 +925,8 @@
Expression expression, DartType typeContext, bool typeNeeded);
@override
- void inferFieldInitializer(ExpressionGeneratorHelper helper,
- DartType declaredType, Expression initializer) {
+ void inferFieldInitializer(
+ InferenceHelper helper, DartType declaredType, Expression initializer) {
assert(closureContext == null);
this.helper = helper;
var actualType = inferExpression(
@@ -950,7 +945,7 @@
DartType inferFieldTopLevel(ShadowField field, bool typeNeeded);
@override
- void inferFunctionBody(ExpressionGeneratorHelper helper, DartType returnType,
+ void inferFunctionBody(InferenceHelper helper, DartType returnType,
AsyncMarker asyncMarker, Statement body) {
assert(closureContext == null);
this.helper = helper;
@@ -1243,8 +1238,7 @@
}
@override
- void inferMetadata(
- ExpressionGeneratorHelper helper, List<Expression> annotations) {
+ void inferMetadata(InferenceHelper helper, List<Expression> annotations) {
if (annotations != null) {
this.helper = helper;
inferMetadataKeepingHelper(annotations);
@@ -1326,8 +1320,8 @@
}
@override
- void inferParameterInitializer(ExpressionGeneratorHelper helper,
- Expression initializer, DartType declaredType) {
+ void inferParameterInitializer(
+ InferenceHelper helper, Expression initializer, DartType declaredType) {
assert(closureContext == null);
this.helper = helper;
assert(declaredType != null);
diff --git a/pkg/front_end/lib/src/scanner/token.dart b/pkg/front_end/lib/src/scanner/token.dart
index 7842a42..3543578 100644
--- a/pkg/front_end/lib/src/scanner/token.dart
+++ b/pkg/front_end/lib/src/scanner/token.dart
@@ -29,6 +29,7 @@
const int MULTIPLICATIVE_PRECEDENCE = 14;
const int PREFIX_PRECEDENCE = 15;
const int POSTFIX_PRECEDENCE = 16;
+const int SELECTOR_PRECEDENCE = 17;
/**
* The opening half of a grouping pair of tokens. This is used for curly
@@ -1289,7 +1290,7 @@
const TokenType('#', 'HASH', NO_PRECEDENCE, HASH_TOKEN);
static const TokenType INDEX = const TokenType(
- '[]', 'INDEX', POSTFIX_PRECEDENCE, INDEX_TOKEN,
+ '[]', 'INDEX', SELECTOR_PRECEDENCE, INDEX_TOKEN,
isOperator: true, isUserDefinableOperator: true);
static const TokenType INDEX_EQ = const TokenType(
@@ -1328,10 +1329,10 @@
'{', 'OPEN_CURLY_BRACKET', NO_PRECEDENCE, OPEN_CURLY_BRACKET_TOKEN);
static const TokenType OPEN_PAREN =
- const TokenType('(', 'OPEN_PAREN', POSTFIX_PRECEDENCE, OPEN_PAREN_TOKEN);
+ const TokenType('(', 'OPEN_PAREN', SELECTOR_PRECEDENCE, OPEN_PAREN_TOKEN);
static const TokenType OPEN_SQUARE_BRACKET = const TokenType('[',
- 'OPEN_SQUARE_BRACKET', POSTFIX_PRECEDENCE, OPEN_SQUARE_BRACKET_TOKEN);
+ 'OPEN_SQUARE_BRACKET', SELECTOR_PRECEDENCE, OPEN_SQUARE_BRACKET_TOKEN);
static const TokenType PERCENT = const TokenType(
'%', 'PERCENT', MULTIPLICATIVE_PRECEDENCE, PERCENT_TOKEN,
@@ -1342,7 +1343,7 @@
isOperator: true);
static const TokenType PERIOD =
- const TokenType('.', 'PERIOD', POSTFIX_PRECEDENCE, PERIOD_TOKEN);
+ const TokenType('.', 'PERIOD', SELECTOR_PRECEDENCE, PERIOD_TOKEN);
static const TokenType PERIOD_PERIOD = const TokenType(
'..', 'PERIOD_PERIOD', CASCADE_PRECEDENCE, PERIOD_PERIOD_TOKEN,
@@ -1365,7 +1366,7 @@
isOperator: true);
static const TokenType QUESTION_PERIOD = const TokenType(
- '?.', 'QUESTION_PERIOD', POSTFIX_PRECEDENCE, QUESTION_PERIOD_TOKEN,
+ '?.', 'QUESTION_PERIOD', SELECTOR_PRECEDENCE, QUESTION_PERIOD_TOKEN,
isOperator: true);
static const TokenType QUESTION_QUESTION = const TokenType(
@@ -1700,6 +1701,12 @@
this == TokenType.PLUS_PLUS ||
this == TokenType.MINUS_MINUS;
+ /**
+ * Return `true` if this type of token represents a selector operator
+ * (starting token of a selector).
+ */
+ bool get isSelectorOperator => precedence == SELECTOR_PRECEDENCE;
+
@override
String toString() => name;
diff --git a/pkg/front_end/test/dependency_grapher_test.dart b/pkg/front_end/test/dependency_grapher_test.dart
deleted file mode 100644
index 4d7e981..0000000
--- a/pkg/front_end/test/dependency_grapher_test.dart
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
-// 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 'dart:async';
-
-import 'package:front_end/src/api_prototype/compiler_options.dart';
-import 'package:front_end/src/api_prototype/dependency_grapher.dart';
-import 'package:front_end/src/api_prototype/memory_file_system.dart';
-import 'package:test/test.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-main() {
- defineReflectiveSuite(() {
- defineReflectiveTests(DependencyGrapherTest);
- });
-}
-
-final root = Uri.parse('org-dartlang-test:///');
-
-@reflectiveTest
-class DependencyGrapherTest {
- LibraryNode checkLibrary(LibraryCycleNode cycle, String uri,
- {List<String> dependencies: const ['dart:core'],
- List<String> parts: const []}) {
- var library = cycle.libraries[Uri.parse(uri)];
- expect('${library.uri}', uri);
- expect(library.dependencies.map((dep) => '${dep.uri}'),
- unorderedEquals(dependencies));
- expect(library.parts.map((part) => '$part'), unorderedEquals(parts));
- return library;
- }
-
- Future<List<LibraryCycleNode>> getCycles(Map<String, String> contents,
- {List<String> startingPoints, String packagesFilePath}) async {
- // If no starting points given, assume the first entry in [contents] is the
- // single starting point.
- startingPoints ??= [contents.keys.first];
- var fileSystem = new MemoryFileSystem(root);
- if (packagesFilePath == null) {
- fileSystem.entityForUri(Uri.parse('.packages')).writeAsStringSync('');
- }
- contents.forEach((path, text) {
- fileSystem.entityForUri(root.resolve(path)).writeAsStringSync(text);
- });
- // TODO(paulberry): implement and test other option possibilities.
- var options = new CompilerOptions()
- ..fileSystem = fileSystem
- ..chaseDependencies = true
- ..packagesFileUri = packagesFilePath == null
- ? Uri.parse('.packages')
- : root.resolve(packagesFilePath);
- var graph = await graphForProgram(
- startingPoints.map(root.resolve).toList(), options);
- return graph.topologicallySortedCycles;
- }
-
- /// Sort the given library cycles into a deterministic order based on their
- /// URIs for easier unit testing.
- List<LibraryCycleNode> sortCycles(Iterable<LibraryCycleNode> cycles) {
- var result = cycles.toList();
- String sortKey(LibraryCycleNode node) => node.libraries.keys.join(',');
- result.sort((a, b) => Comparable.compare(sortKey(a), sortKey(b)));
- return result;
- }
-
- test_explicitCoreDependency() async {
- // If "dart:core" is explicitly imported, there shouldn't be two imports of
- // "dart:core", just one.
- var cycles = await getCycles({'/foo.dart': 'import "dart:core";'});
- expect(cycles, hasLength(1));
- expect(cycles[0].libraries, hasLength(1));
- checkLibrary(cycles[0], 'org-dartlang-test:///foo.dart');
- }
-
- test_exportDependency() async {
- var cycles =
- await getCycles({'/foo.dart': 'export "bar.dart";', '/bar.dart': ''});
- expect(cycles, hasLength(2));
- expect(cycles[0].libraries, hasLength(1));
- checkLibrary(cycles[0], 'org-dartlang-test:///bar.dart');
- expect(cycles[1].libraries, hasLength(1));
- checkLibrary(cycles[1], 'org-dartlang-test:///foo.dart',
- dependencies: ['org-dartlang-test:///bar.dart', 'dart:core']);
- }
-
- test_importDependency() async {
- var cycles =
- await getCycles({'/foo.dart': 'import "bar.dart";', '/bar.dart': ''});
- expect(cycles, hasLength(2));
- expect(cycles[0].libraries, hasLength(1));
- checkLibrary(cycles[0], 'org-dartlang-test:///bar.dart');
- expect(cycles[1].libraries, hasLength(1));
- checkLibrary(cycles[1], 'org-dartlang-test:///foo.dart',
- dependencies: ['org-dartlang-test:///bar.dart', 'dart:core']);
- }
-
- test_multipleStartingPoints() async {
- var cycles = await getCycles({
- '/a.dart': 'import "c.dart";',
- '/b.dart': 'import "c.dart";',
- '/c.dart': ''
- }, startingPoints: [
- '/a.dart',
- '/b.dart'
- ]);
- expect(cycles, hasLength(3));
- expect(cycles[0].libraries, hasLength(1));
- checkLibrary(cycles[0], 'org-dartlang-test:///c.dart');
- // The other two cycles might be in any order, so sort them for
- // reproducibility.
- List<LibraryCycleNode> otherCycles = sortCycles(cycles.sublist(1));
- checkLibrary(otherCycles[0], 'org-dartlang-test:///a.dart',
- dependencies: ['org-dartlang-test:///c.dart', 'dart:core']);
- checkLibrary(otherCycles[1], 'org-dartlang-test:///b.dart',
- dependencies: ['org-dartlang-test:///c.dart', 'dart:core']);
- }
-
- test_packages() async {
- var cycles = await getCycles({
- '/foo.dart': 'import "package:foo/bar.dart";',
- '/.packages': 'foo:pkg/foo/lib\nbar:pkg/bar/lib\n',
- '/pkg/foo/lib/bar.dart': 'import "package:bar/baz.dart";',
- '/pkg/bar/lib/baz.dart': ''
- }, packagesFilePath: '/.packages');
- expect(cycles, hasLength(3));
- expect(cycles[0].libraries, hasLength(1));
- checkLibrary(cycles[0], 'package:bar/baz.dart');
- expect(cycles[1].libraries, hasLength(1));
- checkLibrary(cycles[1], 'package:foo/bar.dart',
- dependencies: ['package:bar/baz.dart', 'dart:core']);
- expect(cycles[2].libraries, hasLength(1));
- checkLibrary(cycles[2], 'org-dartlang-test:///foo.dart',
- dependencies: ['package:foo/bar.dart', 'dart:core']);
- }
-
- test_parts() async {
- var cycles = await getCycles({
- '/foo.dart': 'library foo; part "a.dart"; part "b.dart";',
- '/a.dart': 'part of foo;',
- '/b.dart': 'part of foo;'
- });
- expect(cycles, hasLength(1));
- expect(cycles[0].libraries, hasLength(1));
- checkLibrary(cycles[0], 'org-dartlang-test:///foo.dart',
- parts: ['org-dartlang-test:///a.dart', 'org-dartlang-test:///b.dart']);
- }
-
- test_relativeUris() async {
- var cycles = await getCycles({
- '/a.dart': 'import "b/c.dart";',
- '/b/c.dart': 'import "d/e.dart";',
- '/b/d/e.dart': 'import "../f.dart";',
- '/b/f.dart': ''
- });
- expect(cycles, hasLength(4));
- expect(cycles[0].libraries, hasLength(1));
- checkLibrary(cycles[0], 'org-dartlang-test:///b/f.dart');
- expect(cycles[1].libraries, hasLength(1));
- checkLibrary(cycles[1], 'org-dartlang-test:///b/d/e.dart',
- dependencies: ['org-dartlang-test:///b/f.dart', 'dart:core']);
- expect(cycles[2].libraries, hasLength(1));
- checkLibrary(cycles[2], 'org-dartlang-test:///b/c.dart',
- dependencies: ['org-dartlang-test:///b/d/e.dart', 'dart:core']);
- expect(cycles[3].libraries, hasLength(1));
- checkLibrary(cycles[3], 'org-dartlang-test:///a.dart',
- dependencies: ['org-dartlang-test:///b/c.dart', 'dart:core']);
- }
-
- test_sdkDependency() async {
- // Dependencies on the SDK should be recorded even if SDK libraries aren't
- // being included in the graph.
- var cycles = await getCycles({'/foo.dart': 'import "dart:async";'});
- expect(cycles, hasLength(1));
- expect(cycles[0].libraries, hasLength(1));
- checkLibrary(cycles[0], 'org-dartlang-test:///foo.dart',
- dependencies: ['dart:core', 'dart:async']);
- }
-
- test_simpleCycle() async {
- var cycles = await getCycles(
- {'/foo.dart': 'import "bar.dart";', '/bar.dart': 'import "foo.dart";'});
- expect(cycles, hasLength(1));
- expect(cycles[0].libraries, hasLength(2));
- var foo = checkLibrary(cycles[0], 'org-dartlang-test:///foo.dart',
- dependencies: ['org-dartlang-test:///bar.dart', 'dart:core']);
- var bar = checkLibrary(cycles[0], 'org-dartlang-test:///bar.dart',
- dependencies: ['org-dartlang-test:///foo.dart', 'dart:core']);
- expect(foo.dependencies[0], same(bar));
- expect(bar.dependencies[0], same(foo));
- }
-
- test_singleFile() async {
- var cycles = await getCycles({'/foo.dart': ''});
- expect(cycles, hasLength(1));
- expect(cycles[0].libraries, hasLength(1));
- checkLibrary(cycles[0], 'org-dartlang-test:///foo.dart');
- }
-}
diff --git a/pkg/front_end/test/fasta/generator_to_string_test.dart b/pkg/front_end/test/fasta/generator_to_string_test.dart
index e228c60..53b70fe 100644
--- a/pkg/front_end/test/fasta/generator_to_string_test.dart
+++ b/pkg/front_end/test/fasta/generator_to_string_test.dart
@@ -18,6 +18,7 @@
Name,
Procedure,
ProcedureKind,
+ Statement,
StringLiteral,
TypeParameter,
VariableDeclaration,
@@ -45,38 +46,40 @@
show Message, templateUnspecified;
import 'package:front_end/src/fasta/kernel/expression_generator.dart'
- show
- DeferredAccessGenerator,
- Generator,
- IncompleteErrorGenerator,
- IncompletePropertyAccessGenerator,
- IndexedAccessGenerator,
- LargeIntAccessGenerator,
- LoadLibraryGenerator,
- NullAwarePropertyAccessGenerator,
- ParenthesizedExpressionGenerator,
- PropertyAccessGenerator,
- ReadOnlyAccessGenerator,
- SendAccessGenerator,
- StaticAccessGenerator,
- SuperIndexedAccessGenerator,
- SuperPropertyAccessGenerator,
- ThisAccessGenerator,
- ThisIndexedAccessGenerator,
- ThisPropertyAccessGenerator,
- TypeDeclarationAccessGenerator,
- UnresolvedNameGenerator,
- VariableUseGenerator;
-
-import 'package:front_end/src/fasta/kernel/body_builder.dart'
- show DelayedAssignment, DelayedPostfixIncrement;
+ show Generator;
import 'package:front_end/src/fasta/kernel/kernel_body_builder.dart'
show KernelBodyBuilder;
+import 'package:front_end/src/fasta/kernel/kernel_expression_generator.dart'
+ show
+ DeferredAccessGenerator,
+ DelayedAssignment,
+ DelayedPostfixIncrement,
+ IncompleteErrorGenerator,
+ IncompletePropertyAccessGenerator,
+ KernelIndexedAccessGenerator,
+ KernelNullAwarePropertyAccessGenerator,
+ KernelPropertyAccessGenerator,
+ KernelSuperPropertyAccessGenerator,
+ KernelThisIndexedAccessGenerator,
+ KernelThisPropertyAccessGenerator,
+ KernelVariableUseGenerator,
+ LargeIntAccessGenerator,
+ LoadLibraryGenerator,
+ ParenthesizedExpressionGenerator,
+ ReadOnlyAccessGenerator,
+ SendAccessGenerator,
+ StaticAccessGenerator,
+ SuperIndexedAccessGenerator,
+ ThisAccessGenerator,
+ TypeDeclarationAccessGenerator,
+ UnresolvedNameGenerator;
+
import 'package:front_end/src/fasta/scanner.dart' show Token, scanString;
-void check(String expected, Generator<Arguments> generator) {
+void check(
+ String expected, Generator<Expression, Statement, Arguments> generator) {
Expect.stringEquals(expected, "$generator");
}
@@ -123,8 +126,7 @@
KernelBodyBuilder helper = new KernelBodyBuilder(
libraryBuilder, null, null, null, null, null, null, false, uri, null);
- Generator generator =
- new ThisAccessGenerator<Arguments>(helper, token, false);
+ Generator generator = new ThisAccessGenerator(helper, token, false);
Library library = new Library(uri);
Class cls = new Class();
@@ -136,98 +138,94 @@
check(
"DelayedAssignment(offset: 4, value: expression,"
" assignmentOperator: +=)",
- new DelayedAssignment<Arguments>(
+ new DelayedAssignment(
helper, token, generator, expression, assignmentOperator));
check(
"DelayedPostfixIncrement(offset: 4, binaryOperator: +,"
" interfaceTarget: $uri::#class1::myInterfaceTarget)",
- new DelayedPostfixIncrement<Arguments>(
+ new DelayedPostfixIncrement(
helper, token, generator, binaryOperator, interfaceTarget));
check(
"VariableUseGenerator(offset: 4, variable: dynamic #t1;\n,"
" promotedType: void)",
- new VariableUseGenerator<Arguments>(helper, token, variable, type));
+ new KernelVariableUseGenerator(helper, token, variable, type));
check(
"PropertyAccessGenerator(offset: 4, _receiverVariable: null,"
" receiver: expression, name: bar, getter: $uri::myGetter,"
" setter: $uri::mySetter)",
- new PropertyAccessGenerator<Arguments>.internal(
+ new KernelPropertyAccessGenerator.internal(
helper, token, expression, name, getter, setter));
check(
"ThisPropertyAccessGenerator(offset: 4, name: bar,"
" getter: $uri::myGetter, setter: $uri::mySetter)",
- new ThisPropertyAccessGenerator<Arguments>(
+ new KernelThisPropertyAccessGenerator(
helper, token, name, getter, setter));
check(
"NullAwarePropertyAccessGenerator(offset: 4,"
" receiver: final dynamic #t1 = expression;\n,"
" receiverExpression: expression, name: bar, getter: $uri::myGetter,"
" setter: $uri::mySetter, type: void)",
- new NullAwarePropertyAccessGenerator<Arguments>(
+ new KernelNullAwarePropertyAccessGenerator(
helper, token, expression, name, getter, setter, type));
check(
"SuperPropertyAccessGenerator(offset: 4, name: bar,"
" getter: $uri::myGetter, setter: $uri::mySetter)",
- new SuperPropertyAccessGenerator<Arguments>(
+ new KernelSuperPropertyAccessGenerator(
helper, token, name, getter, setter));
check(
"IndexedAccessGenerator(offset: 4, receiver: expression, index: index,"
" getter: $uri::myGetter, setter: $uri::mySetter,"
" receiverVariable: null, indexVariable: null)",
- new IndexedAccessGenerator<Arguments>.internal(
+ new KernelIndexedAccessGenerator.internal(
helper, token, expression, index, getter, setter));
check(
"ThisIndexedAccessGenerator(offset: 4, index: index,"
" getter: $uri::myGetter, setter: $uri::mySetter, indexVariable: null)",
- new ThisIndexedAccessGenerator<Arguments>(
+ new KernelThisIndexedAccessGenerator(
helper, token, index, getter, setter));
check(
"SuperIndexedAccessGenerator(offset: 4, index: index,"
" getter: $uri::myGetter, setter: $uri::mySetter, indexVariable: null)",
- new SuperIndexedAccessGenerator<Arguments>(
- helper, token, index, getter, setter));
+ new SuperIndexedAccessGenerator(helper, token, index, getter, setter));
check(
"StaticAccessGenerator(offset: 4, readTarget: $uri::myGetter,"
" writeTarget: $uri::mySetter)",
- new StaticAccessGenerator<Arguments>(helper, token, getter, setter));
+ new StaticAccessGenerator(helper, token, getter, setter));
check(
"LoadLibraryGenerator(offset: 4,"
" builder: Instance of 'LoadLibraryBuilder')",
- new LoadLibraryGenerator<Arguments>(helper, token, loadLibraryBuilder));
+ new LoadLibraryGenerator(helper, token, loadLibraryBuilder));
check(
"ThisAccessGenerator(offset: 4, isInitializer: false, isSuper: false)",
- new ThisAccessGenerator<Arguments>(helper, token, false));
+ new ThisAccessGenerator(helper, token, false));
check("IncompleteErrorGenerator(offset: 4, message: Unspecified)",
- new IncompleteErrorGenerator<Arguments>(helper, token, message));
+ new IncompleteErrorGenerator(helper, token, message));
check("SendAccessGenerator(offset: 4, name: bar, arguments: (\"arg\"))",
- new SendAccessGenerator<Arguments>(helper, token, name, arguments));
+ new SendAccessGenerator(helper, token, name, arguments));
check("IncompletePropertyAccessGenerator(offset: 4, name: bar)",
- new IncompletePropertyAccessGenerator<Arguments>(helper, token, name));
+ new IncompletePropertyAccessGenerator(helper, token, name));
check(
"DeferredAccessGenerator(offset: 4, "
"builder: Instance of 'PrefixBuilder',"
" generator: ThisAccessGenerator(offset: 4, isInitializer: false,"
" isSuper: false))",
- new DeferredAccessGenerator<Arguments>(
- helper, token, prefixBuilder, generator));
+ new DeferredAccessGenerator(helper, token, prefixBuilder, generator));
check(
"ReadOnlyAccessGenerator(offset: 4, expression: expression,"
" plainNameForRead: foo, value: null)",
- new ReadOnlyAccessGenerator<Arguments>(
- helper, token, expression, "foo"));
+ new ReadOnlyAccessGenerator(helper, token, expression, "foo"));
check("LargeIntAccessGenerator(offset: 4, lexeme: myToken)",
- new LargeIntAccessGenerator<Arguments>(helper, token));
+ new LargeIntAccessGenerator(helper, token));
check(
"ParenthesizedExpressionGenerator(offset: 4, expression: expression,"
" plainNameForRead: null, value: null)",
- new ParenthesizedExpressionGenerator<Arguments>(
- helper, token, expression));
+ new ParenthesizedExpressionGenerator(helper, token, expression));
check(
"TypeDeclarationAccessGenerator(offset: 4, expression: T,"
" plainNameForRead: foo, value: null)",
- new TypeDeclarationAccessGenerator<Arguments>(
+ new TypeDeclarationAccessGenerator(
helper, token, prefixBuilder, -1, declaration, "foo"));
check("UnresolvedNameGenerator(offset: 4, name: bar)",
- new UnresolvedNameGenerator<Arguments>(helper, token, name));
+ new UnresolvedNameGenerator(helper, token, name));
});
}
diff --git a/pkg/front_end/test/precedence_info_test.dart b/pkg/front_end/test/precedence_info_test.dart
index 60cb57a..3d6ee26 100644
--- a/pkg/front_end/test/precedence_info_test.dart
+++ b/pkg/front_end/test/precedence_info_test.dart
@@ -216,12 +216,7 @@
void test_isUnaryPostfixOperator() {
const unaryPostfixLexemes = const [
'--',
- '(',
- '[',
- '.',
'++',
- '?.',
- '[]',
];
assertInfo((String source, Token token) {
expect(token.type.isUnaryPostfixOperator,
@@ -245,6 +240,20 @@
});
}
+ void test_isSelectorOperator() {
+ const selectorLexemes = const [
+ '(',
+ '[',
+ '.',
+ '?.',
+ '[]',
+ ];
+ assertInfo((String source, Token token) {
+ expect(token.type.isSelectorOperator, selectorLexemes.contains(source),
+ reason: source);
+ });
+ }
+
void test_isUserDefinableOperator() {
const userDefinableOperatorLexemes = const [
'&',
@@ -358,7 +367,8 @@
/// because it is interpreted as a minus token (precedence 13).
void test_precedence() {
const precedenceTable = const <int, List<String>>{
- 16: const <String>['.', '?.', '++', '--', '[', '('],
+ 17: const <String>['.', '?.', '[', '('],
+ 16: const <String>['++', '--'],
15: const <String>['!', '~'], // excluded '-', '++', '--'
14: const <String>['*', '/', '~/', '%'],
13: const <String>['+', '-'],
diff --git a/pkg/front_end/test/src/async_dependency_walker_test.dart b/pkg/front_end/test/src/async_dependency_walker_test.dart
deleted file mode 100644
index 8cf0b28..0000000
--- a/pkg/front_end/test/src/async_dependency_walker_test.dart
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
-// 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 'dart:async';
-
-import 'package:front_end/src/async_dependency_walker.dart';
-import 'package:test/test.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-main() {
- defineReflectiveSuite(() {
- defineReflectiveTests(AsyncDependencyWalkerTest);
- });
-}
-
-@reflectiveTest
-class AsyncDependencyWalkerTest {
- final nodes = <String, TestNode>{};
-
- Future<Null> checkGraph(
- Map<String, List<String>> graph,
- String startingNodeName,
- List<List<String>> expectedEvaluations,
- List<bool> expectedSccFlags) async {
- makeGraph(graph);
- var walker = await walk(startingNodeName);
- expect(walker._evaluations, expectedEvaluations.map((x) => x.toSet()));
- expect(walker._sccFlags, expectedSccFlags);
- }
-
- TestNode getNode(String name) =>
- nodes.putIfAbsent(name, () => new TestNode(name));
-
- void makeGraph(Map<String, List<String>> graph) {
- graph.forEach((name, deps) {
- var node = getNode(name);
- for (var dep in deps) {
- node._dependencies.add(getNode(dep));
- }
- });
- }
-
- test_complex_graph() async {
- await checkGraph(
- {
- 'a': ['b', 'c'],
- 'b': ['c', 'd'],
- 'c': [],
- 'd': ['c', 'e'],
- 'e': ['b', 'f'],
- 'f': ['c', 'd']
- },
- 'a',
- [
- ['c'],
- ['b', 'd', 'e', 'f'],
- ['a']
- ],
- [false, true, false]);
- }
-
- test_diamond() async {
- await checkGraph(
- {
- 'a': ['b', 'c'],
- 'b': ['d'],
- 'c': ['d'],
- 'd': []
- },
- 'a',
- [
- ['d'],
- ['b'],
- ['c'],
- ['a']
- ],
- [false, false, false, false]);
- }
-
- test_singleNode() async {
- await checkGraph(
- {'a': []},
- 'a',
- [
- ['a']
- ],
- [false]);
- }
-
- test_singleNodeWithTrivialCycle() async {
- await checkGraph(
- {
- 'a': ['a']
- },
- 'a',
- [
- ['a']
- ],
- [true]);
- }
-
- test_threeNodesWithCircularDependency() async {
- await checkGraph(
- {
- 'a': ['b'],
- 'b': ['c'],
- 'c': ['a'],
- },
- 'a',
- [
- ['a', 'b', 'c']
- ],
- [true]);
- }
-
- test_twoBacklinksEarlierFirst() async {
- // Test a graph A->B->C->D, where D points back to B and then C.
- await checkGraph(
- {
- 'a': ['b'],
- 'b': ['c'],
- 'c': ['d'],
- 'd': ['b', 'c']
- },
- 'a',
- [
- ['b', 'c', 'd'],
- ['a']
- ],
- [true, false]);
- }
-
- test_twoBacklinksLaterFirst() async {
- // Test a graph A->B->C->D, where D points back to C and then B.
- await checkGraph(
- {
- 'a': ['b'],
- 'b': ['c'],
- 'c': ['d'],
- 'd': ['c', 'b']
- },
- 'a',
- [
- ['b', 'c', 'd'],
- ['a']
- ],
- [true, false]);
- }
-
- test_twoNodesWithCircularDependency() async {
- await checkGraph(
- {
- 'a': ['b'],
- 'b': ['a']
- },
- 'a',
- [
- ['a', 'b']
- ],
- [true]);
- }
-
- test_twoNodesWithSimpleDependency() async {
- await checkGraph(
- {
- 'a': ['b'],
- 'b': []
- },
- 'a',
- [
- ['b'],
- ['a']
- ],
- [false, false]);
- }
-
- Future<TestWalker> walk(String startingNodeName) async {
- var testWalker = new TestWalker();
- await testWalker.walk(getNode(startingNodeName));
- return testWalker;
- }
-}
-
-class TestNode extends Node<TestNode> {
- final String _name;
-
- bool _computeDependenciesCalled = false;
-
- final _dependencies = <TestNode>[];
-
- TestNode(this._name);
-
- @override
- Future<List<TestNode>> computeDependencies() async {
- expect(_computeDependenciesCalled, false);
- _computeDependenciesCalled = true;
- return _dependencies;
- }
-}
-
-class TestWalker extends AsyncDependencyWalker<TestNode> {
- final _evaluations = <Set<String>>[];
- final _sccFlags = <bool>[];
-
- @override
- Future<Null> evaluate(TestNode v) async {
- _evaluations.add([v._name].toSet());
- _sccFlags.add(false);
- }
-
- @override
- Future<Null> evaluateScc(List<TestNode> scc) async {
- var sccNames = scc.map((node) => node._name).toSet();
- // Make sure there were no duplicates
- expect(sccNames.length, scc.length);
- _evaluations.add(sccNames);
- _sccFlags.add(true);
- }
-}
diff --git a/pkg/front_end/test/subpackage_relationships_test.dart b/pkg/front_end/test/subpackage_relationships_test.dart
deleted file mode 100644
index bcf7288..0000000
--- a/pkg/front_end/test/subpackage_relationships_test.dart
+++ /dev/null
@@ -1,335 +0,0 @@
-// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
-// 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 'dart:async';
-import 'dart:io';
-
-import 'package:front_end/src/api_prototype/compiler_options.dart';
-import 'package:front_end/src/api_prototype/dependency_grapher.dart';
-import 'package:front_end/src/testing/package_root.dart' as package_root;
-import 'package:path/path.dart' as pathos;
-
-main() async {
- exit(await new _SubpackageRelationshipsTest().run());
-}
-
-/// List of packages that front_end is allowed to directly depend on.
-///
-/// Note that this script only checks files in pkg/front_end/lib, so this list
-/// excludes dev dependencies.
-final allowedPackageDependencies = [
- 'charcode',
- 'convert',
- 'crypto',
- 'kernel',
- 'meta',
- 'package_config',
- 'path',
- 'source_span',
- 'testing',
-];
-
-/// Map from subpackage name to the rules for what the subpackage is allowed to
-/// depend directly on.
-///
-/// Each listed directory is considered a subpackage. Each package contains all
-/// of its descendant files that are not in a more deeply nested subpackage.
-final subpackageRules = {
- 'lib/src': new SubpackageRules(allowedDependencies: [
- 'lib/src/api_prototype',
- 'lib/src/base',
- 'lib/src/fasta',
- "lib/src/fasta/dill",
- "lib/src/fasta/kernel",
- 'lib/src/fasta/source',
- ]),
- 'lib/src/api_prototype': new SubpackageRules(allowedDependencies: [
- 'lib/src',
- 'lib/src/base',
- 'lib/src/byte_store',
- 'lib/src/fasta',
- 'lib/src/fasta/scanner'
- ]),
- 'lib/src/api_unstable': new SubpackageRules(allowedDependencies: [
- 'lib/src',
- 'lib/src/api_prototype',
- 'lib/src/base',
- 'lib/src/fasta',
- ]),
- 'lib/src/base': new SubpackageRules(allowedDependencies: [
- 'lib/src/api_prototype',
- 'lib/src/fasta',
- 'lib/src/fasta/util',
- ]),
- // Note: byte_store should never depend on other parts of front_end, since we
- // may want to move it to its own package someday.
- 'lib/src/byte_store': new SubpackageRules(allowedDependencies: []),
- 'lib/src/codegen': new SubpackageRules(),
- 'lib/src/fasta': new SubpackageRules(allowedDependencies: [
- 'lib/src/api_prototype',
- 'lib/src/base',
- 'lib/src/fasta/builder',
- 'lib/src/fasta/dill',
- 'lib/src/fasta/kernel',
- 'lib/src/fasta/parser',
- 'lib/src/fasta/scanner',
- 'lib/src/fasta/source',
- 'lib/src/fasta/util',
- 'lib/src/scanner',
- ]),
- 'lib/src/fasta/builder': new SubpackageRules(allowedDependencies: [
- 'lib/src/base',
- 'lib/src/fasta',
- 'lib/src/fasta/parser',
- 'lib/src/fasta/source',
- ]),
- 'lib/src/fasta/dill': new SubpackageRules(allowedDependencies: [
- 'lib/src/fasta',
- 'lib/src/fasta/kernel',
- ]),
- 'lib/src/fasta/kernel': new SubpackageRules(allowedDependencies: [
- 'lib/src/api_prototype',
- 'lib/src/fasta',
- 'lib/src/base',
- 'lib/src/fasta/builder',
- 'lib/src/fasta/dill',
- 'lib/src/fasta/parser',
- 'lib/src/fasta/scanner',
- 'lib/src/fasta/source',
- 'lib/src/fasta/type_inference',
- 'lib/src/scanner',
- ]),
- 'lib/src/fasta/parser': new SubpackageRules(allowedDependencies: [
- 'lib/src/fasta',
- 'lib/src/fasta/scanner',
- 'lib/src/fasta/util',
- 'lib/src/scanner',
- ]),
- 'lib/src/fasta/scanner': new SubpackageRules(allowedDependencies: [
- 'lib/src/fasta',
- // fasta scanner produces analyzer scanner tokens
- 'lib/src/scanner',
- 'lib/src/fasta/util',
- ]),
- 'lib/src/fasta/source': new SubpackageRules(allowedDependencies: [
- 'lib/src/api_prototype',
- 'lib/src/fasta',
- 'lib/src/base',
- 'lib/src/fasta/builder',
- 'lib/src/fasta/dill',
- 'lib/src/fasta/kernel',
- 'lib/src/fasta/parser',
- 'lib/src/fasta/type_inference',
- 'lib/src/scanner',
- ]),
- 'lib/src/fasta/testing': new SubpackageRules(allowedDependencies: [
- 'lib/src/api_prototype',
- 'lib/src',
- 'lib/src/base',
- 'lib/src/fasta',
- 'lib/src/fasta/kernel',
- 'lib/src/fasta/scanner',
- 'lib/src/scanner',
- ]),
- 'lib/src/fasta/type_inference': new SubpackageRules(allowedDependencies: [
- 'lib/src/base',
- 'lib/src/fasta/builder',
- 'lib/src/fasta',
- 'lib/src/fasta/kernel',
- 'lib/src/fasta/source',
- ]),
- 'lib/src/fasta/util': new SubpackageRules(),
- 'lib/src/incremental': new SubpackageRules(allowedDependencies: [
- 'lib/src/api_prototype',
- 'lib/src',
- 'lib/src/base',
- 'lib/src/fasta',
- 'lib/src/fasta/dill',
- 'lib/src/fasta/kernel',
- 'lib/src/fasta/parser',
- 'lib/src/fasta/scanner',
- 'lib/src/fasta/source',
- ]),
- 'lib/src/scanner': new SubpackageRules(allowedDependencies: [
- 'lib/src/base',
- // For error codes.
- 'lib/src/fasta',
- // fasta scanner produces analyzer scanner tokens
- 'lib/src/fasta/scanner',
- ]),
- 'lib/src/testing': new SubpackageRules(allowedDependencies: [
- 'lib/src',
- 'lib/src/api_prototype',
- 'lib/src/fasta',
- ]),
-};
-
-/// Rules for what a subpackage may depend directly on.
-class SubpackageRules {
- /// Indicates whether dart files may exist in subdirectories of this
- /// subpackage.
- ///
- /// If `false`, any subdirectory of this subpackage must be a separate
- /// subpackage.
- final bool allowSubdirs;
-
- /// Indicates which other subpackages a given subpackage may directly depend
- /// on.
- final List<String> allowedDependencies;
-
- var actuallyContainsFiles = false;
-
- var actuallyHasSubdirs = false;
-
- var actualDependencies = new Set<String>();
-
- SubpackageRules(
- {this.allowSubdirs: false, this.allowedDependencies: const []});
-}
-
-class _SubpackageRelationshipsTest {
- /// File uri of the front_end package's "lib" directory.
- final frontEndLibUri =
- new Uri.file(package_root.packageRoot).resolve('front_end/lib/');
-
- /// Indicates whether any problems have been reported yet.
- bool problemsReported = false;
-
- /// Package dependencies that were actually discovered
- final actualPackageDependencies = <String>[];
-
- /// Check for problems resulting from URI [src] having a direct dependency on
- /// URI [dst].
- void checkDependency(Uri src, Uri dst) {
- var srcSubpackage = subpackageForUri(src);
- if (srcSubpackage == null) return;
- var srcSubpackageRules = subpackageRules[srcSubpackage];
- if (srcSubpackageRules == null) {
- problem('$src is in subpackage "$srcSubpackage", which is not found in '
- 'subpackageRules');
- return;
- }
- srcSubpackageRules.actuallyContainsFiles = true;
- if (dst.scheme == 'dart') return;
- if (dst.scheme != 'package') {
- problem('$src depends on $dst, which is neither a package: or dart: URI');
- return;
- }
- if (src.scheme == 'package' &&
- src.pathSegments[0] == 'front_end' &&
- dst.scheme == 'package' &&
- dst.pathSegments[0] != 'front_end') {
- if (allowedPackageDependencies.contains(dst.pathSegments[0])) {
- actualPackageDependencies.add(dst.pathSegments[0]);
- } else {
- problem('$src depends on package "${dst.pathSegments[0]}", which is '
- 'not found in allowedPackageDependencies');
- }
- }
- var dstSubPackage = subpackageForUri(dst);
- if (dstSubPackage == null) return;
- if (dstSubPackage == srcSubpackage) return;
- if (srcSubpackageRules.allowedDependencies.contains(dstSubPackage)) {
- srcSubpackageRules.actualDependencies.add(dstSubPackage);
- } else {
- problem('$src depends on $dst, but subpackage "$srcSubpackage" is not '
- 'allowed to depend on subpackage "$dstSubPackage"');
- }
- }
-
- /// Finds all files in the front_end's "lib" directory and returns their Uris
- /// (as "package:" URIs).
- List<Uri> findFrontEndUris() {
- var frontEndUris = <Uri>[];
- var frontEndLibPath = pathos.fromUri(frontEndLibUri);
- for (var entity in new Directory(frontEndLibPath)
- .listSync(recursive: true, followLinks: false)) {
- if (entity.path.endsWith('.dart')) {
- var posixRelativePath = pathos.url.joinAll(
- pathos.split(pathos.relative(entity.path, from: frontEndLibPath)));
- frontEndUris.add(Uri.parse('package:front_end/$posixRelativePath'));
- }
- }
- return frontEndUris;
- }
-
- /// Reports a single problem.
- void problem(String description) {
- print(description);
- problemsReported = true;
- }
-
- /// Tests all subpackage relationships in the front end, and returns an
- /// appropriate exit code.
- Future<int> run() async {
- var frontEndUris = await findFrontEndUris();
- var packagesFileUri = Platform.packageConfig != null
- ? Uri.parse(Platform.packageConfig)
- : frontEndLibUri.resolve('../../../.packages');
- var graph = await graphForProgram(
- frontEndUris,
- new CompilerOptions()
- ..packagesFileUri = packagesFileUri
- ..chaseDependencies = true);
- for (var i = 0; i < graph.topologicallySortedCycles.length; i++) {
- for (var library in graph.topologicallySortedCycles[i].libraries.values) {
- for (var dependency in library.dependencies) {
- checkDependency(library.uri, dependency.uri);
- }
- }
- }
- for (var package in allowedPackageDependencies) {
- if (!actualPackageDependencies.contains(package)) {
- problem('$package is listed in allowedPackageDependencies, '
- 'but is not used');
- }
- }
- subpackageRules.forEach((subpackage, rule) {
- if (!rule.actuallyContainsFiles) {
- problem("$subpackage contains no files");
- }
- if (rule.allowSubdirs && !rule.actuallyHasSubdirs) {
- problem("$subpackage is allowed to have subdirectories, but doesn't");
- }
- for (var dep in rule.allowedDependencies
- .toSet()
- .difference(rule.actualDependencies)) {
- problem("$subpackage lists $dep as a dependency, but doesn't use it");
- }
- });
- return problemsReported ? 1 : 0;
- }
-
- /// Determines which subpackage [src] is in.
- ///
- /// If [src] is not part of the front end, `null` is returned.
- String subpackageForUri(Uri src) {
- if (src.scheme != 'package') return null;
- if (src.pathSegments[0] != 'front_end') return null;
- var pathWithLib = 'lib/${src.pathSegments.skip(1).join('/')}';
- String subpackage;
- String pathWithinSubpackage;
- for (var subpackagePath in subpackageRules.keys) {
- var subpackagePathWithSlash = '$subpackagePath/';
- if (pathWithLib.startsWith(subpackagePathWithSlash) &&
- (subpackage == null || subpackage.length < subpackagePath.length)) {
- subpackage = subpackagePath;
- pathWithinSubpackage =
- pathWithLib.substring(subpackagePathWithSlash.length);
- }
- }
- if (subpackage == null) {
- problem('Uri $src is inside package:front_end but is not in any known '
- 'subpackage');
- } else if (pathWithinSubpackage.contains('/')) {
- if (subpackageRules[subpackage].allowSubdirs) {
- subpackageRules[subpackage].actuallyHasSubdirs = true;
- } else {
- problem('Uri $src is in a subfolder of $subpackage, but that '
- 'subpackage does not allow dart files in subdirectories.');
- }
- }
- return subpackage;
- }
-}
diff --git a/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.expect b/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.expect
index 197f600..172bc99 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.expect
@@ -2,13 +2,9 @@
import self as self;
import "dart:core" as core;
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:11: Error: A function expression can't have a return type.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
var x = void f<T>(T t) {};
- ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
- var x = void f<T>(T t) {};
- ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:9: Error: A function expression can't have a return type.
- print(void g<T>(T t) {});
- ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
+ ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
print(void g<T>(T t) {});
^"]/* from null */;
static method main() → dynamic {
diff --git a/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.transformed.expect b/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.transformed.expect
index 197f600..172bc99 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression.dart.direct.transformed.expect
@@ -2,13 +2,9 @@
import self as self;
import "dart:core" as core;
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:11: Error: A function expression can't have a return type.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
var x = void f<T>(T t) {};
- ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
- var x = void f<T>(T t) {};
- ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:9: Error: A function expression can't have a return type.
- print(void g<T>(T t) {});
- ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
+ ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
print(void g<T>(T t) {});
^"]/* from null */;
static method main() → dynamic {
diff --git a/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.expect b/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.expect
index 99ed439..1030838 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.expect
@@ -2,13 +2,9 @@
import self as self;
import "dart:core" as core;
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:11: Error: A function expression can't have a return type.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
var x = void f<T>(T t) {};
- ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
- var x = void f<T>(T t) {};
- ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:9: Error: A function expression can't have a return type.
- print(void g<T>(T t) {});
- ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
+ ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
print(void g<T>(T t) {});
^"]/* from null */;
static method main() → dynamic {
diff --git a/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.transformed.expect b/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.transformed.expect
index 99ed439..1030838 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression.dart.strong.transformed.expect
@@ -2,13 +2,9 @@
import self as self;
import "dart:core" as core;
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:11: Error: A function expression can't have a return type.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
var x = void f<T>(T t) {};
- ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:6:16: Error: A function expression can't have a name.
- var x = void f<T>(T t) {};
- ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:9: Error: A function expression can't have a return type.
- print(void g<T>(T t) {});
- ^^^^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
+ ^", "pkg/front_end/testcases/illegal_named_function_expression.dart:8:14: Error: A function expression can't have a name.
print(void g<T>(T t) {});
^"]/* from null */;
static method main() → dynamic {
diff --git a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.expect b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.expect
index 0bff178..d31deb1 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.expect
@@ -2,9 +2,7 @@
import self as self;
import "dart:core" as core;
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:9: Error: A function expression can't have a return type.
- print(void f() {});
- ^^^^", "pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
print(void f() {});
^"]/* from null */;
static method main() → dynamic {
diff --git a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.transformed.expect b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.transformed.expect
index 0bff178..d31deb1 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.direct.transformed.expect
@@ -2,9 +2,7 @@
import self as self;
import "dart:core" as core;
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:9: Error: A function expression can't have a return type.
- print(void f() {});
- ^^^^", "pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
print(void f() {});
^"]/* from null */;
static method main() → dynamic {
diff --git a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.expect b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.expect
index 9c4d9bd..dcee09d 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.expect
@@ -2,9 +2,7 @@
import self as self;
import "dart:core" as core;
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:9: Error: A function expression can't have a return type.
- print(void f() {});
- ^^^^", "pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
print(void f() {});
^"]/* from null */;
static method main() → dynamic {
diff --git a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.transformed.expect b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.transformed.expect
index 9c4d9bd..dcee09d 100644
--- a/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/illegal_named_function_expression_scope.dart.strong.transformed.expect
@@ -2,9 +2,7 @@
import self as self;
import "dart:core" as core;
-static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:9: Error: A function expression can't have a return type.
- print(void f() {});
- ^^^^", "pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/illegal_named_function_expression_scope.dart:7:14: Error: A function expression can't have a name.
print(void f() {});
^"]/* from null */;
static method main() → dynamic {
diff --git a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect
index bf5d7a9..bece5a7 100644
--- a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.expect
@@ -20,6 +20,7 @@
return new self::Pair::•<self::Pair::U, self::Pair::T>(this.{self::Pair::u}, this.{self::Pair::t});
}
static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart:22:110: Error: Can't use a super-bounded type for instance creation. Got 'test::Pair<test::Clonable<dynamic>, test::Clonable<dynamic>>'.
+Specify a regular-bounded type instead of the super-bounded type. Note that the latter may be due to type inference.
new /*error:COULD_NOT_INFER,error:COULD_NOT_INFER*/ /*@typeArgs=Clonable<dynamic>, Clonable<dynamic>*/ Pair
^"]/* from null */;
static method main() → dynamic {
diff --git a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect
index bf5d7a9..bece5a7 100644
--- a/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart.strong.transformed.expect
@@ -20,6 +20,7 @@
return new self::Pair::•<self::Pair::U, self::Pair::T>(this.{self::Pair::u}, this.{self::Pair::t});
}
static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/inference/constructors_inference_f_bounded.dart:22:110: Error: Can't use a super-bounded type for instance creation. Got 'test::Pair<test::Clonable<dynamic>, test::Clonable<dynamic>>'.
+Specify a regular-bounded type instead of the super-bounded type. Note that the latter may be due to type inference.
new /*error:COULD_NOT_INFER,error:COULD_NOT_INFER*/ /*@typeArgs=Clonable<dynamic>, Clonable<dynamic>*/ Pair
^"]/* from null */;
static method main() → dynamic {
diff --git a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect
index 893b908..682d590 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.expect
@@ -9,6 +9,7 @@
}
static field self::B<core::Comparable<dynamic>> y = new self::B::•<core::Comparable<dynamic>>();
static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart:11:13: Error: Can't use a super-bounded type for instance creation. Got '#lib1::B<dart.core::Comparable<dynamic>>'.
+Specify a regular-bounded type instead of the super-bounded type. Note that the latter may be due to type inference.
var y = new B();
^"]/* from null */;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect
index 893b908..682d590 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart.strong.transformed.expect
@@ -9,6 +9,7 @@
}
static field self::B<core::Comparable<dynamic>> y = new self::B::•<core::Comparable<dynamic>>();
static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/instantiate_to_bound/inference_super_bounded_rejected.dart:11:13: Error: Can't use a super-bounded type for instance creation. Got '#lib1::B<dart.core::Comparable<dynamic>>'.
+Specify a regular-bounded type instead of the super-bounded type. Note that the latter may be due to type inference.
var y = new B();
^"]/* from null */;
static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/named_function_scope.dart b/pkg/front_end/testcases/named_function_scope.dart
index bb6e8aa..010ffc7 100644
--- a/pkg/front_end/testcases/named_function_scope.dart
+++ b/pkg/front_end/testcases/named_function_scope.dart
@@ -41,7 +41,6 @@
// This causes a scope error as T is already used in the function-type
// scope (the return type).
var x =
- /*@error=ReturnTypeFunctionExpression*/
/*@context=DuplicatedNamePreviouslyUsedCause*/
T
/*@error=NamedFunctionExpression*/
diff --git a/pkg/front_end/testcases/named_function_scope.dart.direct.expect b/pkg/front_end/testcases/named_function_scope.dart.direct.expect
index b5ce346..8392f75 100644
--- a/pkg/front_end/testcases/named_function_scope.dart.direct.expect
+++ b/pkg/front_end/testcases/named_function_scope.dart.direct.expect
@@ -14,11 +14,9 @@
}
static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/named_function_scope.dart:28:48: Error: A function expression can't have a name.
var x = /*@error=NamedFunctionExpression*/ T() {};
- ^", "pkg/front_end/testcases/named_function_scope.dart:46:9: Error: A function expression can't have a return type.
- T
- ^", "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: A function expression can't have a name.
+ ^", "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: A function expression can't have a name.
T() {};
- ^", "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: A function expression can't have a name.
+ ^", "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: A function expression can't have a name.
T< /*@context=DuplicatedNameCause*/ T>() {};
^"]/* from null */;
static method test() → dynamic {
@@ -47,24 +45,24 @@
^" in let final dynamic #t2 = null in null;
}
{
- dynamic x = let final dynamic #t3 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: Can't declare 'T' because it was already used in this scope.
+ dynamic x = let final dynamic #t3 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: Can't declare 'T' because it was already used in this scope.
T() {};
^" in let final () → self::T T = () → self::T {} in T;
}
{
- self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:55:47: Error: Can't declare 'V' because it was already used in this scope.
+ self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:54:47: Error: Can't declare 'V' because it was already used in this scope.
V /*@error=DuplicatedNamePreviouslyUsed*/ V;
^";
}
{
- dynamic x = let final dynamic #t4 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: 'T' is already declared in this scope.
+ dynamic x = let final dynamic #t4 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: 'T' is already declared in this scope.
T< /*@context=DuplicatedNameCause*/ T>() {};
^" in let final <T extends core::Object = dynamic>() → dynamic T = <T extends core::Object = dynamic>() → dynamic {} in T;
}
{
self::T t;
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:68:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:67:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
^";
function T() → self::T {}
@@ -72,7 +70,7 @@
}
{
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:72:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:71:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
^";
function T() → self::T {}
@@ -81,7 +79,7 @@
{
self::T t;
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:77:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:76:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
^";
function T(self::T t) → self::T {}
@@ -89,7 +87,7 @@
}
{
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:81:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:80:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
^";
function T(self::T t) → self::T {}
diff --git a/pkg/front_end/testcases/named_function_scope.dart.direct.transformed.expect b/pkg/front_end/testcases/named_function_scope.dart.direct.transformed.expect
index b5ce346..8392f75 100644
--- a/pkg/front_end/testcases/named_function_scope.dart.direct.transformed.expect
+++ b/pkg/front_end/testcases/named_function_scope.dart.direct.transformed.expect
@@ -14,11 +14,9 @@
}
static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/named_function_scope.dart:28:48: Error: A function expression can't have a name.
var x = /*@error=NamedFunctionExpression*/ T() {};
- ^", "pkg/front_end/testcases/named_function_scope.dart:46:9: Error: A function expression can't have a return type.
- T
- ^", "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: A function expression can't have a name.
+ ^", "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: A function expression can't have a name.
T() {};
- ^", "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: A function expression can't have a name.
+ ^", "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: A function expression can't have a name.
T< /*@context=DuplicatedNameCause*/ T>() {};
^"]/* from null */;
static method test() → dynamic {
@@ -47,24 +45,24 @@
^" in let final dynamic #t2 = null in null;
}
{
- dynamic x = let final dynamic #t3 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: Can't declare 'T' because it was already used in this scope.
+ dynamic x = let final dynamic #t3 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: Can't declare 'T' because it was already used in this scope.
T() {};
^" in let final () → self::T T = () → self::T {} in T;
}
{
- self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:55:47: Error: Can't declare 'V' because it was already used in this scope.
+ self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:54:47: Error: Can't declare 'V' because it was already used in this scope.
V /*@error=DuplicatedNamePreviouslyUsed*/ V;
^";
}
{
- dynamic x = let final dynamic #t4 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: 'T' is already declared in this scope.
+ dynamic x = let final dynamic #t4 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: 'T' is already declared in this scope.
T< /*@context=DuplicatedNameCause*/ T>() {};
^" in let final <T extends core::Object = dynamic>() → dynamic T = <T extends core::Object = dynamic>() → dynamic {} in T;
}
{
self::T t;
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:68:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:67:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
^";
function T() → self::T {}
@@ -72,7 +70,7 @@
}
{
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:72:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:71:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
^";
function T() → self::T {}
@@ -81,7 +79,7 @@
{
self::T t;
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:77:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:76:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
^";
function T(self::T t) → self::T {}
@@ -89,7 +87,7 @@
}
{
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:81:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:80:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
^";
function T(self::T t) → self::T {}
diff --git a/pkg/front_end/testcases/named_function_scope.dart.strong.expect b/pkg/front_end/testcases/named_function_scope.dart.strong.expect
index 3790ec0..f93c202 100644
--- a/pkg/front_end/testcases/named_function_scope.dart.strong.expect
+++ b/pkg/front_end/testcases/named_function_scope.dart.strong.expect
@@ -14,13 +14,11 @@
}
static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/named_function_scope.dart:28:48: Error: A function expression can't have a name.
var x = /*@error=NamedFunctionExpression*/ T() {};
- ^", "pkg/front_end/testcases/named_function_scope.dart:46:9: Error: A function expression can't have a return type.
- T
- ^", "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: A function expression can't have a name.
+ ^", "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: A function expression can't have a name.
T() {};
- ^", "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: A function expression can't have a name.
+ ^", "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: A function expression can't have a name.
T< /*@context=DuplicatedNameCause*/ T>() {};
- ^", "pkg/front_end/testcases/named_function_scope.dart:84:32: Error: 'T' isn't a type.
+ ^", "pkg/front_end/testcases/named_function_scope.dart:83:32: Error: 'T' isn't a type.
void T(/*@error=NotAType*/ T t) {}
^"]/* from null */;
static method test() → dynamic {
@@ -49,24 +47,24 @@
^" in let final dynamic #t2 = null in null;
}
{
- dynamic x = let final dynamic #t3 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: Can't declare 'T' because it was already used in this scope.
+ dynamic x = let final dynamic #t3 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: Can't declare 'T' because it was already used in this scope.
T() {};
^" in let final () → self::T T = () → self::T {} in T;
}
{
- self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:55:47: Error: Can't declare 'V' because it was already used in this scope.
+ self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:54:47: Error: Can't declare 'V' because it was already used in this scope.
V /*@error=DuplicatedNamePreviouslyUsed*/ V;
^" as{TypeError} self::V;
}
{
- dynamic x = let final dynamic #t4 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: 'T' is already declared in this scope.
+ dynamic x = let final dynamic #t4 = let dynamic _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: 'T' is already declared in this scope.
T< /*@context=DuplicatedNameCause*/ T>() {};
^" in let final <T extends core::Object = dynamic>() → dynamic T = <T extends core::Object = dynamic>() → dynamic {} in T;
}
{
self::T t;
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:68:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:67:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
^";
function T() → self::T {}
@@ -74,7 +72,7 @@
}
{
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:72:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:71:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
^";
function T() → self::T {}
@@ -83,7 +81,7 @@
{
self::T t;
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:77:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:76:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
^";
function T(self::T t) → self::T {}
@@ -91,7 +89,7 @@
}
{
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:81:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:80:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
^";
function T(self::T t) → self::T {}
diff --git a/pkg/front_end/testcases/named_function_scope.dart.strong.transformed.expect b/pkg/front_end/testcases/named_function_scope.dart.strong.transformed.expect
index 94ed7c1..051c027 100644
--- a/pkg/front_end/testcases/named_function_scope.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/named_function_scope.dart.strong.transformed.expect
@@ -14,13 +14,11 @@
}
static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/named_function_scope.dart:28:48: Error: A function expression can't have a name.
var x = /*@error=NamedFunctionExpression*/ T() {};
- ^", "pkg/front_end/testcases/named_function_scope.dart:46:9: Error: A function expression can't have a return type.
- T
- ^", "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: A function expression can't have a name.
+ ^", "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: A function expression can't have a name.
T() {};
- ^", "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: A function expression can't have a name.
+ ^", "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: A function expression can't have a name.
T< /*@context=DuplicatedNameCause*/ T>() {};
- ^", "pkg/front_end/testcases/named_function_scope.dart:84:32: Error: 'T' isn't a type.
+ ^", "pkg/front_end/testcases/named_function_scope.dart:83:32: Error: 'T' isn't a type.
void T(/*@error=NotAType*/ T t) {}
^"]/* from null */;
static method test() → dynamic {
@@ -49,24 +47,24 @@
^" in let final<BottomType> #t2 = null in null;
}
{
- dynamic x = let final dynamic #t3 = let<BottomType> _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:49:9: Error: Can't declare 'T' because it was already used in this scope.
+ dynamic x = let final dynamic #t3 = let<BottomType> _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:48:9: Error: Can't declare 'T' because it was already used in this scope.
T() {};
^" in let final () → self::T T = () → self::T {} in T;
}
{
- self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:55:47: Error: Can't declare 'V' because it was already used in this scope.
+ self::V V = invalid-expression "pkg/front_end/testcases/named_function_scope.dart:54:47: Error: Can't declare 'V' because it was already used in this scope.
V /*@error=DuplicatedNamePreviouslyUsed*/ V;
^" as{TypeError} self::V;
}
{
- dynamic x = let final dynamic #t4 = let<BottomType> _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:63:9: Error: 'T' is already declared in this scope.
+ dynamic x = let final dynamic #t4 = let<BottomType> _ = null in invalid-expression "pkg/front_end/testcases/named_function_scope.dart:62:9: Error: 'T' is already declared in this scope.
T< /*@context=DuplicatedNameCause*/ T>() {};
^" in let final <T extends core::Object = dynamic>() → dynamic T = <T extends core::Object = dynamic>() → dynamic {} in T;
}
{
self::T t;
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:68:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:67:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
^";
function T() → self::T {}
@@ -74,7 +72,7 @@
}
{
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:72:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:71:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T() {}
^";
function T() → self::T {}
@@ -83,7 +81,7 @@
{
self::T t;
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:77:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:76:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
^";
function T(self::T t) → self::T {}
@@ -91,7 +89,7 @@
}
{
{
- invalid-expression "pkg/front_end/testcases/named_function_scope.dart:81:47: Error: Can't declare 'T' because it was already used in this scope.
+ invalid-expression "pkg/front_end/testcases/named_function_scope.dart:80:47: Error: Can't declare 'T' because it was already used in this scope.
T /*@error=DuplicatedNamePreviouslyUsed*/ T(T t) {}
^";
function T(self::T t) → self::T {}
diff --git a/pkg/front_end/testcases/regress/issue_31185.dart b/pkg/front_end/testcases/regress/issue_31185.dart
new file mode 100644
index 0000000..568d2af
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_31185.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+int i = 5;
+
+int test1() {
+ return i ++ (i);
+}
+
+int test2() {
+ return (i) ++ (i);
+}
+
+main() {
+ test1();
+ // Don't call test2, as error recovery has put a runtime error in there.
+}
diff --git a/pkg/front_end/testcases/regress/issue_31185.dart.direct.expect b/pkg/front_end/testcases/regress/issue_31185.dart.direct.expect
new file mode 100644
index 0000000..bf6678e
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_31185.dart.direct.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static field core::int i = 5;
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/regress/issue_31185.dart:8:15: Error: Expected ';' before this.
+ return i ++ (i);
+ ^", "pkg/front_end/testcases/regress/issue_31185.dart:12:17: Error: Expected ';' before this.
+ return (i) ++ (i);
+ ^"]/* from null */;
+static method test1() → core::int {
+ return let final dynamic #t1 = self::i in let final dynamic #t2 = self::i = #t1.+(1) in #t1;
+ self::i;
+}
+static method test2() → core::int {
+ return let final dynamic #t3 = self::i in let final dynamic #t4 = #t3 in let final dynamic #t5 = invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
+ return (i) ++ (i);
+ ^" in #t4;
+ self::i;
+}
+static method main() → dynamic {
+ self::test1();
+}
diff --git a/pkg/front_end/testcases/regress/issue_31185.dart.direct.transformed.expect b/pkg/front_end/testcases/regress/issue_31185.dart.direct.transformed.expect
new file mode 100644
index 0000000..bf6678e
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_31185.dart.direct.transformed.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static field core::int i = 5;
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/regress/issue_31185.dart:8:15: Error: Expected ';' before this.
+ return i ++ (i);
+ ^", "pkg/front_end/testcases/regress/issue_31185.dart:12:17: Error: Expected ';' before this.
+ return (i) ++ (i);
+ ^"]/* from null */;
+static method test1() → core::int {
+ return let final dynamic #t1 = self::i in let final dynamic #t2 = self::i = #t1.+(1) in #t1;
+ self::i;
+}
+static method test2() → core::int {
+ return let final dynamic #t3 = self::i in let final dynamic #t4 = #t3 in let final dynamic #t5 = invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
+ return (i) ++ (i);
+ ^" in #t4;
+ self::i;
+}
+static method main() → dynamic {
+ self::test1();
+}
diff --git a/pkg/front_end/testcases/regress/issue_31185.dart.outline.expect b/pkg/front_end/testcases/regress/issue_31185.dart.outline.expect
new file mode 100644
index 0000000..608d890
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_31185.dart.outline.expect
@@ -0,0 +1,11 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static field core::int i;
+static method test1() → core::int
+ ;
+static method test2() → core::int
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/regress/issue_31185.dart.strong.expect b/pkg/front_end/testcases/regress/issue_31185.dart.strong.expect
new file mode 100644
index 0000000..a6e3919
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_31185.dart.strong.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static field core::int i = 5;
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/regress/issue_31185.dart:8:15: Error: Expected ';' before this.
+ return i ++ (i);
+ ^", "pkg/front_end/testcases/regress/issue_31185.dart:12:17: Error: Expected ';' before this.
+ return (i) ++ (i);
+ ^"]/* from null */;
+static method test1() → core::int {
+ return let final core::int #t1 = self::i in let final core::int #t2 = self::i = #t1.{core::num::+}(1) in #t1;
+ self::i;
+}
+static method test2() → core::int {
+ return (let final dynamic #t3 = self::i in let final dynamic #t4 = #t3 in let final dynamic #t5 = invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
+ return (i) ++ (i);
+ ^" in #t4) as{TypeError} core::int;
+ self::i;
+}
+static method main() → dynamic {
+ self::test1();
+}
diff --git a/pkg/front_end/testcases/regress/issue_31185.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_31185.dart.strong.transformed.expect
new file mode 100644
index 0000000..719e1e1
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_31185.dart.strong.transformed.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static field core::int i = 5;
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/regress/issue_31185.dart:8:15: Error: Expected ';' before this.
+ return i ++ (i);
+ ^", "pkg/front_end/testcases/regress/issue_31185.dart:12:17: Error: Expected ';' before this.
+ return (i) ++ (i);
+ ^"]/* from null */;
+static method test1() → core::int {
+ return let final core::int #t1 = self::i in let final core::int #t2 = self::i = #t1.{core::num::+}(1) in #t1;
+ self::i;
+}
+static method test2() → core::int {
+ return (let final core::int #t3 = self::i in let final core::int #t4 = #t3 in let final dynamic #t5 = invalid-expression "pkg/front_end/testcases/regress/issue_31185.dart:12:12: Error: Can't assign to a parenthesized expression.
+ return (i) ++ (i);
+ ^" in #t4) as{TypeError} core::int;
+ self::i;
+}
+static method main() → dynamic {
+ self::test1();
+}
diff --git a/pkg/vm/lib/kernel_front_end.dart b/pkg/vm/lib/kernel_front_end.dart
index 7d3cec8..7e7762f 100644
--- a/pkg/vm/lib/kernel_front_end.dart
+++ b/pkg/vm/lib/kernel_front_end.dart
@@ -159,8 +159,6 @@
final typeEnvironment =
new TypeEnvironment(coreTypes, hierarchy, strongMode: strongMode);
- // NOTE: Currently we keep fields, because there are certain constant
- // fields which the VM accesses (e.g. `_Random._A` needs to be preserved).
// TODO(kustermann): We should use the entrypoints manifest to find out
// which fields need to be preserved and remove the rest.
constants.transformComponent(component, vmConstants,
diff --git a/pkg/vm/lib/transformations/type_flow/entry_points_extra.json b/pkg/vm/lib/transformations/type_flow/entry_points_extra.json
index 0ff8ba4..e739bb9 100644
--- a/pkg/vm/lib/transformations/type_flow/entry_points_extra.json
+++ b/pkg/vm/lib/transformations/type_flow/entry_points_extra.json
@@ -173,12 +173,6 @@
"library": "dart:async",
"class": "_AsyncStarStreamController",
"action": "create-instance"
- },
- {
- "library": "dart:math",
- "class": "_Random",
- "name": "_A",
- "action": "get"
}
]
}
diff --git a/runtime/lib/math_patch.dart b/runtime/lib/math_patch.dart
index 793b10b..8888042 100644
--- a/runtime/lib/math_patch.dart
+++ b/runtime/lib/math_patch.dart
@@ -189,6 +189,7 @@
// The constant A is selected from "Numerical Recipes 3rd Edition" p.348 B1.
// Implements:
+ // const _A = 0xffffda61;
// var state =
// ((_A * (_state[_kSTATE_LO])) + _state[_kSTATE_HI]) & ((1 << 64) - 1);
// _state[_kSTATE_LO] = state & ((1 << 32) - 1);
@@ -233,8 +234,6 @@
static const _POW2_53_D = 1.0 * (1 << 53);
static const _POW2_27_D = 1.0 * (1 << 27);
- static const _A = 0xffffda61;
-
// Use a singleton Random object to get a new seed if no seed was passed.
static var _prng = new _Random._withState(_initialSeed());
diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc
index c7e0628..0a01b69 100644
--- a/runtime/vm/compiler/backend/range_analysis.cc
+++ b/runtime/vm/compiler/backend/range_analysis.cc
@@ -1421,7 +1421,8 @@
// check earlier, or we're compiling precompiled code (no
// optimistic hoisting of checks possible)
const bool try_generalization =
- function.allows_bounds_check_generalization() && !FLAG_precompiled_mode;
+ !function.ProhibitsBoundsCheckGeneralization() &&
+ !FLAG_precompiled_mode;
BoundsCheckGeneralizer generalizer(this, flow_graph_);
diff --git a/runtime/vm/compiler/backend/redundancy_elimination.cc b/runtime/vm/compiler/backend/redundancy_elimination.cc
index 449ace0..faadfa6 100644
--- a/runtime/vm/compiler/backend/redundancy_elimination.cc
+++ b/runtime/vm/compiler/backend/redundancy_elimination.cc
@@ -1331,7 +1331,7 @@
}
void LICM::OptimisticallySpecializeSmiPhis() {
- if (!flow_graph()->function().allows_hoisting_check_class() ||
+ if (flow_graph()->function().ProhibitsHoistingCheckClass() ||
FLAG_precompiled_mode) {
// Do not hoist any: Either deoptimized on a hoisted check,
// or compiling precompiled code where we can't do optimistic
@@ -1355,7 +1355,7 @@
}
void LICM::Optimize() {
- if (!flow_graph()->function().allows_hoisting_check_class()) {
+ if (flow_graph()->function().ProhibitsHoistingCheckClass()) {
// Do not hoist any.
return;
}
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 58bc7fa..ddea9fe 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -4146,6 +4146,13 @@
intptr_t argument_count,
const Instance* receiver,
const TypeArguments* type_args) {
+ // We use a kernel2kernel constant evaluator in Dart 2.0 AOT compilation, so
+ // we should never end up evaluating constants using the VM's constant
+ // evaluator.
+ if (I->strong() && FLAG_precompiled_mode) {
+ UNREACHABLE();
+ }
+
// We do not support generic methods yet.
ASSERT((receiver == NULL) || (type_args == NULL));
intptr_t extra_arguments =
@@ -7412,7 +7419,8 @@
}
ActiveClass* StreamingFlowGraphBuilder::active_class() {
- return &flow_graph_builder_->active_class_;
+ return (flow_graph_builder_ != NULL) ? &flow_graph_builder_->active_class_
+ : NULL;
}
ScopeBuildingResult* StreamingFlowGraphBuilder::scopes() {
@@ -11057,10 +11065,17 @@
return param_descriptor.raw();
}
-RawObject* StreamingFlowGraphBuilder::EvaluateMetadata(intptr_t kernel_offset) {
+RawObject* StreamingFlowGraphBuilder::EvaluateMetadata(
+ intptr_t kernel_offset,
+ const Class& owner_class) {
SetOffset(kernel_offset);
const Tag tag = PeekTag();
+ // Setup active_class in type translator for type finalization.
+ ActiveClass active_class;
+ active_class.klass = &owner_class;
+ type_translator_.set_active_class(&active_class);
+
if (tag == kClass) {
ClassHelper class_helper(this);
class_helper.ReadUntilExcluding(ClassHelper::kAnnotations);
@@ -11087,6 +11102,8 @@
metadata_values.SetAt(i, value);
}
+ type_translator_.set_active_class(NULL);
+
return metadata_values.raw();
}
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index 169f403..ce7dc4d 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -707,6 +707,10 @@
const Type& ReceiverType(const Class& klass);
+ void set_active_class(ActiveClass* active_class) {
+ active_class_ = active_class;
+ }
+
private:
// Can build a malformed type.
void BuildTypeInternal(bool invalid_as_dynamic = false);
@@ -1261,7 +1265,7 @@
Fragment BuildStatementAt(intptr_t kernel_offset);
RawObject* BuildParameterDescriptor(intptr_t kernel_offset);
- RawObject* EvaluateMetadata(intptr_t kernel_offset);
+ RawObject* EvaluateMetadata(intptr_t kernel_offset, const Class& owner_class);
void CollectTokenPositionsFor(
intptr_t script_index,
intptr_t initial_script_index,
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index c8a1f61..34aa36e 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -2776,8 +2776,9 @@
&helper, Script::Handle(Z, metadata_field.Script()), Z,
TypedData::Handle(Z, metadata_field.KernelData()),
metadata_field.KernelDataProgramOffset());
+ const Class& owner_class = Class::Handle(Z, metadata_field.Owner());
return streaming_flow_graph_builder.EvaluateMetadata(
- metadata_field.kernel_offset());
+ metadata_field.kernel_offset(), owner_class);
} else {
Thread* thread = Thread::Current();
Error& error = Error::Handle();
diff --git a/runtime/vm/compiler/intrinsifier.h b/runtime/vm/compiler/intrinsifier.h
index 2dbc111..bf2ec2a 100644
--- a/runtime/vm/compiler/intrinsifier.h
+++ b/runtime/vm/compiler/intrinsifier.h
@@ -36,6 +36,10 @@
static void IntrinsicCallEpilogue(Assembler* assembler);
private:
+ // The "_A" value used in the intrinsification of
+ // `runtime/lib/math_patch.dart:_Random._nextState()`
+ static const int64_t kRandomAValue = 0xffffda61;
+
static bool CanIntrinsify(const Function& function);
#define DECLARE_FUNCTION(class_name, function_name, enum_name, type, fp) \
diff --git a/runtime/vm/compiler/intrinsifier_arm.cc b/runtime/vm/compiler/intrinsifier_arm.cc
index 9b0c63b..201306d 100644
--- a/runtime/vm/compiler/intrinsifier_arm.cc
+++ b/runtime/vm/compiler/intrinsifier_arm.cc
@@ -1520,17 +1520,7 @@
const Field& state_field = Field::ZoneHandle(
random_class.LookupInstanceFieldAllowPrivate(Symbols::_state()));
ASSERT(!state_field.IsNull());
- const Field& random_A_field = Field::ZoneHandle(
- random_class.LookupStaticFieldAllowPrivate(Symbols::_A()));
- ASSERT(!random_A_field.IsNull());
- ASSERT(random_A_field.is_const());
- Instance& a_value = Instance::Handle(random_A_field.StaticValue());
- if (a_value.raw() == Object::sentinel().raw() ||
- a_value.raw() == Object::transition_sentinel().raw()) {
- random_A_field.EvaluateInitializer();
- a_value = random_A_field.StaticValue();
- }
- const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
+ const int64_t a_int_value = Intrinsifier::kRandomAValue;
// 'a_int_value' is a mask.
ASSERT(Utils::IsUint(32, a_int_value));
int32_t a_int32_value = static_cast<int32_t>(a_int_value);
diff --git a/runtime/vm/compiler/intrinsifier_arm64.cc b/runtime/vm/compiler/intrinsifier_arm64.cc
index 4598536..d14b824 100644
--- a/runtime/vm/compiler/intrinsifier_arm64.cc
+++ b/runtime/vm/compiler/intrinsifier_arm64.cc
@@ -1579,17 +1579,7 @@
const Field& state_field = Field::ZoneHandle(
random_class.LookupInstanceFieldAllowPrivate(Symbols::_state()));
ASSERT(!state_field.IsNull());
- const Field& random_A_field = Field::ZoneHandle(
- random_class.LookupStaticFieldAllowPrivate(Symbols::_A()));
- ASSERT(!random_A_field.IsNull());
- ASSERT(random_A_field.is_const());
- Instance& a_value = Instance::Handle(random_A_field.StaticValue());
- if (a_value.raw() == Object::sentinel().raw() ||
- a_value.raw() == Object::transition_sentinel().raw()) {
- random_A_field.EvaluateInitializer();
- a_value = random_A_field.StaticValue();
- }
- const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
+ const int64_t a_int_value = Intrinsifier::kRandomAValue;
// Receiver.
__ ldr(R0, Address(SP, 0 * kWordSize));
diff --git a/runtime/vm/compiler/intrinsifier_ia32.cc b/runtime/vm/compiler/intrinsifier_ia32.cc
index 7727717..2e46b55 100644
--- a/runtime/vm/compiler/intrinsifier_ia32.cc
+++ b/runtime/vm/compiler/intrinsifier_ia32.cc
@@ -1588,20 +1588,11 @@
const Field& state_field = Field::ZoneHandle(
random_class.LookupInstanceFieldAllowPrivate(Symbols::_state()));
ASSERT(!state_field.IsNull());
- const Field& random_A_field = Field::ZoneHandle(
- random_class.LookupStaticFieldAllowPrivate(Symbols::_A()));
- ASSERT(!random_A_field.IsNull());
- ASSERT(random_A_field.is_const());
- Instance& a_value = Instance::Handle(random_A_field.StaticValue());
- if (a_value.raw() == Object::sentinel().raw() ||
- a_value.raw() == Object::transition_sentinel().raw()) {
- random_A_field.EvaluateInitializer();
- a_value = random_A_field.StaticValue();
- }
- const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
+ const int64_t a_int_value = Intrinsifier::kRandomAValue;
// 'a_int_value' is a mask.
ASSERT(Utils::IsUint(32, a_int_value));
int32_t a_int32_value = static_cast<int32_t>(a_int_value);
+
// Receiver.
__ movl(EAX, Address(ESP, +1 * kWordSize));
// Field '_state'.
diff --git a/runtime/vm/compiler/intrinsifier_x64.cc b/runtime/vm/compiler/intrinsifier_x64.cc
index 1e2574c..a3a0c9b 100644
--- a/runtime/vm/compiler/intrinsifier_x64.cc
+++ b/runtime/vm/compiler/intrinsifier_x64.cc
@@ -1496,17 +1496,8 @@
const Field& state_field = Field::ZoneHandle(
random_class.LookupInstanceFieldAllowPrivate(Symbols::_state()));
ASSERT(!state_field.IsNull());
- const Field& random_A_field = Field::ZoneHandle(
- random_class.LookupStaticFieldAllowPrivate(Symbols::_A()));
- ASSERT(!random_A_field.IsNull());
- ASSERT(random_A_field.is_const());
- Instance& a_value = Instance::Handle(random_A_field.StaticValue());
- if (a_value.raw() == Object::sentinel().raw() ||
- a_value.raw() == Object::transition_sentinel().raw()) {
- random_A_field.EvaluateInitializer();
- a_value = random_A_field.StaticValue();
- }
- const int64_t a_int_value = Integer::Cast(a_value).AsInt64Value();
+ const int64_t a_int_value = Intrinsifier::kRandomAValue;
+
// Receiver.
__ movq(RAX, Address(RSP, +1 * kWordSize));
// Field '_state'.
diff --git a/runtime/vm/deferred_objects.cc b/runtime/vm/deferred_objects.cc
index a4e5920..153f2ae 100644
--- a/runtime/vm/deferred_objects.cc
+++ b/runtime/vm/deferred_objects.cc
@@ -139,11 +139,11 @@
} else {
if (deopt_context->HasDeoptFlag(ICData::kHoisted)) {
// Prevent excessive deoptimization.
- function.set_allows_hoisting_check_class(false);
+ function.SetProhibitsHoistingCheckClass(true);
}
if (deopt_context->HasDeoptFlag(ICData::kGeneralized)) {
- function.set_allows_bounds_check_generalization(false);
+ function.SetProhibitsBoundsCheckGeneralization(true);
}
}
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index c50f3ee..de61db2 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -7097,8 +7097,6 @@
result.set_is_optimizable(is_native ? false : true);
result.set_is_background_optimizable(is_native ? false : true);
result.set_is_inlinable(true);
- result.set_allows_hoisting_check_class(true);
- result.set_allows_bounds_check_generalization(true);
result.SetInstructionsSafe(
Code::Handle(StubCode::LazyCompile_entry()->code()));
if (kind == RawFunction::kClosureFunction ||
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index c7749c5..1d8dc12 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2788,28 +2788,37 @@
void set_modifier(RawFunction::AsyncModifier value) const;
+// 'WasCompiled' is true if the function was compiled once in this
+// VM instantiation. It is independent from presence of type feedback
+// (ic_data_array) and code, which may be loaded from a snapshot.
+// 'WasExecuted' is true if the usage counter has ever been positive.
+// 'ProhibitsHoistingCheckClass' is true if this function deoptimized before on
+// a hoisted check class instruction.
+// 'ProhibitsBoundsCheckGeneralization' is true if this function deoptimized
+// before on a generalized bounds check.
+#define STATE_BITS_LIST(V) \
+ V(WasCompiled) \
+ V(WasExecutedBit) \
+ V(ProhibitsHoistingCheckClass) \
+ V(ProhibitsBoundsCheckGeneralization)
+
enum StateBits {
- kWasCompiledPos = 0,
- kWasExecutedPos = 1,
+#define DECLARE_FLAG_POS(Name) k##Name##Pos,
+ STATE_BITS_LIST(DECLARE_FLAG_POS)
+#undef DECLARE_FLAG_POS
};
- class WasCompiledBit : public BitField<uint8_t, bool, kWasCompiledPos, 1> {};
- class WasExecutedBit : public BitField<uint8_t, bool, kWasExecutedPos, 1> {};
+#define DEFINE_FLAG_BIT(Name) \
+ class Name##Bit : public BitField<uint8_t, bool, k##Name##Pos, 1> {};
+ STATE_BITS_LIST(DEFINE_FLAG_BIT)
+#undef DEFINE_FLAG_BIT
- // 'WasCompiled' is true if the function was compiled once in this
- // VM instantiation. It is independent from presence of type feedback
- // (ic_data_array) and code, which may be loaded from a snapshot.
- void SetWasCompiled(bool value) const {
- set_state_bits(WasCompiledBit::update(value, state_bits()));
- }
- bool WasCompiled() const { return WasCompiledBit::decode(state_bits()); }
-
- // 'WasExecuted' is true if the usage counter has ever been positive.
- void SetWasExecuted(bool value) const {
- set_state_bits(WasExecutedBit::update(value, state_bits()));
- }
- bool WasExecuted() const {
- return (usage_counter() > 0) || WasExecutedBit::decode(state_bits());
- }
+#define DEFINE_FLAG_ACCESSORS(Name) \
+ void Set##Name(bool value) const { \
+ set_state_bits(Name##Bit::update(value, state_bits())); \
+ } \
+ bool Name() const { return Name##Bit::decode(state_bits()); }
+ STATE_BITS_LIST(DEFINE_FLAG_ACCESSORS)
+#undef DEFINE_FLAG_ACCESSORS
void SetUsageCounter(intptr_t value) const {
if (usage_counter() > 0) {
@@ -2818,6 +2827,10 @@
set_usage_counter(value);
}
+ bool WasExecuted() const { return (usage_counter() > 0) || WasExecutedBit(); }
+
+ void SetWasExecuted(bool value) const { SetWasExecutedBit(value); }
+
// static: Considered during class-side or top-level resolution rather than
// instance-side resolution.
// const: Valid target of a const constructor call.
@@ -2855,8 +2868,6 @@
V(Native, is_native) \
V(Redirecting, is_redirecting) \
V(External, is_external) \
- V(AllowsHoistingCheckClass, allows_hoisting_check_class) \
- V(AllowsBoundsCheckGeneralization, allows_bounds_check_generalization) \
V(GeneratedBody, is_generated_body) \
V(AlwaysInline, always_inline) \
V(PolymorphicTarget, is_polymorphic_target)
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 43b9a5c..2d62110 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -57,6 +57,13 @@
}
#endif // !PRODUCT
+static RawInstance* AllocateObjectByClassName(const Library& library,
+ const String& class_name) {
+ const Class& cls = Class::Handle(library.LookupClassAllowPrivate(class_name));
+ ASSERT(!cls.IsNull());
+ return Instance::New(cls);
+}
+
RawError* ObjectStore::PreallocateObjects() {
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
@@ -81,17 +88,13 @@
Object& result = Object::Handle();
const Library& library = Library::Handle(Library::CoreLibrary());
- result =
- DartLibraryCalls::InstanceCreate(library, Symbols::StackOverflowError(),
- Symbols::Dot(), Object::empty_array());
+ result = AllocateObjectByClassName(library, Symbols::StackOverflowError());
if (result.IsError()) {
return Error::Cast(result).raw();
}
set_stack_overflow(Instance::Cast(result));
- result =
- DartLibraryCalls::InstanceCreate(library, Symbols::OutOfMemoryError(),
- Symbols::Dot(), Object::empty_array());
+ result = AllocateObjectByClassName(library, Symbols::OutOfMemoryError());
if (result.IsError()) {
return Error::Cast(result).raw();
}
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index fdd9ee4..a68bce5 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -387,7 +387,6 @@
V(ExternalName, "ExternalName") \
V(_Random, "_Random") \
V(_state, "_state") \
- V(_A, "_A") \
V(_stackTrace, "_stackTrace") \
V(_SpecialTypeMirror, "_SpecialTypeMirror") \
V(_LocalClassMirror, "_LocalClassMirror") \
diff --git a/tests/lib_2/html/interactive_media_test.dart b/tests/lib_2/html/interactive_media_test.dart
index 25d43d4..d7060ac 100644
--- a/tests/lib_2/html/interactive_media_test.dart
+++ b/tests/lib_2/html/interactive_media_test.dart
@@ -18,71 +18,86 @@
if (MediaStream.supported) {
test('getUserMedia audio', () async {
- var mediaStream = await window.navigator.getUserMedia(audio: true);
- expect(mediaStream, isNotNull);
- expect(mediaStream is MediaStream, true);
- var devices = window.navigator.mediaDevices;
- var enumDevices = await devices.enumerateDevices();
- expect(enumDevices.length > 1, true);
- for (var device in enumDevices) {
- var goodDevLabel = device.label.endsWith('Built-in Output') ||
- device.label.endsWith('Built-in Microphone');
- expect(goodDevLabel, true);
+ try {
+ var mediaStream = await window.navigator.getUserMedia(audio: true);
+ expect(mediaStream, isNotNull);
+ expect(mediaStream is MediaStream, true);
+ var devices = window.navigator.mediaDevices;
+ var enumDevices = await devices.enumerateDevices();
+ expect(enumDevices.length > 1, true);
+ for (var device in enumDevices) {
+ var goodDevLabel = device.label.endsWith('Built-in Output') ||
+ device.label.endsWith('Built-in Microphone');
+ expect(goodDevLabel, true);
+ }
+ } catch (e) {
+ // Could fail if bot machine doesn't support audio or video.
+ expect(e.name, DomException.NOT_FOUND);
}
});
test('getUserMedia', () {
- return window.navigator.getUserMedia(video: true).then((stream) {
- expect(stream, isNotNull);
+ try {
+ return window.navigator.getUserMedia(video: true).then((stream) {
+ expect(stream, isNotNull);
- var url = Url.createObjectUrlFromStream(stream);
- expect(url, isNotNull);
+ var url = Url.createObjectUrlFromStream(stream);
+ expect(url, isNotNull);
- var video = new VideoElement()..autoplay = true;
+ var video = new VideoElement()..autoplay = true;
- var completer = new Completer();
- video.onError.listen((e) {
- completer.completeError(e);
+ var completer = new Completer();
+ video.onError.listen((e) {
+ completer.completeError(e);
+ });
+ video.onPlaying.first.then((e) {
+ completer.complete(video);
+ });
+
+ document.body.append(video);
+ video.src = url;
+
+ return completer.future;
});
- video.onPlaying.first.then((e) {
- completer.complete(video);
- });
-
- document.body.append(video);
- video.src = url;
-
- return completer.future;
- });
+ } catch (e) {
+ // Could fail if bot machine doesn't support audio or video.
+ expect(e.name, DomException.NOT_FOUND);
+ }
});
test('getUserMediaComplexConstructor', () {
- return window.navigator.getUserMedia(video: {
- 'mandatory': {'minAspectRatio': 1.333, 'maxAspectRatio': 1.334},
- 'optional': [
- {'minFrameRate': 60},
- {'maxWidth': 640}
- ]
- }).then((stream) {
- expect(stream, isNotNull);
+ try {
+ return window.navigator.getUserMedia(video: {
+ 'mandatory': {'minAspectRatio': 1.333, 'maxAspectRatio': 1.334},
+ 'optional': [
+ {'minFrameRate': 60},
+ {'maxWidth': 640}
+ ]
+ }).then((stream) {
+ expect(stream, isNotNull);
- var url = Url.createObjectUrlFromStream(stream);
- expect(url, isNotNull);
+ var url = Url.createObjectUrlFromStream(stream);
+ expect(url, isNotNull);
- var video = new VideoElement()..autoplay = true;
+ var video = new VideoElement()..autoplay = true;
- var completer = new Completer();
- video.onError.listen((e) {
- completer.completeError(e);
+ var completer = new Completer();
+ video.onError.listen((e) {
+ completer.completeError(e);
+ });
+ video.onPlaying.first.then((e) {
+ completer.complete(video);
+ });
+
+ document.body.append(video);
+ video.src = url;
+
+ return completer.future;
});
- video.onPlaying.first.then((e) {
- completer.complete(video);
- });
-
- document.body.append(video);
- video.src = url;
-
- return completer.future;
- });
+ } catch (e) {
+ // Could fail if bot machine doesn't support audio or video.
+ expect(e.name, DomException.NOT_FOUND);
+ }
});
}
}
diff --git a/tests/lib_2/lib_2_dart2js.status b/tests/lib_2/lib_2_dart2js.status
index e49ac50..72d9070 100644
--- a/tests/lib_2/lib_2_dart2js.status
+++ b/tests/lib_2/lib_2_dart2js.status
@@ -468,6 +468,9 @@
[ $compiler == dart2js && $system == linux ]
html/interactive_geolocation_test: Skip # Requires allowing geo location.
+[ $compiler == dart2js && $system != macos && ($runtime != chrome || $runtime != safari) ]
+html/interactive_media_test: RuntimeError # # See NOTE in test on how to run.
+
[ $compiler == dart2js && $system == windows ]
html/xhr_test: RuntimeError
@@ -790,9 +793,6 @@
convert/streamed_conversion_json_utf8_encode_test: SkipSlow # Times out. Issue 22050
convert/streamed_conversion_utf8_decode_test: SkipSlow # Times out. Issue 22050
-[ $compiler == dart2js && ($runtime != chrome || $system != macos) ]
-html/interactive_media_test: RuntimeError # # See NOTE in test on how to run.
-
[ $compiler == dart2js && ($runtime == ff || $runtime == safari || $ie) ]
html/custom/attribute_changed_callback_test/unsupported_on_polyfill: Fail # Polyfill does not support
html/custom/entered_left_view_test/viewless_document: Fail # Polyfill does not handle this
diff --git a/tests/lib_2/lib_2_kernel.status b/tests/lib_2/lib_2_kernel.status
index f015610..14b7bf9 100644
--- a/tests/lib_2/lib_2_kernel.status
+++ b/tests/lib_2/lib_2_kernel.status
@@ -134,7 +134,6 @@
mirrors/library_metadata_test: RuntimeError
mirrors/load_library_test: RuntimeError
mirrors/metadata_allowed_values_test/16: Skip # Flaky, crashes.
-mirrors/metadata_constructed_constant_test: Crash, RuntimeError
mirrors/metadata_scope_test/none: RuntimeError
mirrors/method_mirror_location_test: RuntimeError
mirrors/method_mirror_source_line_ending_test: Crash
@@ -221,13 +220,11 @@
mirrors/instance_members_with_override_test: RuntimeError
mirrors/invoke_closurization2_test: RuntimeError
mirrors/invoke_throws_test: RuntimeError
-mirrors/metadata_const_map_test: Crash
mirrors/mixin_members_test: RuntimeError
mirrors/operator_test: RuntimeError
mirrors/redirecting_factory_different_type_test/02: MissingCompileTimeError
mirrors/redirecting_factory_different_type_test/none: RuntimeError
mirrors/redirecting_factory_reflection_test: RuntimeError
-mirrors/regress_16321_test/none: Crash
mirrors/top_level_accessors_test/01: MissingCompileTimeError
# Enabling of dartk for sim{arm,arm64,dbc64} revealed these test failures, which
diff --git a/tests/lib_2/mirrors/metadata_type_literal_test.dart b/tests/lib_2/mirrors/metadata_type_literal_test.dart
new file mode 100644
index 0000000..a40023a
--- /dev/null
+++ b/tests/lib_2/mirrors/metadata_type_literal_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// 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 'dart:mirrors';
+import 'package:expect/expect.dart';
+
+class Foo {}
+
+class Annotation {
+ final Object bindings;
+ const Annotation(this.bindings);
+}
+
+@Annotation(Foo)
+class Annotated {}
+
+main(List<String> args) {
+ ClassMirror mirror = reflectType(Annotated);
+ Expect.equals("ClassMirror on 'Annotated'", mirror.toString());
+
+ var bindings = mirror.metadata[0].reflectee.bindings;
+ Expect.equals('Foo', bindings.toString());
+}
diff --git a/tools/VERSION b/tools/VERSION
index 717dac6..18e0327 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 0
PATCH 0
-PRERELEASE 57
+PRERELEASE 58
PRERELEASE_PATCH 0