Version 1.9.0-dev.8.3
svn merge -c 43714 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43772 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43809 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43821 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43824 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43827 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43836 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43839 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 43719,43754,43812,43813,43758 https://dart.googlecode.com/svn/branches/bleeding_edge trunk (conflicts resolved by https://codereview.chromium.org/929053005)
git-svn-id: http://dart.googlecode.com/svn/trunk@43844 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index f5430ac..0e50099 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -334,21 +334,6 @@
}
/**
- * Performs all scheduled analysis operations.
- */
- void test_performAllAnalysisOperations() {
- while (true) {
- ServerOperation operation = operationQueue.takeIf((operation) {
- return operation is PerformAnalysisOperation;
- });
- if (operation == null) {
- break;
- }
- operation.perform(this);
- }
- }
-
- /**
* If the given notice applies to a file contained within an analysis root,
* notify interested parties that the file has been (at least partially)
* analyzed.
@@ -474,23 +459,6 @@
return context.getErrors(source);
}
-// TODO(brianwilkerson) Add the following method after 'prioritySources' has
-// been added to InternalAnalysisContext.
-// /**
-// * Return a list containing the full names of all of the sources that are
-// * priority sources.
-// */
-// List<String> getPriorityFiles() {
-// List<String> priorityFiles = new List<String>();
-// folderMap.values.forEach((ContextDirectory directory) {
-// InternalAnalysisContext context = directory.context;
-// context.prioritySources.forEach((Source source) {
-// priorityFiles.add(source.fullName);
-// });
-// });
-// return priorityFiles;
-// }
-
/**
* Returns resolved [AstNode]s at the given [offset] of the given [file].
*
@@ -508,6 +476,23 @@
return nodes;
}
+// TODO(brianwilkerson) Add the following method after 'prioritySources' has
+// been added to InternalAnalysisContext.
+// /**
+// * Return a list containing the full names of all of the sources that are
+// * priority sources.
+// */
+// List<String> getPriorityFiles() {
+// List<String> priorityFiles = new List<String>();
+// folderMap.values.forEach((ContextDirectory directory) {
+// InternalAnalysisContext context = directory.context;
+// context.prioritySources.forEach((Source source) {
+// priorityFiles.add(source.fullName);
+// });
+// });
+// return priorityFiles;
+// }
+
/**
* Returns resolved [CompilationUnit]s of the Dart file with the given [path].
*
@@ -965,6 +950,21 @@
}
/**
+ * Performs all scheduled analysis operations.
+ */
+ void test_performAllAnalysisOperations() {
+ while (true) {
+ ServerOperation operation = operationQueue.takeIf((operation) {
+ return operation is PerformAnalysisOperation;
+ });
+ if (operation == null) {
+ break;
+ }
+ operation.perform(this);
+ }
+ }
+
+ /**
* Implementation for `analysis.updateContent`.
*/
void updateContent(String id, Map<String, dynamic> changes) {
@@ -1165,7 +1165,7 @@
_onContextsChangedController.stream;
@override
- void addContext(Folder folder, UriResolver packageUriResolver) {
+ AnalysisContext addContext(Folder folder, UriResolver packageUriResolver) {
InternalAnalysisContext context =
AnalysisEngine.instance.createAnalysisContext();
context.contentCache = analysisServer._overlayState;
@@ -1175,6 +1175,7 @@
_onContextsChangedController.add(
new ContextsChangedEvent(added: [context]));
analysisServer.schedulePerformAnalysisOperation(context);
+ return context;
}
@override
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index fc42e65..999c975 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -36,6 +36,11 @@
*/
abstract class ContextManager {
/**
+ * The name of the `lib` directory.
+ */
+ static const String LIB_DIR_NAME = 'lib';
+
+ /**
* [_ContextInfo] object for each included directory in the most
* recent successful call to [setRoots].
*/
@@ -85,9 +90,9 @@
}
/**
- * Called when a new context needs to be created.
+ * Create and return a new analysis context.
*/
- void addContext(Folder folder, UriResolver packageUriResolver);
+ AnalysisContext addContext(Folder folder, UriResolver packageUriResolver);
/**
* Called when the set of files associated with a context have changed (or
@@ -282,7 +287,8 @@
/**
* Resursively adds all Dart and HTML files to the [changeSet].
*/
- void _addSourceFiles(ChangeSet changeSet, Folder folder, _ContextInfo info) {
+ void _addSourceFiles(ChangeSet changeSet, Folder folder, _ContextInfo info,
+ bool pubspecExists, bool createPackageUri) {
if (info.excludesResource(folder) || folder.shortName.startsWith('.')) {
return;
}
@@ -297,14 +303,47 @@
if (child is File) {
if (_shouldFileBeAnalyzed(child)) {
Source source = child.createSource();
+ if (createPackageUri) {
+ //
+ // It should be possible to generate the uri by executing:
+ //
+ // Uri uri = info.context.sourceFactory.restoreUri(source);
+ //
+ // but for some reason this doesn't produce the same result as the
+ // code below. This needs to be investigated.
+ // (See https://code.google.com/p/dart/issues/detail?id=22463).
+ //
+ String packagePath = info.folder.path;
+ String packageName =
+ resourceProvider.pathContext.basename(packagePath);
+ String libPath =
+ resourceProvider.pathContext.join(packagePath, LIB_DIR_NAME);
+ String relPath = source.fullName.substring(libPath.length);
+ Uri uri =
+ Uri.parse('${PackageMapUriResolver.PACKAGE_SCHEME}:$packageName$relPath');
+ source = child.createSource(uri);
+ }
changeSet.addedSource(source);
info.sources[path] = source;
}
} else if (child is Folder) {
- if (child.shortName == PACKAGES_NAME) {
+ String shortName = child.shortName;
+ if (shortName == PACKAGES_NAME) {
continue;
}
- _addSourceFiles(changeSet, child, info);
+ if (pubspecExists &&
+ !createPackageUri &&
+ shortName == LIB_DIR_NAME &&
+ child.parent == info.folder) {
+ _addSourceFiles(changeSet, child, info, pubspecExists, true);
+ } else {
+ _addSourceFiles(
+ changeSet,
+ child,
+ info,
+ pubspecExists,
+ createPackageUri);
+ }
}
}
}
@@ -338,15 +377,19 @@
/**
* Create a new empty context associated with [folder].
*/
- _ContextInfo _createContext(Folder folder, List<_ContextInfo> children) {
- _ContextInfo info =
- new _ContextInfo(folder, children, normalizedPackageRoots[folder.path]);
+ _ContextInfo _createContext(Folder folder, File pubspecFile,
+ List<_ContextInfo> children) {
+ _ContextInfo info = new _ContextInfo(
+ folder,
+ pubspecFile,
+ children,
+ normalizedPackageRoots[folder.path]);
_contexts[folder] = info;
info.changeSubscription = folder.changes.listen((WatchEvent event) {
_handleWatchEvent(folder, info, event);
});
UriResolver packageUriResolver = _computePackageUriResolver(folder, info);
- addContext(folder, packageUriResolver);
+ info.context = addContext(folder, packageUriResolver);
return info;
}
@@ -365,13 +408,16 @@
* Returns create pubspec-based contexts.
*/
List<_ContextInfo> _createContexts(Folder folder, bool withPubspecOnly) {
- // check if there is a pubspec in the folder
- {
- File pubspecFile = folder.getChild(PUBSPEC_NAME);
- if (pubspecFile.exists) {
- _ContextInfo info = _createContextWithSources(folder, <_ContextInfo>[]);
- return [info];
- }
+ // check whether there is a pubspec in the folder
+ File pubspecFile = folder.getChild(PUBSPEC_NAME);
+ bool pubspecExists = pubspecFile.exists;
+ if (pubspecExists) {
+ _ContextInfo info = _createContextWithSources(
+ folder,
+ pubspecFile,
+ pubspecExists,
+ <_ContextInfo>[]);
+ return [info];
}
// try to find subfolders with pubspec files
List<_ContextInfo> children = <_ContextInfo>[];
@@ -386,18 +432,21 @@
return children;
}
// OK, create a context without a pubspec
- _createContextWithSources(folder, children);
+ _createContextWithSources(folder, pubspecFile, pubspecExists, children);
return children;
}
/**
- * Create a new context associated with [folder] and fills its with sources.
+ * Create a new context associated with the given [folder]. The [pubspecFile]
+ * is the `pubspec.yaml` file contained in the folder, and [pubspecExists] is
+ * `true` if the file exists. Add any sources that are not included in one of
+ * the [children] to the context.
*/
- _ContextInfo _createContextWithSources(Folder folder,
- List<_ContextInfo> children) {
- _ContextInfo info = _createContext(folder, children);
+ _ContextInfo _createContextWithSources(Folder folder, File pubspecFile,
+ bool pubspecExists, List<_ContextInfo> children) {
+ _ContextInfo info = _createContext(folder, pubspecFile, children);
ChangeSet changeSet = new ChangeSet();
- _addSourceFiles(changeSet, folder, info);
+ _addSourceFiles(changeSet, folder, info, pubspecExists, false);
applyChangesToContext(folder, changeSet);
return info;
}
@@ -416,7 +465,7 @@
*/
void _extractContext(_ContextInfo oldInfo, File pubspecFile) {
Folder newFolder = pubspecFile.parent;
- _ContextInfo newInfo = _createContext(newFolder, []);
+ _ContextInfo newInfo = _createContext(newFolder, pubspecFile, []);
newInfo.parent = oldInfo;
// prepare sources to extract
Map<String, Source> extractedSources = new HashMap<String, Source>();
@@ -629,6 +678,11 @@
StreamSubscription<WatchEvent> changeSubscription;
/**
+ * The analysis context that was created for the [folder].
+ */
+ AnalysisContext context;
+
+ /**
* Map from full path to the [Source] object, for each source that has been
* added to the context.
*/
@@ -640,8 +694,8 @@
*/
Set<String> packageMapDependencies;
- _ContextInfo(this.folder, this.children, this.packageRoot) {
- pubspecPath = folder.getChild(PUBSPEC_NAME).path;
+ _ContextInfo(this.folder, File pubspecFile, this.children, this.packageRoot) {
+ pubspecPath = pubspecFile.path;
for (_ContextInfo child in children) {
child.parent = this;
}
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 6cde096..fd4d116 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -4,6 +4,8 @@
library test.context.directory.manager;
+import 'dart:collection';
+
import 'package:analysis_server/src/context_manager.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
@@ -27,12 +29,44 @@
@reflectiveTest
class ContextManagerTest {
+ /**
+ * The name of the 'bin' directory.
+ */
+ static const String BIN_NAME = 'bin';
+ /**
+ * The name of the 'lib' directory.
+ */
+ static const String LIB_NAME = 'lib';
+ /**
+ * The name of the 'src' directory.
+ */
+ static const String SRC_NAME = 'src';
+
+ /**
+ * The name of the 'test' directory.
+ */
+ static const String TEST_NAME = 'test';
+
TestContextManager manager;
+
MemoryResourceProvider resourceProvider;
+
MockPackageMapProvider packageMapProvider;
String projPath = '/my/proj';
+ String newFile(List<String> pathComponents, [String content = '']) {
+ String filePath = posix.joinAll(pathComponents);
+ resourceProvider.newFile(filePath, content);
+ return filePath;
+ }
+
+ String newFolder(List<String> pathComponents) {
+ String folderPath = posix.joinAll(pathComponents);
+ resourceProvider.newFolder(folderPath);
+ return folderPath;
+ }
+
void setUp() {
resourceProvider = new MemoryResourceProvider();
packageMapProvider = new MockPackageMapProvider();
@@ -174,6 +208,32 @@
expect(manager.currentContextFilePaths[projPath], hasLength(0));
}
+ void test_setRoots_addFolderWithPubspecAndLib() {
+ String binPath = newFolder([projPath, BIN_NAME]);
+ String libPath = newFolder([projPath, LIB_NAME]);
+ String srcPath = newFolder([libPath, SRC_NAME]);
+ String testPath = newFolder([projPath, TEST_NAME]);
+
+ newFile([projPath, PUBSPEC_NAME]);
+ String appPath = newFile([binPath, 'app.dart']);
+ newFile([libPath, 'main.dart']);
+ newFile([srcPath, 'internal.dart']);
+ String testFilePath = newFile([testPath, 'main_test.dart']);
+
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ Set<Source> sources = manager.currentContextSources[projPath];
+
+ expect(manager.currentContextPaths, hasLength(1));
+ expect(manager.currentContextPaths, contains(projPath));
+ expect(sources, hasLength(4));
+ List<String> uris =
+ sources.map((Source source) => source.uri.toString()).toList();
+ expect(uris, contains('file://$appPath'));
+ expect(uris, contains('package:proj/main.dart'));
+ expect(uris, contains('package:proj/src/internal.dart'));
+ expect(uris, contains('file://$testFilePath'));
+ }
+
void test_setRoots_addFolderWithPubspecFolders() {
// prepare paths
String root = '/root';
@@ -792,6 +852,13 @@
Map<String, int>>{};
/**
+ * A map from the paths of contexts to a set of the sources that should be
+ * explicitly analyzed in those contexts.
+ */
+ final Map<String, Set<Source>> currentContextSources = <String,
+ Set<Source>>{};
+
+ /**
* Map from context to package URI resolver.
*/
final Map<String, UriResolver> currentContextPackageUriResolvers = <String,
@@ -807,24 +874,30 @@
Iterable<String> get currentContextPaths => currentContextTimestamps.keys;
@override
- void addContext(Folder folder, UriResolver packageUriResolver) {
+ AnalysisContext addContext(Folder folder, UriResolver packageUriResolver) {
String path = folder.path;
expect(currentContextPaths, isNot(contains(path)));
currentContextTimestamps[path] = now;
currentContextFilePaths[path] = <String, int>{};
+ currentContextSources[path] = new HashSet<Source>();
currentContextPackageUriResolvers[path] = packageUriResolver;
+ return null;
}
@override
void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) {
Map<String, int> filePaths = currentContextFilePaths[contextFolder.path];
+ Set<Source> sources = currentContextSources[contextFolder.path];
+
for (Source source in changeSet.addedSources) {
expect(filePaths, isNot(contains(source.fullName)));
filePaths[source.fullName] = now;
+ sources.add(source);
}
for (Source source in changeSet.removedSources) {
expect(filePaths, contains(source.fullName));
filePaths.remove(source.fullName);
+ sources.remove(source);
}
for (Source source in changeSet.changedSources) {
expect(filePaths, contains(source.fullName));
@@ -847,6 +920,7 @@
expect(currentContextPaths, contains(path));
currentContextTimestamps.remove(path);
currentContextFilePaths.remove(path);
+ currentContextSources.remove(path);
currentContextPackageUriResolvers.remove(path);
}
diff --git a/pkg/analyzer/lib/source/package_map_resolver.dart b/pkg/analyzer/lib/source/package_map_resolver.dart
index badaf3a..37de62a 100644
--- a/pkg/analyzer/lib/source/package_map_resolver.dart
+++ b/pkg/analyzer/lib/source/package_map_resolver.dart
@@ -83,7 +83,7 @@
String pkgFolderPath = pkgFolder.path;
if (sourcePath.startsWith(pkgFolderPath)) {
String relPath = sourcePath.substring(pkgFolderPath.length);
- return new Uri(path: '$PACKAGE_SCHEME:$pkgName$relPath');
+ return Uri.parse('$PACKAGE_SCHEME:$pkgName$relPath');
}
}
}
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index c76cef7..9898b75 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -10343,7 +10343,7 @@
}
if (scriptAttribute != null) {
try {
- Uri uri = new Uri(path: scriptAttribute.text);
+ Uri uri = Uri.parse(scriptAttribute.text);
String fileName = uri.path;
Source librarySource =
_task.context.sourceFactory.resolveUri(_task.source, fileName);
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index a40c7e6..f130d40 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -7913,36 +7913,18 @@
*/
LibraryElement resolveLibrary(Source librarySource, bool fullAnalysis) {
//
- // Create the objects representing the library being resolved and the core
- // library.
+ // Create the object representing the library being resolved and compute
+ // the dependency relationship. Note that all libraries depend implicitly
+ // on core, and we inject an ersatz dependency on async, so once this is
+ // done the core and async library elements will have been created.
//
Library targetLibrary = createLibrary(librarySource);
+ _computeLibraryDependencies(targetLibrary);
_coreLibrary = _libraryMap[_coreLibrarySource];
- if (_coreLibrary == null) {
- // This should only happen if the library being analyzed is the core
- // library.
- _coreLibrary = _createLibraryOrNull(_coreLibrarySource);
- if (_coreLibrary == null) {
- LibraryResolver2.missingCoreLibrary(
- analysisContext,
- _coreLibrarySource);
- }
- }
_asyncLibrary = _libraryMap[_asyncLibrarySource];
- if (_asyncLibrary == null) {
- // This should only happen if the library being analyzed is the async
- // library.
- _asyncLibrary = _createLibraryOrNull(_asyncLibrarySource);
- if (_asyncLibrary == null) {
- LibraryResolver2.missingAsyncLibrary(
- analysisContext,
- _asyncLibrarySource);
- }
- }
//
// Compute the set of libraries that need to be resolved together.
//
- _computeLibraryDependencies(targetLibrary);
_librariesInCycles = _computeLibrariesInCycles(targetLibrary);
//
// Build the element models representing the libraries being resolved.
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 18af984..c1c294b 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -38,6 +38,10 @@
import 'parser_test.dart';
import 'resolver_test.dart';
import 'test_support.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:path/src/context.dart';
main() {
@@ -8474,6 +8478,32 @@
result.fullName,
FileUtilities2.createFile("/does/not/exist.dart").getAbsolutePath());
}
+
+ void test_resolveUri_nonAbsolute_relative_package() {
+ MemoryResourceProvider provider = new MemoryResourceProvider();
+ Context context = provider.pathContext;
+ String packagePath = context.joinAll([context.separator, 'path', 'to', 'package']);
+ String libPath = context.joinAll([packagePath, 'lib']);
+ String dirPath = context.joinAll([libPath, 'dir']);
+ String firstPath = context.joinAll([dirPath, 'first.dart']);
+ String secondPath = context.joinAll([dirPath, 'second.dart']);
+
+ provider.newFolder(packagePath);
+ Folder libFolder = provider.newFolder(libPath);
+ provider.newFolder(dirPath);
+ File firstFile = provider.newFile(firstPath, '');
+ provider.newFile(secondPath, '');
+
+ PackageMapUriResolver resolver = new PackageMapUriResolver(provider, {'package' : [libFolder]});
+ SourceFactory factory = new SourceFactory([resolver]);
+ Source librarySource = firstFile.createSource(Uri.parse('package:package/dir/first.dart'));
+
+ Source result = factory.resolveUri(librarySource, 'second.dart');
+ expect(result, isNotNull);
+ expect(result.fullName, secondPath);
+ expect(result.uri.toString(), 'package:package/dir/second.dart');
+ }
+
void test_restoreUri() {
JavaFile file1 = FileUtilities2.createFile("/some/file1.dart");
JavaFile file2 = FileUtilities2.createFile("/some/file2.dart");
diff --git a/pkg/analyzer/test/source/package_map_resolver_test.dart b/pkg/analyzer/test/source/package_map_resolver_test.dart
index a12e361..0869c56 100644
--- a/pkg/analyzer/test/source/package_map_resolver_test.dart
+++ b/pkg/analyzer/test/source/package_map_resolver_test.dart
@@ -162,13 +162,13 @@
Source source = _createFileSource('/pkgA/lib/libA.dart');
Uri uri = resolver.restoreAbsolute(source);
expect(uri, isNotNull);
- expect(uri.path, 'package:pkgA/libA.dart');
+ expect(uri.toString(), 'package:pkgA/libA.dart');
}
{
Source source = _createFileSource('/pkgB/lib/src/libB.dart');
Uri uri = resolver.restoreAbsolute(source);
expect(uri, isNotNull);
- expect(uri.path, 'package:pkgB/src/libB.dart');
+ expect(uri.toString(), 'package:pkgB/src/libB.dart');
}
{
Source source = _createFileSource('/no/such/file');
diff --git a/pkg/compiler/lib/src/dart_types.dart b/pkg/compiler/lib/src/dart_types.dart
index 713cbc1..fd27d88 100644
--- a/pkg/compiler/lib/src/dart_types.dart
+++ b/pkg/compiler/lib/src/dart_types.dart
@@ -475,7 +475,7 @@
* Returns the type as an instance of class [other], if possible, null
* otherwise.
*/
- DartType asInstanceOf(ClassElement other) {
+ InterfaceType asInstanceOf(ClassElement other) {
other = other.declaration;
if (element == other) return this;
InterfaceType supertype = element.asInstanceOf(other);
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index 656b1af..961ec7b 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -4,13 +4,17 @@
library rewrite_async;
-// TODO(sigurdm): Throws in catch-handlers are handled wrong.
// TODO(sigurdm): Avoid using variables in templates. It could blow up memory
// use.
+// TODO(sigurdm): Move the try/catch expression to a js_helper function.
+// That would also simplify the sync* case, where the error can just be thrown.
import "dart:math" show max;
import 'dart:collection';
+import 'package:_internal/compiler/js_lib/shared/async_await_error_codes.dart'
+ as error_codes;
+
import "js.dart" as js;
import '../util/util.dart';
@@ -37,14 +41,39 @@
Map<js.Node, int> continueLabels = new Map<js.Node, int>();
Map<js.Node, int> breakLabels = new Map<js.Node, int>();
- Map<js.Node, int> finallyLabels = new Map<js.Node, int>();
- int exitLabel;
- // A stack of all enclosing jump targets (including the function for
- // representing the target of a return, and all enclosing try-blocks that have
- // finally part, this way ensuring all the finally blocks between a jump and
- // its target are run before the jump.
- List<js.Node> targetsAndTries = new List<js.Node>();
+ /// The label of a finally part.
+ Map<js.Block, int> finallyLabels = new Map<js.Block, int>();
+
+ /// The label of the catch handler of a [js.Try] or a [js.Fun] or [js.Catch].
+ ///
+ /// These mark the points an error can be consumed.
+ ///
+ /// - The handler of a [js.Fun] is the outermost and will rethrow the error.
+ /// - The handler of a [js.Try] will run the catch handler.
+ /// - The handler of a [js.Catch] is a synthetic handler that ensures the
+ /// right finally blocks are run if an error is thrown inside a
+ /// catch-handler.
+ Map<js.Node, int> handlerLabels = new Map<js.Node, int>();
+
+ int exitLabel;
+ int rethrowLabel;
+
+ /// A stack of all (surrounding) jump targets.
+ ///
+ /// Jump targets are:
+ ///
+ /// * The function, signalling a return or uncaught throw.
+ /// * Loops.
+ /// * LabeledStatements (also used for 'continue' when attached to loops).
+ /// * Try statements, for catch and finally handlers.
+ /// * Catch handlers, when inside a catch-part of a try, the catch-handler is
+ /// used to associate with a synthetic handler that will ensure the right
+ /// finally blocks are visited.
+ ///
+ /// When jumping to a target it is necessary to visit all finallies that
+ /// are on the way to target (i.e. more nested than the jump target).
+ List<js.Node> jumpTargets = new List<js.Node>();
List<int> continueStack = new List<int>();
List<int> breakStack = new List<int>();
@@ -55,8 +84,6 @@
PreTranslationAnalysis analysis;
- List<int> errorHandlerLabels = new List<int>();
-
final Function safeVariableName;
// All the <x>Name variables are names of Javascript variables used in the
@@ -86,13 +113,17 @@
/// }
/// }
///
- /// It is a parameter to the [helperName] function, so that [thenHelper] and
- /// [streamHelper] can call [helperName] with the result of an awaited Future.
+ /// It is a parameter to the [bodyName] function, so that [asyncHelper] and
+ /// [streamHelper] can call [bodyName] with the result of an awaited Future.
String resultName;
+ /// A parameter to the [bodyName] function. Indicating if we are in success
+ /// or error case.
+ String errorCodeName;
+
/// The name of the inner function that is scheduled to do each await/yield,
/// and called to do a new iteration for sync*.
- String helperName;
+ String bodyName;
/// The Completer that will finish an async function.
///
@@ -121,9 +152,16 @@
/// the last.
String nextName;
+ /// The stack of labels of finally blocks to assign to [nextName] if the
+ /// async* [StreamSubscription] was canceled during a yield.
+ String nextWhenCanceledName;
+
/// The current returned value (a finally block may overwrite it).
String returnValueName;
+ /// If we are in the process of handling an error, stores the current error.
+ String currentErrorName;
+
/// The label of the outer loop.
///
/// Used if there are untransformed loops containing break or continues to
@@ -131,7 +169,7 @@
String outerLabelName;
/// If javascript `this` is used, it is accessed via this variable, in the
- /// [helperName] function.
+ /// [bodyName] function.
String selfName;
// These expressions are hooks for communicating with the runtime.
@@ -141,19 +179,21 @@
/// For an await it is called with:
///
/// - The value to await
- /// - The [helperName]
- /// - The [completerName]
- /// - A JavaScript function that is executed if the future completed with
- /// an error. That function is responsible for executing the right error
- /// handler and/or finally blocks).
+ /// - The body function [bodyName]
+ /// - The completer object [completerName]
///
/// For a return it is called with:
///
/// - The value to complete the completer with.
- /// - null
- /// - The [completerName]
- /// - null.
- final js.Expression thenHelper;
+ /// - [error_codes.SUCCESS]
+ /// - The completer object [completerName]
+ ///
+ /// For a throw it is called with:
+ ///
+ /// - The error to complete the completer with.
+ /// - [error_codes.ERROR]
+ /// - The completer object [completerName]
+ final js.Expression asyncHelper;
/// The function called by an async* function to simulate an await, yield or
/// yield*.
@@ -162,11 +202,8 @@
///
/// - The value to await/yieldExpression(value to yield)/
/// yieldStarExpression(stream to yield)
- /// - The [helperName]
- /// - The [controllerName]
- /// - A JavaScript function that is executed if the future completed with
- /// an error. That function is responsible for executing the right error
- /// handler and/or finally blocks).
+ /// - The body function [bodyName]
+ /// - The controller object [controllerName]
///
/// For a return it is called with:
///
@@ -192,7 +229,7 @@
final js.Expression streamOfController;
/// Contructor creating the Iterable for a sync* method. Called with
- /// [helperName].
+ /// [bodyName].
final js.Expression newIterable;
/// A JS Expression that creates a marker showing that iteration is over.
@@ -210,6 +247,9 @@
/// Called with the stream to yield from.
final js.Expression yieldStarExpression;
+ /// Used by sync* functions to throw exeptions.
+ final js.Expression uncaughtErrorExpression;
+
final DiagnosticListener diagnosticListener;
// For error reporting only.
Spannable get spannable {
@@ -235,7 +275,7 @@
AsyncRewriter(this.diagnosticListener,
spannable,
- {this.thenHelper,
+ {this.asyncHelper,
this.streamHelper,
this.streamOfController,
this.newCompleter,
@@ -244,6 +284,7 @@
this.newIterable,
this.yieldExpression,
this.yieldStarExpression,
+ this.uncaughtErrorExpression,
this.safeVariableName})
: _spannable = spannable;
@@ -263,14 +304,17 @@
// To avoid name collisions with existing names, the fresh names are
// generated after the analysis.
resultName = freshName("result");
+ errorCodeName = freshName("errorCode");
completerName = freshName("completer");
controllerName = freshName("controller");
- helperName = freshName("helper");
+ bodyName = freshName("body");
gotoName = freshName("goto");
handlerName = freshName("handler");
errorName = freshName("error");
nextName = freshName("next");
+ nextWhenCanceledName = freshName("nextWhenCanceled");
returnValueName = freshName("returnValue");
+ currentErrorName = freshName("currentError");
outerLabelName = freshName("outer");
selfName = freshName("self");
@@ -278,9 +322,8 @@
}
js.Expression get currentErrorHandler {
- return errorHandlerLabels.isEmpty
- ? new js.LiteralNull()
- : js.number(errorHandlerLabels.last);
+ return js.number(handlerLabels[jumpTargets.lastWhere(
+ (node) => handlerLabels[node] != null)]);
}
int allocateTempVar() {
@@ -542,7 +585,7 @@
/// through all the enclosing finally blocks). The jump to here is made in
/// [visitReturn].
///
- /// Returning from an async method calls the [thenHelper] with the result.
+ /// Returning from an async method calls the [asyncHelper] with the result.
/// (the result might have been stored in [returnValueName] by some finally
/// block).
///
@@ -561,26 +604,40 @@
String returnValue =
analysis.hasExplicitReturns ? returnValueName : "null";
addStatement(js.js.statement(
- "return #thenHelper($returnValue, null, $completerName, null)", {
- "thenHelper": thenHelper
- }));
+ "return #thenHelper($returnValue, #successCode, "
+ "$completerName, null)", {
+ "thenHelper": asyncHelper,
+ "successCode": js.number(error_codes.SUCCESS)}));
break;
case const js.AsyncModifier.syncStar():
addStatement(new js.Return(new js.Call(endOfIteration, [])));
break;
case const js.AsyncModifier.asyncStar():
addStatement(js.js.statement(
- "return #streamHelper(null, null, $controllerName, null)", {
- "streamHelper": streamHelper
- }));
+ "return #streamHelper(null, #successCode, $controllerName)", {
+ "streamHelper": streamHelper,
+ "successCode": js.number(error_codes.SUCCESS)}));
break;
default:
diagnosticListener.internalError(
spannable, "Internal error, unexpected asyncmodifier $async");
}
+ if (isAsync || isAsyncStar) {
+ beginLabel(rethrowLabel);
+ addStatement(js.js.statement(
+ "return #thenHelper($currentErrorName, #errorCode, "
+ "${isAsync ? completerName : controllerName})", {
+ "thenHelper": isAsync ? asyncHelper : streamHelper,
+ "errorCode": js.number(error_codes.ERROR)}));
+ } else {
+ assert(isSyncStar);
+ beginLabel(rethrowLabel);
+ addStatement(new js.Return(new js.Call(uncaughtErrorExpression,
+ [new js.VariableUse(currentErrorName)])));
+ }
}
- /// The initial call to [thenHelper]/[streamHelper].
+ /// The initial call to [asyncHelper]/[streamHelper].
///
/// There is no value to await/yield, so the first argument is `null` and
/// also the errorCallback is `null`.
@@ -590,8 +647,8 @@
js.Statement generateInitializer() {
if (isAsync) {
return js.js.statement(
- "return #thenHelper(null, $helperName, $completerName, null);", {
- "thenHelper": thenHelper
+ "return #asyncHelper(null, $bodyName, $completerName, null);", {
+ "asyncHelper": asyncHelper
});
} else if (isAsyncStar) {
return js.js.statement(
@@ -607,17 +664,17 @@
/// Rewrites an async/sync*/async* function to a normal Javascript function.
///
/// The control flow is flattened by simulating 'goto' using a switch in a
- /// loop and a state variable [gotoName] inside a helper-function that can be
- /// called back by [thenHelper]/[streamHelper]/the [Iterator].
+ /// loop and a state variable [gotoName] inside a nested function [bodyName]
+ /// that can be called back by [asyncHelper]/[asyncStarHelper]/the [Iterator].
///
/// Local variables are hoisted outside the helper.
///
/// Awaits in async/async* are translated to code that remembers the current
/// location (so the function can resume from where it was) followed by a call
- /// to the [thenHelper]. The helper sets up the waiting for the awaited value
+ /// to the [asyncHelper]. The helper sets up the waiting for the awaited value
/// and returns a future which is immediately returned by the translated
/// await.
- /// Yields in async* are translated to a call to the [streamHelper]. They,
+ /// Yields in async* are translated to a call to the [asyncStarHelper]. They,
/// too, need to be prepared to be interrupted in case the stream is paused or
/// canceled. (Currently we always suspend - this is different from the spec,
/// see `streamHelper` in `js_helper.dart`).
@@ -635,7 +692,7 @@
/// return bar(p);
/// }
///
- /// Becomes:
+ /// Becomes (without error handling):
///
/// function(x, y, z) {
/// var goto = 0, returnValue, completer = new Completer(), p;
@@ -644,17 +701,17 @@
/// switch (goto) {
/// case 0:
/// goto = 1 // Remember where to continue when the future succeeds.
- /// return thenHelper(foo(), helper, completer, null);
+ /// return thenHelper(foo(), helper, completer);
/// case 1:
/// p = result;
/// returnValue = bar(p);
/// goto = 2;
/// break;
/// case 2:
- /// return thenHelper(returnValue, null, completer, null)
+ /// return thenHelper(returnValue, null, completer)
/// }
/// }
- /// return thenHelper(null, helper, completer, null);
+ /// return thenHelper(null, helper, completer);
/// }
/// }
///
@@ -689,11 +746,16 @@
/// var goto = 0;
/// var returnValue;
/// var completer = new Completer();
- /// var handler = null;
+ /// var handler = 8; // Outside try-blocks go to the rethrow label.
/// var p;
+ /// var storedError;
/// // The result can be either the result of an awaited future, or an
/// // error if the future completed with an error.
- /// function helper(result) {
+ /// function helper(errorCode, result) {
+ /// if (errorCode == 1) {
+ /// storedError = result;
+ /// goto = handler;
+ /// }
/// while (true) {
/// try {
/// switch (goto) {
@@ -718,7 +780,9 @@
/// goto = 5; // finally handler for outer try.
/// break;
/// case 4: // catch handler for outer try.
- /// e = result;
+ /// handler = 5; // If the handler throws, do the finally ..
+ /// next = [8] // ... and rethrow.
+ /// e = storedError;
/// handle(e);
/// // Fall through to finally.
/// case 5: // finally handler for outer try.
@@ -728,14 +792,16 @@
/// break;
/// case 6: // Exiting outer try.
/// case 7: // return
- /// return thenHelper(returnValue, null, completer, null);
+ /// return thenHelper(returnValue, 0, completer);
+ /// case 8: // Rethrow
+ /// return thenHelper(storedError, 1, completer);
/// }
/// } catch (error) {
- /// result = error;
+ /// storedError = error;
/// goto = handler;
/// }
/// }
- /// return thenHelper(null, helper, completer, null);
+ /// return thenHelper(null, helper, completer);
/// }
/// }
///
@@ -748,10 +814,12 @@
// [visitDartYield].
exitLabel =
analysis.hasExplicitReturns || isAsyncStar ? newLabel("return") : null;
+ rethrowLabel = newLabel("rethrow");
+ handlerLabels[node] = rethrowLabel;
js.Statement body = node.body;
- targetsAndTries.add(node);
+ jumpTargets.add(node);
visitStatement(body);
- targetsAndTries.removeLast();
+ jumpTargets.removeLast();
addExit();
List<js.SwitchClause> clauses = labelledParts.keys.map((label) {
@@ -762,17 +830,13 @@
if (hasJumpThoughOuterLabel) {
helperBody = js.js.statement("$outerLabelName: #", [helperBody]);
}
- if (hasTryBlocks) {
- helperBody = js.js.statement("""
- try {
- #body
- } catch ($errorName){
- if ($handlerName === null)
- throw $errorName;
- $resultName = $errorName;
- $gotoName = $handlerName;
- }""", {"body": helperBody});
- }
+ helperBody = js.js.statement("""
+ try {
+ #body
+ } catch ($errorName){
+ $currentErrorName = $errorName;
+ $gotoName = $handlerName;
+ }""", {"body": helperBody});
List<js.VariableInitialization> inits = <js.VariableInitialization>[];
js.VariableInitialization makeInit(String name, js.Expression initValue) {
@@ -785,17 +849,19 @@
inits.add(makeInit(completerName, new js.New(newCompleter, [])));
} else if (isAsyncStar) {
inits.add(makeInit(controllerName,
- new js.Call(newController, [new js.VariableUse(helperName)])));
+ new js.Call(newController, [new js.VariableUse(bodyName)])));
}
- if (hasTryBlocks) {
- inits.add(makeInit(handlerName, new js.LiteralNull()));
- }
- if (hasJumpThroughFinally) {
+ inits.add(makeInit(handlerName, js.number(rethrowLabel)));
+ inits.add(makeInit(currentErrorName, null));
+ if (hasJumpThroughFinally || analysis.hasYield) {
inits.add(makeInit(nextName, null));
}
if (analysis.hasExplicitReturns && isAsync) {
inits.add(makeInit(returnValueName, null));
}
+ if (isSyncStar) {
+ inits.add(makeInit(resultName, null));
+ }
if (analysis.hasThis && !isSyncStar) {
// Sync* functions must remember `this` on the level of the outer
// function.
@@ -807,6 +873,7 @@
inits.addAll(new Iterable.generate(tempVarHighWaterMark,
(int i) => makeInit(useTempVar(i + 1).name, null)));
js.VariableDeclarationList varDecl = new js.VariableDeclarationList(inits);
+ // TODO(sigurdm): Explain the difference between these cases.
if (isSyncStar) {
return js.js("""
function (#params) {
@@ -814,7 +881,7 @@
var $selfName = this;
return new #newIterable(function () {
#varDecl;
- return function $helperName($resultName) {
+ return function $bodyName() {
while (true)
#helperBody;
};
@@ -831,15 +898,33 @@
return js.js("""
function (#params) {
#varDecl;
- function $helperName($resultName) {
+ function $bodyName($errorCodeName, $resultName) {
+ if (#hasYield)
+ switch ($errorCodeName) {
+ case #streamWasCanceled:
+ $nextName = $nextWhenCanceledName;
+ $gotoName = $nextName.pop();
+ break;
+ case #errorCode:
+ $currentErrorName = $resultName;
+ $gotoName = $handlerName;
+ }
+ else
+ if ($errorCodeName == #errorCode) {
+ $currentErrorName = $resultName;
+ $gotoName = $handlerName;
+ }
while (true)
#helperBody;
}
#init;
}""", {
"params": node.params,
- "helperBody": helperBody,
"varDecl": varDecl,
+ "streamWasCanceled": js.number(error_codes.STREAM_WAS_CANCELED),
+ "errorCode": js.number(error_codes.ERROR),
+ "hasYield": analysis.hasYield,
+ "helperBody": helperBody,
"init": generateInitializer()
});
}
@@ -888,7 +973,7 @@
}
}
- /// An await is translated to a call to [thenHelper]/[streamHelper].
+ /// An await is translated to a call to [asyncHelper]/[streamHelper].
///
/// See the comments of [visitFun] for an example.
@override
@@ -897,23 +982,13 @@
int afterAwait = newLabel("returning from await.");
withExpression(node.expression, (js.Expression value) {
addStatement(setGotoVariable(afterAwait));
- js.Expression errorCallback = errorHandlerLabels.isEmpty
- ? new js.LiteralNull()
- : js.js("""
- function($errorName) {
- $gotoName = #currentHandler;
- $helperName($errorName);
- }""", {"currentHandler": currentErrorHandler});
-
addStatement(js.js.statement("""
- return #thenHelper(#value,
- $helperName,
- ${isAsync ? completerName : controllerName},
- #errorCallback);
+ return #asyncHelper(#value,
+ $bodyName,
+ ${isAsync ? completerName : controllerName});
""", {
- "thenHelper": isAsync ? thenHelper : streamHelper,
+ "asyncHelper": isAsync ? asyncHelper : streamHelper,
"value": value,
- "errorCallback": errorCallback
}));
}, store: false);
beginLabel(afterAwait);
@@ -1073,9 +1148,8 @@
// the jump.
// The bottom of the stack is the label where the jump goes to.
List<int> jumpStack = new List<int>();
- for (js.Node node in targetsAndTries.reversed) {
- if (node is js.Try) {
- assert(node.finallyPart != null);
+ for (js.Node node in jumpTargets.reversed) {
+ if (finallyLabels[node] != null) {
jumpStack.add(finallyLabels[node]);
} else if (node == target) {
jumpStack.add(targetLabel);
@@ -1120,9 +1194,9 @@
beginLabel(startLabel);
- targetsAndTries.add(node);
+ jumpTargets.add(node);
visitStatement(node.body);
- targetsAndTries.removeLast();
+ jumpTargets.removeLast();
beginLabel(continueLabel);
withExpression(node.condition, (js.Expression condition) {
@@ -1191,9 +1265,9 @@
new js.Prefix("!", condition), gotoAndBreak(afterLabel)));
}, store: false);
}
- targetsAndTries.add(node);
+ jumpTargets.add(node);
visitStatement(node.body);
- targetsAndTries.removeLast();
+ jumpTargets.removeLast();
if (node.update != null) {
beginLabel(continueLabel);
visitExpressionIgnoreResult(node.update);
@@ -1294,9 +1368,9 @@
continueLabels[node] = continueLabel;
beginLabel(continueLabel);
- targetsAndTries.add(node);
+ jumpTargets.add(node);
visitStatement(node.body);
- targetsAndTries.removeLast();
+ jumpTargets.removeLast();
beginLabel(breakLabel);
}
@@ -1502,13 +1576,13 @@
}
}
- targetsAndTries.add(node);
+ jumpTargets.add(node);
for (int i = 0; i < labels.length; i++) {
beginLabel(labels[i]);
visitStatement(node.cases[i].body);
}
beginLabel(after);
- targetsAndTries.removeLast();
+ jumpTargets.removeLast();
}
@override
@@ -1523,12 +1597,30 @@
}, store: false);
}
- setErrorHandler() {
+ setErrorHandler([int errorHandler]) {
addExpressionStatement(new js.Assignment(
- new js.VariableUse(handlerName), currentErrorHandler));
+ new js.VariableUse(handlerName),
+ errorHandler == null ? currentErrorHandler : js.number(errorHandler)));
}
- @override
+ List<int> _finalliesUpToAndEnclosingHandler() {
+ List<int> result = new List<int>();
+ for (int i = jumpTargets.length - 1; i >= 0; i--) {
+ js.Node node = jumpTargets[i];
+ int handlerLabel = handlerLabels[node];
+ if (handlerLabel != null) {
+ result.add(handlerLabel);
+ break;
+ }
+ int finallyLabel = finallyLabels[node];
+ if (finallyLabel != null) {
+ result.add(finallyLabel);
+ }
+ }
+ return result.reversed.toList();
+ }
+
+ /// See the comments of [visitFun] for more explanation.
void visitTry(js.Try node) {
if (!shouldTransform(node)) {
js.Block body = translateInBlock(node.body);
@@ -1542,31 +1634,48 @@
addStatement(new js.Try(body, catchPart, finallyPart));
return;
}
+
hasTryBlocks = true;
- int handlerLabel = newLabel("catch");
+ int uncaughtLabel = newLabel("uncaught");
+ int handlerLabel = (node.catchPart == null)
+ ? uncaughtLabel
+ : newLabel("catch");
+
int finallyLabel = newLabel("finally");
int afterFinallyLabel = newLabel("after finally");
- errorHandlerLabels.add(handlerLabel);
+ if (node.finallyPart != null) {
+ finallyLabels[node.finallyPart] = finallyLabel;
+ jumpTargets.add(node.finallyPart);
+ }
+
+ handlerLabels[node] = handlerLabel;
+ jumpTargets.add(node);
+
// Set the error handler here. It must be cleared on every path out;
// normal and error exit.
setErrorHandler();
- if (node.finallyPart != null) {
- finallyLabels[node] = finallyLabel;
- targetsAndTries.add(node);
- }
+
visitStatement(node.body);
- errorHandlerLabels.removeLast();
- addStatement(
- js.js.statement("$nextName = [#];", [js.number(afterFinallyLabel)]));
+
+ js.Node last = jumpTargets.removeLast();
+ assert(last == node);
+
if (node.finallyPart == null) {
setErrorHandler();
addGoto(afterFinallyLabel);
} else {
- // The handler is set as the first thing in the finally block.
+ // The handler is reset as the first thing in the finally block.
+ addStatement(
+ js.js.statement("$nextName = [#];", [js.number(afterFinallyLabel)]));
addGoto(finallyLabel);
}
- beginLabel(handlerLabel);
+
if (node.catchPart != null) {
+ beginLabel(handlerLabel);
+ // [uncaughtLabel] is the handler for the code in the catch-part.
+ // It ensures that [nextName] is set up to run the right finally blocks.
+ handlerLabels[node.catchPart] = uncaughtLabel;
+ jumpTargets.add(node.catchPart);
setErrorHandler();
// The catch declaration name can shadow outer variables, so a fresh name
// is needed to avoid collisions. See Ecma 262, 3rd edition,
@@ -1576,19 +1685,46 @@
variableRenamings
.add(new Pair(node.catchPart.declaration.name, errorRename));
addExpressionStatement(new js.Assignment(
- new js.VariableUse(errorRename), new js.VariableUse(resultName)));
+ new js.VariableUse(errorRename),
+ new js.VariableUse(currentErrorName)));
visitStatement(node.catchPart.body);
variableRenamings.removeLast();
+ if (node.finallyPart != null) {
+ // The error has been caught, so after the finally, continue after the
+ // try.
+ addStatement(js.js.statement("$nextName = [#];",
+ [js.number(afterFinallyLabel)]));
+ addGoto(finallyLabel);
+ } else {
+ addGoto(afterFinallyLabel);
+ }
+ js.Node last = jumpTargets.removeLast();
+ assert(last == node.catchPart);
+ }
+
+ // The "uncaught"-handler tells the finally-block to continue with
+ // the enclosing finally-blocks until the current catch-handler.
+ beginLabel(uncaughtLabel);
+
+ List<int> enclosingFinallies = _finalliesUpToAndEnclosingHandler();
+
+ int nextLabel = enclosingFinallies.removeLast();
+ if (enclosingFinallies.isNotEmpty) {
+ // [enclosingFinallies] can be empty if there is no surrounding finally
+ // blocks. Then [nextLabel] will be [rethrowLabel].
+ addStatement(
+ js.js.statement("$nextName = #;", new js.ArrayInitializer(
+ enclosingFinallies.map(js.number).toList())));
+ }
+ if (node.finallyPart == null) {
+ // The finally-block belonging to [node] will be visited because of
+ // fallthrough. If it does not exist, add an explicit goto.
+ addGoto(nextLabel);
}
if (node.finallyPart != null) {
- targetsAndTries.removeLast();
- setErrorHandler();
- // This belongs to the catch-part, but is only needed if there is a
- // `finally`. Therefore it is in this branch.
- // This is needed even if there is no explicit catch-branch, because
- // if an exception is raised the finally part has to be run.
- addStatement(
- js.js.statement("$nextName = [#];", [js.number(afterFinallyLabel)]));
+ js.Node last = jumpTargets.removeLast();
+ assert(last == node.finallyPart);
+
beginLabel(finallyLabel);
setErrorHandler();
visitStatement(node.finallyPart);
@@ -1658,9 +1794,9 @@
new js.Prefix("!", condition), gotoAndBreak(afterLabel)));
}, store: false);
}
- targetsAndTries.add(node);
+ jumpTargets.add(node);
visitStatement(node.body);
- targetsAndTries.removeLast();
+ jumpTargets.removeLast();
addGoto(continueLabel);
beginLabel(afterLabel);
}
@@ -1683,36 +1819,28 @@
///
/// yield/yield* in an async* function is translated much like the `await` is
/// translated in [visitAwait], only the object is wrapped in a
- /// [yieldExpression]/[yieldStarExpression] to let [streamHelper] distinguish.
- ///
- /// Because there is no Future that can fail (as there is in await) null is
- /// passed as the errorCallback.
+ /// [yieldExpression]/[yieldStarExpression] to let [asyncStarHelper]
+ /// distinguish them.
+ /// Also [nextWhenCanceledName] is set up to contain the finally blocks that
+ /// must be run in case the stream was canceled.
void addAsyncYield(js.DartYield node, js.Expression expression) {
assert(isAsyncStar);
// Find all the finally blocks that should be performed if the stream is
// canceled during the yield.
// At the bottom of the stack is the return label.
List<int> enclosingFinallyLabels = <int>[exitLabel];
- enclosingFinallyLabels.addAll(targetsAndTries
- .where((js.Node node) => node is js.Try)
- .map((js.Try node) => finallyLabels[node]));
- int destinationOnCancel = enclosingFinallyLabels.removeLast();
- js.ArrayInitializer finallyListInitializer = new js.ArrayInitializer(
- enclosingFinallyLabels.map(js.number).toList());
+ enclosingFinallyLabels.addAll(jumpTargets
+ .where((js.Node node) => finallyLabels[node] != null)
+ .map((js.Block node) => finallyLabels[node]));
+ addStatement(js.js.statement("$nextWhenCanceledName = #",
+ [new js.ArrayInitializer(enclosingFinallyLabels.map(js.number)
+ .toList())]));
addStatement(js.js.statement("""
return #streamHelper(#yieldExpression(#expression),
- $helperName, $controllerName, function () {
- if (#notEmptyFinallyList)
- $nextName = #finallyList;
- $gotoName = #destinationOnCancel;
- $helperName();
- });""", {
+ $bodyName, $controllerName);""", {
"streamHelper": streamHelper,
"yieldExpression": node.hasStar ? yieldStarExpression : yieldExpression,
"expression": expression,
- "notEmptyFinallyList": enclosingFinallyLabels.isNotEmpty,
- "finallyList": finallyListInitializer,
- "destinationOnCancel": js.number(destinationOnCancel)
}));
}
@@ -1753,6 +1881,8 @@
bool hasThis = false;
+ bool hasYield = false;
+
// The function currently being analyzed.
js.Fun currentFunction;
@@ -2143,6 +2273,7 @@
@override
bool visitDartYield(js.DartYield node) {
+ hasYield = true;
visit(node.expression);
return true;
}
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index e396899..4f77f85 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -1600,8 +1600,8 @@
return findHelper("throwCyclicInit");
}
- Element getThenHelper() {
- return findHelper("thenHelper");
+ Element getAsyncHelper() {
+ return findHelper("asyncHelper");
}
Element getYieldStar() {
@@ -1616,8 +1616,14 @@
return classElement.lookupLocalMember("yieldSingle");
}
- Element getStreamHelper() {
- return findHelper("streamHelper");
+ Element getSyncStarUncaughtError() {
+ ClassElement classElement = findHelper("IterationMarker");
+ classElement.ensureResolved(compiler);
+ return classElement.lookupLocalMember("uncaughtError");
+ }
+
+ Element getAsyncStarHelper() {
+ return findHelper("asyncStarHelper");
}
Element getStreamOfController() {
@@ -2405,7 +2411,7 @@
Enqueuer enqueuer,
Registry registry) {
if (element.asyncMarker == AsyncMarker.ASYNC) {
- enqueue(enqueuer, getThenHelper(), registry);
+ enqueue(enqueuer, getAsyncHelper(), registry);
enqueue(enqueuer, getCompleterConstructor(), registry);
enqueue(enqueuer, getStreamIteratorConstructor(), registry);
} else if (element.asyncMarker == AsyncMarker.SYNC_STAR) {
@@ -2413,9 +2419,10 @@
enqueue(enqueuer, getSyncStarIterableConstructor(), registry);
enqueue(enqueuer, getEndOfIteration(), registry);
enqueue(enqueuer, getYieldStar(), registry);
+ enqueue(enqueuer, getSyncStarUncaughtError(), registry);
} else if (element.asyncMarker == AsyncMarker.ASYNC_STAR) {
enqueuer.registerInstantiatedClass(getASyncStarController(), registry);
- enqueue(enqueuer, getStreamHelper(), registry);
+ enqueue(enqueuer, getAsyncStarHelper(), registry);
enqueue(enqueuer, getStreamOfController(), registry);
enqueue(enqueuer, getYieldSingle(), registry);
enqueue(enqueuer, getYieldStar(), registry);
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 13350ca..1d4a274 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -25,12 +25,13 @@
JavaScriptBackend backend = builder.backend;
AsyncRewriter rewriter = null;
+
if (element.asyncMarker == AsyncMarker.ASYNC) {
rewriter = new AsyncRewriter(
backend.compiler,
backend.compiler.currentElement,
- thenHelper:
- backend.emitter.staticFunctionAccess(backend.getThenHelper()),
+ asyncHelper:
+ backend.emitter.staticFunctionAccess(backend.getAsyncHelper()),
newCompleter: backend.emitter.staticFunctionAccess(
backend.getCompleterConstructor()),
safeVariableName: backend.namer.safeVariableName);
@@ -44,6 +45,8 @@
backend.getSyncStarIterableConstructor()),
yieldStarExpression: backend.emitter.staticFunctionAccess(
backend.getYieldStar()),
+ uncaughtErrorExpression: backend.emitter.staticFunctionAccess(
+ backend.getSyncStarUncaughtError()),
safeVariableName: backend.namer.safeVariableName);
}
else if (element.asyncMarker == AsyncMarker.ASYNC_STAR) {
@@ -51,7 +54,7 @@
backend.compiler,
backend.compiler.currentElement,
streamHelper: backend.emitter.staticFunctionAccess(
- backend.getStreamHelper()),
+ backend.getAsyncStarHelper()),
streamOfController: backend.emitter.staticFunctionAccess(
backend.getStreamOfController()),
newController: backend.emitter.staticFunctionAccess(
@@ -1058,6 +1061,13 @@
// We build the Ssa graph by simulating a stack machine.
List<HInstruction> stack = <HInstruction>[];
+ /// Returns `true` if the current element is an `async` function.
+ bool get isBuildingAsyncFunction {
+ Element element = sourceElement;
+ return (element is FunctionElement &&
+ element.asyncMarker == AsyncMarker.ASYNC);
+ }
+
SsaBuilder(JavaScriptBackend backend,
CodegenWorkItem work,
this.nativeEmitter,
@@ -5179,6 +5189,28 @@
emitReturn(value, node);
}
+ /// Returns true if the [type] is a valid return type for an asynchronous
+ /// function.
+ ///
+ /// Asynchronous functions return a `Future`, and a valid return is thus
+ /// either dynamic, Object, or Future.
+ ///
+ /// We do not accept the internal Future implementation class.
+ bool isValidAsyncReturnType(DartType type) {
+ assert (isBuildingAsyncFunction);
+ // TODO(sigurdm): In an internal library a function could be declared:
+ //
+ // _FutureImpl foo async => 1;
+ //
+ // This should be valid (because the actual value returned from an async
+ // function is a `_FutureImpl`), but currently false is returned in this
+ // case.
+ return type.isDynamic ||
+ type.isObject ||
+ (type is InterfaceType &&
+ type.element == compiler.futureClass);
+ }
+
visitReturn(ast.Return node) {
if (identical(node.beginToken.stringValue, 'native')) {
native.handleSsaNative(this, node.expression);
@@ -5190,7 +5222,19 @@
} else {
visit(node.expression);
value = pop();
- value = potentiallyCheckOrTrustType(value, returnType);
+ if (isBuildingAsyncFunction) {
+ if (compiler.enableTypeAssertions &&
+ !isValidAsyncReturnType(returnType)) {
+ String message =
+ "Async function returned a Future, "
+ "was declared to return a $returnType.";
+ generateTypeError(node, message);
+ pop();
+ return;
+ }
+ } else {
+ value = potentiallyCheckOrTrustType(value, returnType);
+ }
}
handleInTryStatement();
diff --git a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
index c89a8ce..3d05dc8 100644
--- a/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
+++ b/pkg/compiler/lib/src/ssa/value_range_analyzer.dart
@@ -711,6 +711,12 @@
indexRange = info.newUnboundRange();
assert(!check.index.isInteger(compiler));
}
+ if (lengthRange == null) {
+ // We might have lost the length range due to a type conversion that
+ // asserts a non-integer type. In such a case, the program will never
+ // get to this point anyway, so no need to try and refine ranges.
+ return indexRange;
+ }
assert(check.length.isInteger(compiler));
// Check if the index is strictly below the upper bound of the length
diff --git a/sdk/bin/pub b/sdk/bin/pub
index 8427727..1fd6864 100755
--- a/sdk/bin/pub
+++ b/sdk/bin/pub
@@ -29,10 +29,6 @@
unset VM_OPTIONS
declare -a VM_OPTIONS
-# Give the VM extra memory for dart2js.
-# TODO(rnystrom): Remove when #8355 is fixed.
-VM_OPTIONS+=("--old_gen_heap_size=1024")
-
# Allow extra VM options to be passed in through an environment variable.
if [[ $DART_VM_OPTIONS ]]; then
read -a OPTIONS <<< "$DART_VM_OPTIONS"
diff --git a/sdk/bin/pub.bat b/sdk/bin/pub.bat
index 4b8b85d..98d5420 100644
--- a/sdk/bin/pub.bat
+++ b/sdk/bin/pub.bat
@@ -23,11 +23,6 @@
set VM_OPTIONS=
-rem Give the VM extra memory for dart2js.
-rem # TODO(rnystrom): Remove when #8355 is fixed.
-rem See comments regarding options below in dart2js shell script.
-set VM_OPTIONS=%VM_OPTIONS% --old_gen_heap_size=1024
-
rem Use the Dart binary in the built SDK so pub can find the version file next
rem to it.
set BUILD_DIR=%SDK_DIR%\..\build\ReleaseIA32
diff --git a/sdk/lib/_internal/compiler/js_lib/js_helper.dart b/sdk/lib/_internal/compiler/js_lib/js_helper.dart
index b170538..49107bc 100644
--- a/sdk/lib/_internal/compiler/js_lib/js_helper.dart
+++ b/sdk/lib/_internal/compiler/js_lib/js_helper.dart
@@ -4,6 +4,8 @@
library _js_helper;
+import 'dart:_async_await_error_codes' as async_error_codes;
+
import 'dart:_js_embedded_names' show
GET_TYPE_FROM_NAME,
GET_ISOLATE_TAG,
@@ -26,13 +28,13 @@
leaveJsAsync;
import 'dart:async' show
- Future,
- DeferredLoadException,
- Completer,
- StreamController,
- Stream,
- StreamSubscription,
- scheduleMicrotask;
+ Future,
+ DeferredLoadException,
+ Completer,
+ StreamController,
+ Stream,
+ StreamSubscription,
+ scheduleMicrotask;
import 'dart:_foreign_helper' show
DART_CLOSURE_TO_JS,
@@ -3477,59 +3479,62 @@
///
/// If [object] is not a future it will be wrapped in a `new Future.value`.
///
-/// If [helperCallback] is null it indicates a return from the async function,
-/// and we complete the completer with object.
+/// If [asyncBody] is [async_error_codes.SUCCESS]/[async_error_codes.ERROR] it
+/// indicates a return or throw from the async function, and
+/// complete/completeError is called on [completer] with [object].
///
-/// Otherwise [helperCallback] is set up to be called when the future is
-/// successfull and [errorCallback] if it is completed with an error.
-///
-/// If helperCallback or errorCallback throws we complete the completer with the
-/// error.
+/// Otherwise [asyncBody] is set up to be called when the future is completed
+/// with a code [async_error_codes.SUCCESS]/[async_error_codes.ERROR] depending
+/// on the success of the future.
///
/// Returns the future of the completer for convenience of the first call.
-dynamic thenHelper(dynamic object,
- dynamic /* js function */ helperCallback,
- Completer completer,
- dynamic /* js function */ errorCallback) {
- if (helperCallback == null) {
+dynamic asyncHelper(dynamic object,
+ dynamic /* js function */ bodyFunctionOrErrorCode,
+ Completer completer) {
+ if (identical(bodyFunctionOrErrorCode, async_error_codes.SUCCESS)) {
completer.complete(object);
return;
+ } else if (identical(bodyFunctionOrErrorCode, async_error_codes.ERROR)) {
+ // The error is a js-error.
+ completer.completeError(unwrapException(object),
+ getTraceFromException(object));
+ return;
}
Future future = object is Future ? object : new Future.value(object);
- future.then(_wrapJsFunctionForThenHelper(helperCallback, completer),
- onError: (errorCallback == null)
- ? null
- : _wrapJsFunctionForThenHelper(errorCallback, completer));
+ future.then(_wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+ async_error_codes.SUCCESS),
+ onError: _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+ async_error_codes.ERROR));
return completer.future;
}
-Function _wrapJsFunctionForThenHelper(dynamic /* js function */ function,
- Completer completer) {
+Function _wrapJsFunctionForAsync(dynamic /* js function */ function,
+ int errorCode) {
return (result) {
- try {
- JS('', '#(#)', function, result);
- } catch (e, st) {
- completer.completeError(e, st);
- }
+ JS('', '#(#, #)', function, errorCode, result);
};
}
-
/// Implements the runtime support for async* functions.
///
/// Called by the transformed function for each original return, await, yield,
/// yield* and before starting the function.
///
-/// When the async* function wants to return it calls this function. with
-/// [helperCallback] == null, the streamHelper takes this as signal to close the
-/// stream.
+/// When the async* function wants to return it calls this function with
+/// [asyncBody] == [async_error_codes.SUCCESS], the asyncStarHelper takes this
+/// as signal to close the stream.
///
-/// If the async* function wants to do a yield or yield* it calls this function
-/// with [object] being an [IterationMarker]. In this case [errorCallback] has a
-/// special meaning; it is a callback that will run all enclosing finalizers.
+/// When the async* function wants to signal that an uncaught error was thrown,
+/// it calls this function with [asyncBody] == [async_error_codes.ERROR],
+/// the streamHelper takes this as signal to addError [object] to the
+/// [controller] and close it.
+///
+/// If the async* function wants to do a yield or yield*, it calls this function
+/// with [object] being an [IterationMarker].
///
/// In the case of a yield or yield*, if the stream subscription has been
-/// canceled [errorCallback] is scheduled.
+/// canceled, schedules [asyncBody] to be called with
+/// [async_error_codes.STREAM_WAS_CANCELED].
///
/// If [object] is a single-yield [IterationMarker], adds the value of the
/// [IterationMarker] to the stream. If the stream subscription has been
@@ -3539,30 +3544,32 @@
/// If [object] is a yield-star [IterationMarker], starts listening to the
/// yielded stream, and adds all events and errors to our own controller (taking
/// care if the subscription has been paused or canceled) - when the sub-stream
-/// is done, schedules [helperCallback] again.
+/// is done, schedules [asyncBody] again.
///
/// If the async* function wants to do an await it calls this function with
/// [object] not and [IterationMarker].
///
/// If [object] is not a [Future], it is wrapped in a `Future.value`.
-/// The [helperCallback] is called on successfull completion of the
-/// future.
-///
-/// If [helperCallback] or [errorCallback] throws the error is added to the
-/// stream.
-void streamHelper(dynamic object,
- dynamic /* js function */ helperCallback,
- AsyncStarStreamController controller,
- dynamic /* js function */ errorCallback) {
- if (helperCallback == null) {
+/// The [asyncBody] is called on completion of the future (see [asyncHelper].
+void asyncStarHelper(dynamic object,
+ dynamic /* int | js function */ bodyFunctionOrErrorCode,
+ AsyncStarStreamController controller) {
+ if (identical(bodyFunctionOrErrorCode, async_error_codes.SUCCESS)) {
// This happens on return from the async* function.
controller.close();
return;
+ } else if (identical(bodyFunctionOrErrorCode, async_error_codes.ERROR)) {
+ // The error is a js-error.
+ controller.addError(unwrapException(object),
+ getTraceFromException(object));
+ controller.close();
+ return;
}
if (object is IterationMarker) {
if (controller.stopRunning) {
- _wrapJsFunctionForStream(errorCallback, controller)();
+ _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+ async_error_codes.STREAM_WAS_CANCELED)(null);
return;
}
if (object.state == IterationMarker.YIELD_SINGLE) {
@@ -3573,7 +3580,9 @@
}
// TODO(sigurdm): We should not suspend here according to the spec.
scheduleMicrotask(() {
- _wrapJsFunctionForStream(helperCallback, controller)(null);
+ _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+ async_error_codes.SUCCESS)
+ (null);
});
return;
} else if (object.state == IterationMarker.YIELD_STAR) {
@@ -3584,17 +3593,18 @@
// TODO(sigurdm): The spec is not very clear here. Clarify with Gilad.
controller.addStream(stream).then((_) {
controller.isAdding = false;
- _wrapJsFunctionForStream(helperCallback, controller)(null);
+ _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+ async_error_codes.SUCCESS)(null);
});
return;
}
}
Future future = object is Future ? object : new Future.value(object);
- future.then(_wrapJsFunctionForStream(helperCallback, controller),
- onError: errorCallback == null
- ? null
- : _wrapJsFunctionForStream(errorCallback, controller));
+ future.then(_wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+ async_error_codes.SUCCESS),
+ onError: _wrapJsFunctionForAsync(bodyFunctionOrErrorCode,
+ async_error_codes.ERROR));
}
Stream streamOfController(AsyncStarStreamController controller) {
@@ -3622,11 +3632,13 @@
AsyncStarStreamController(helperCallback) {
controller = new StreamController(
onListen: () {
- scheduleMicrotask(() => JS('', '#(null)', helperCallback));
+ scheduleMicrotask(() {
+ JS('', '#(#, null)', helperCallback, async_error_codes.SUCCESS);
+ });
},
onResume: () {
if (!isAdding) {
- streamHelper(null, helperCallback, this, null);
+ asyncStarHelper(null, helperCallback, this);
}
}, onCancel: () {
stopRunning = true;
@@ -3638,22 +3650,11 @@
return new AsyncStarStreamController(helperCallback);
}
-Function _wrapJsFunctionForStream(dynamic /* js function */ function,
- AsyncStarStreamController controller) {
- return (result) {
- try {
- JS('', '#(#)', function, result);
- } catch (e, st) {
- controller.addError(e, st);
- }
- };
-}
-
-
class IterationMarker {
static const YIELD_SINGLE = 0;
static const YIELD_STAR = 1;
static const ITERATION_ENDED = 2;
+ static const UNCAUGHT_ERROR = 3;
final value;
final int state;
@@ -3672,11 +3673,15 @@
return new IterationMarker._(YIELD_SINGLE, value);
}
+ static uncaughtError(dynamic error) {
+ return new IterationMarker._(UNCAUGHT_ERROR, error);
+ }
+
toString() => "IterationMarker($state, $value)";
}
class SyncStarIterator implements Iterator {
- final Function _helper;
+ final Function _body;
// If [runningNested] this is the nested iterator, otherwise it is the
// current value.
@@ -3685,8 +3690,8 @@
get current => _runningNested ? _current.current : _current;
- SyncStarIterator(helper)
- : _helper = ((arg) => JS('', '#(#)', helper, arg));
+ SyncStarIterator(body)
+ : _body = (() => JS('', '#()', body));
bool moveNext() {
if (_runningNested) {
@@ -3696,12 +3701,16 @@
_runningNested = false;
}
}
- _current = _helper(null);
+ _current = _body();
if (_current is IterationMarker) {
if (_current.state == IterationMarker.ITERATION_ENDED) {
_current = null;
- // Rely on [_helper] to repeatedly return `ITERATION_ENDED`.
+ // Rely on [_body] to repeatedly return `ITERATION_ENDED`.
return false;
+ } else if (_current.state == IterationMarker.UNCAUGHT_ERROR) {
+ // Rely on [_body] to repeatedly return `UNCAUGHT_ERROR`.
+ // This is a wrapped exception, so we use JavaScript throw to throw it.
+ JS('', 'throw #', _current.value);
} else {
assert(_current.state == IterationMarker.YIELD_STAR);
_current = _current.value.iterator;
@@ -3720,7 +3729,7 @@
// This is a function that will return a helper function that does the
// iteration of the sync*.
//
- // Each invocation should give a helper with fresh state.
+ // Each invocation should give a body with fresh state.
final dynamic /* js function */ _outerHelper;
SyncStarIterable(this._outerHelper);
diff --git a/sdk/lib/_internal/compiler/js_lib/shared/async_await_error_codes.dart b/sdk/lib/_internal/compiler/js_lib/shared/async_await_error_codes.dart
new file mode 100644
index 0000000..f87406b
--- /dev/null
+++ b/sdk/lib/_internal/compiler/js_lib/shared/async_await_error_codes.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2015, 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.
+
+/// Contains error codes that transformed async/async* functions use to
+/// communicate with js_helper functions.
+
+const int SUCCESS = 0;
+const int ERROR = 1;
+const int STREAM_WAS_CANCELED = 2;
diff --git a/sdk/lib/_internal/libraries.dart b/sdk/lib/_internal/libraries.dart
index 7594c93..938c389 100644
--- a/sdk/lib/_internal/libraries.dart
+++ b/sdk/lib/_internal/libraries.dart
@@ -211,6 +211,12 @@
documented: false,
platforms: DART2JS_PLATFORM),
+ "_async_await_error_codes": const LibraryInfo(
+ "_internal/compiler/js_lib/shared/async_await_error_codes.dart",
+ category: "Internal",
+ documented: false,
+ platforms: DART2JS_PLATFORM),
+
"_metadata": const LibraryInfo(
"html/html_common/metadata.dart",
category: "Internal",
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index 8a493a2..ce7fa1b 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -34,16 +34,11 @@
/// Type of lock when requesting a lock on a file.
-class FileLock {
- final int _lock;
-
+enum FileLock {
/// Shared file lock.
- static const SHARED = const FileLock._internal(0);
-
+ SHARED,
/// Exclusive file lock.
- static const EXCLUSIVE = const FileLock._internal(1);
-
- const FileLock._internal(this._lock);
+ EXCLUSIVE
}
/**
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index d00f629..101a2d6 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -222,9 +222,8 @@
*
* If an IP version 6 (IPv6) address is used, both IP version 6
* (IPv6) and version 4 (IPv4) connections will be accepted. To
- * restrict this to version 6 (IPv6) only, use [HttpServer.listenOn]
- * with a [ServerSocket] configured for IP version 6 connections
- * only.
+ * restrict this to version 6 (IPv6) only, use [v6Only] to set
+ * version 6 only.
*
* If [port] has the value [:0:] an ephemeral port will be chosen by
* the system. The actual port used can be retrieved using the
@@ -234,11 +233,21 @@
* backlog for the underlying OS listen setup. If [backlog] has the
* value of [:0:] (the default) a reasonable value will be chosen by
* the system.
+ *
+ * The optional argument [shared] specify whether additional binds
+ * to the same `address`, `port` and `v6Only` combination is
+ * possible from the same Dart process. If `shared` is `true` and
+ * additional binds are performed, then the incoming connections
+ * will be distributed between that set of `HttpServer`s. One way of
+ * using this is to have number of isolates between which incoming
+ * connections are distributed.
*/
static Future<HttpServer> bind(address,
int port,
- {int backlog: 0})
- => _HttpServer.bind(address, port, backlog);
+ {int backlog: 0,
+ bool v6Only: false,
+ bool shared: false})
+ => _HttpServer.bind(address, port, backlog, v6Only, shared);
/**
* The [address] can either be a [String] or an
@@ -254,9 +263,8 @@
*
* If an IP version 6 (IPv6) address is used, both IP version 6
* (IPv6) and version 4 (IPv4) connections will be accepted. To
- * restrict this to version 6 (IPv6) only, use [HttpServer.listenOn]
- * with a [ServerSocket] configured for IP version 6 connections
- * only.
+ * restrict this to version 6 (IPv6) only, use [v6Only] to set
+ * version 6 only.
*
* If [port] has the value [:0:] an ephemeral port will be chosen by
* the system. The actual port used can be retrieved using the
@@ -271,18 +279,30 @@
* is looked up in the certificate database, and is used as the server
* certificate. If [requestClientCertificate] is true, the server will
* request clients to authenticate with a client certificate.
+ *
+ * The optional argument [shared] specify whether additional binds
+ * to the same `address`, `port` and `v6Only` combination is
+ * possible from the same Dart process. If `shared` is `true` and
+ * additional binds are performed, then the incoming connections
+ * will be distributed between that set of `HttpServer`s. One way of
+ * using this is to have number of isolates between which incoming
+ * connections are distributed.
*/
static Future<HttpServer> bindSecure(address,
int port,
{int backlog: 0,
+ bool v6Only: false,
String certificateName,
- bool requestClientCertificate: false})
+ bool requestClientCertificate: false,
+ bool shared: false})
=> _HttpServer.bindSecure(address,
port,
backlog,
+ v6Only,
certificateName,
- requestClientCertificate);
+ requestClientCertificate,
+ shared);
/**
* Attaches the HTTP server to an existing [ServerSocket]. When the
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index 846cd6b..dd03aeb 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -2160,26 +2160,33 @@
Duration _idleTimeout;
Timer _idleTimer;
- static Future<HttpServer> bind(address, int port, int backlog) {
- return ServerSocket.bind(address, port, backlog: backlog).then((socket) {
- return new _HttpServer._(socket, true);
- });
+ static Future<HttpServer> bind(
+ address, int port, int backlog, bool v6Only, bool shared) {
+ return ServerSocket.bind(
+ address, port, backlog: backlog, v6Only: v6Only, shared: shared)
+ .then((socket) {
+ return new _HttpServer._(socket, true);
+ });
}
static Future<HttpServer> bindSecure(address,
int port,
int backlog,
+ bool v6Only,
String certificate_name,
- bool requestClientCertificate) {
+ bool requestClientCertificate,
+ bool shared) {
return SecureServerSocket.bind(
address,
port,
certificate_name,
backlog: backlog,
- requestClientCertificate: requestClientCertificate)
- .then((socket) {
- return new _HttpServer._(socket, true);
- });
+ v6Only: v6Only,
+ requestClientCertificate: requestClientCertificate,
+ shared: shared)
+ .then((socket) {
+ return new _HttpServer._(socket, true);
+ });
}
_HttpServer._(this._serverSocket, this._closeServer) {
diff --git a/sdk/lib/io/secure_server_socket.dart b/sdk/lib/io/secure_server_socket.dart
index 2a73418..c987a48 100644
--- a/sdk/lib/io/secure_server_socket.dart
+++ b/sdk/lib/io/secure_server_socket.dart
@@ -58,6 +58,14 @@
* To check whether a client certificate was received, check
* SecureSocket.peerCertificate after connecting. If no certificate
* was received, the result will be null.
+ *
+ * The optional argument [shared] specify whether additional binds
+ * to the same `address`, `port` and `v6Only` combination is
+ * possible from the same Dart process. If `shared` is `true` and
+ * additional binds are performed, then the incoming connections
+ * will be distributed between that set of
+ * `SecureServerSocket`s. One way of using this is to have number of
+ * isolates between which incoming connections are distributed.
*/
static Future<SecureServerSocket> bind(
address,
@@ -185,6 +193,14 @@
* need to specify both. To check whether a client certificate was received,
* check SecureSocket.peerCertificate after connecting. If no certificate
* was received, the result will be null.
+ *
+ * The optional argument [shared] specify whether additional binds
+ * to the same `address`, `port` and `v6Only` combination is
+ * possible from the same Dart process. If `shared` is `true` and
+ * additional binds are performed, then the incoming connections
+ * will be distributed between that set of
+ * `RawSecureServerSocket`s. One way of using this is to have number
+ * of isolates between which incoming connections are distributed.
*/
static Future<RawSecureServerSocket> bind(
address,
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index 08f973e..d703c8d 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.dart
@@ -223,6 +223,14 @@
* backlog for the underlying OS listen setup. If [backlog] has the
* value of [:0:] (the default) a reasonable value will be chosen by
* the system.
+ *
+ * The optional argument [shared] specify whether additional binds
+ * to the same `address`, `port` and `v6Only` combination is
+ * possible from the same Dart process. If `shared` is `true` and
+ * additional binds are performed, then the incoming connections
+ * will be distributed between that set of `RawServerSocket`s. One
+ * way of using this is to have number of isolates between which
+ * incoming connections are distributed.
*/
external static Future<RawServerSocket> bind(address,
int port,
@@ -249,8 +257,9 @@
/**
* Get the [RawServerSocketReference].
*
- * WARNING: This feature is *highly experimental* and currently only works on
- * Linux. The API is most likely going to change in the near future.
+ * WARNING: This feature is *highly experimental* and currently only
+ * works on Linux. The API will be removed in Dart 1.10. Use the
+ * `shared` optional argument on the `bind` method instead.
*
* The returned [RawServerSocketReference] can be used to create other
* [RawServerSocket]s listening on the same port,
@@ -260,6 +269,9 @@
* The [RawServerSocketReference] can be distributed to other isolates through
* a [RawSendPort].
*/
+
+ @Deprecated('This will be removed in Dart 1.10. Use the '
+ '`shared` optional argument on the `bind` method instead.')
RawServerSocketReference get reference;
}
@@ -270,6 +282,7 @@
* WARNING: This class is used with [RawServerSocket.reference] which is highly
* experimental.
*/
+@Deprecated('This will be removed in Dart 1.10.')
abstract class RawServerSocketReference {
/**
* Create a new [RawServerSocket], from this reference.
@@ -315,6 +328,14 @@
* backlog for the underlying OS listen setup. If [backlog] has the
* value of [:0:] (the default) a reasonable value will be chosen by
* the system.
+ *
+ * The optional argument [shared] specify whether additional binds
+ * to the same `address`, `port` and `v6Only` combination is
+ * possible from the same Dart process. If `shared` is `true` and
+ * additional binds are performed, then the incoming connections
+ * will be distributed between that set of `ServerSocket`s. One way
+ * of using this is to have number of isolates between which
+ * incoming connections are distributed.
*/
external static Future<ServerSocket> bind(address,
int port,
@@ -341,8 +362,9 @@
/**
* Get the [ServerSocketReference].
*
- * WARNING: This feature is *highly experimental* and currently only works on
- * Linux. The API is most likely going to change in the near future.
+ * WARNING: This feature is *highly experimental* and currently only
+ * works on Linux. The API will be removed in Dart 1.10. Use the
+ * `shared` optional argument on the `bind` method instead.
*
* The returned [ServerSocketReference] can be used to create other
* [ServerSocket]s listening on the same port,
@@ -352,6 +374,8 @@
* The [ServerSocketReference] can be distributed to other isolates through a
* [SendPort].
*/
+ @Deprecated('This will be removed in Dart 1.10. Use the '
+ '`shared` optional argument on the `bind` method instead.')
ServerSocketReference get reference;
}
@@ -362,6 +386,7 @@
* WARNING: This class is used with [ServerSocket.reference] which is highly
* experimental.
*/
+@Deprecated('This will be removed in Dart 1.10.')
abstract class ServerSocketReference {
/**
* Create a new [ServerSocket], from this reference.
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index a9a64c2..49362dc 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -257,15 +257,6 @@
Language/15_Types/1_Static_Types_A03_t01: RuntimeError # Issue 21089
Language/15_Types/2_Dynamic_Type_System_A01_t02: RuntimeError # Issue 21088
Language/15_Types/8_Parameterized_Types_A03_t07: RuntimeError # Issue 21088
-LayoutTests/fast/url/file-http-base_t01: Crash # Issue 21166
-LayoutTests/fast/url/file_t01: Crash # Issue 21166
-LayoutTests/fast/url/relative-unix_t01: Crash # Issue 21166
-LayoutTests/fast/url/relative-win_t01: Crash # Issue 21166
-LayoutTests/fast/url/relative_t01: Crash # Issue 21166
-LayoutTests/fast/url/segments-from-data-url_t01: Crash # Issue 21166
-LayoutTests/fast/url/segments_t01: Crash # Issue 21166
-LayoutTests/fast/url/trivial-segments_t01: Crash # Issue 21166
-LayoutTests/fast/url/trivial_t01: Crash # Issue 21166
LibTest/core/Map/Map_class_A01_t04: Slow, Pass
LibTest/core/Uri/Uri_A06_t03: Slow, Pass
LibTest/math/Point/operator_mult_A02_t01: RuntimeError # Issue 1533
diff --git a/tests/compiler/dart2js/async_await_js_transform_test.dart b/tests/compiler/dart2js/async_await_js_transform_test.dart
index 1006186..98bcbe3 100644
--- a/tests/compiler/dart2js/async_await_js_transform_test.dart
+++ b/tests/compiler/dart2js/async_await_js_transform_test.dart
@@ -13,14 +13,15 @@
Fun rewritten = new AsyncRewriter(
null, // The diagnostic helper should not be used in these tests.
null,
- thenHelper: new VariableUse("thenHelper"),
+ asyncHelper: new VariableUse("thenHelper"),
newCompleter: new VariableUse("Completer"),
endOfIteration: new VariableUse("endOfIteration"),
newIterable: new VariableUse("Iterator"),
safeVariableName: (String name) => "__$name").rewrite(fun);
-
+
JavaScriptPrintingOptions options = new JavaScriptPrintingOptions();
- JavaScriptPrintingContext context = new SimpleJavaScriptPrintingContext();
+ SimpleJavaScriptPrintingContext context =
+ new SimpleJavaScriptPrintingContext();
Printer printer = new Printer(options, context);
printer.visit(rewritten);
Expect.stringEquals(expected, context.getText());
@@ -28,31 +29,44 @@
main() {
testTransform("""
-function() async {
+function(a) async {
print(this.x); // Ensure `this` is translated in the helper function.
await foo();
}""", """
-function() {
- var __goto = 0, __completer = new Completer(), __self = this;
- function __helper(__result) {
+function(a) {
+ var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, __self = this;
+ function __body(__errorCode, __result) {
+ if (__errorCode == 1) {
+ __currentError = __result;
+ __goto = __handler;
+ }
while (true)
- switch (__goto) {
- case 0:
- // Function start
- print(__self.x);
- __goto = 1;
- return thenHelper(foo(), __helper, __completer, null);
- case 1:
- // returning from await.
- // implicit return
- return thenHelper(null, null, __completer, null);
+ try {
+ switch (__goto) {
+ case 0:
+ // Function start
+ print(__self.x);
+ __goto = 2;
+ return thenHelper(foo(), __body, __completer);
+ case 2:
+ // returning from await.
+ // implicit return
+ return thenHelper(null, 0, __completer, null);
+ case 1:
+ // rethrow
+ return thenHelper(__currentError, 1, __completer);
+ }
+ } catch (__error) {
+ __currentError = __error;
+ __goto = __handler;
}
+
}
- return thenHelper(null, __helper, __completer, null);
+ return thenHelper(null, __body, __completer, null);
}""");
testTransform("""
-function() async {
+function(b) async {
try {
__outer: while (true) { // Overlapping label name.
try {
@@ -75,87 +89,86 @@
}
return 4;
}""", """
-function() {
- var __goto = 0, __completer = new Completer(), __handler = null, __next, __returnValue, __helper;
- function __helper1(__result) {
+function(b) {
+ var __goto = 0, __completer = new Completer(), __handler = 2, __currentError, __next, __returnValue, __helper;
+ function __body(__errorCode, __result) {
+ if (__errorCode == 1) {
+ __currentError = __result;
+ __goto = __handler;
+ }
while (true)
try {
__outer1:
switch (__goto) {
case 0:
// Function start
- __handler = 2;
- case 6:
- // continue __outer
+ __handler = 3;
case 7:
+ // continue __outer
+ case 8:
// while condition
- __handler = 9;
+ __handler = 10;
inner: {
while (true) {
- __next = [5];
+ __next = [6];
// goto finally
- __goto = 10;
+ __goto = 11;
break __outer1;
break;
}
}
while (true) {
- __next = [1, 3];
+ __next = [1, 4];
// goto finally
- __goto = 10;
+ __goto = 11;
break __outer1;
}
- __goto = 12;
- return thenHelper(foo(), __helper1, __completer, function(__error) {
- __goto = 9;
- __helper1(__error);
- });
- case 12:
+ __goto = 13;
+ return thenHelper(foo(), __body, __completer);
+ case 13:
// returning from await.
__helper = __result;
- __next = [11];
+ __next = [12];
// goto finally
- __goto = 10;
+ __goto = 11;
break;
- case 9:
- // catch
- __handler = 2;
- __next = [11];
case 10:
+ // uncaught
+ __next = [3];
+ case 11:
// finally
- __handler = 2;
+ __handler = 3;
foo();
// goto while condition
- __goto = 7;
+ __goto = 8;
break;
__returnValue = 2;
__next = [1];
// goto finally
- __goto = 3;
+ __goto = 4;
break;
// goto the next finally handler
__goto = __next.pop();
break;
- case 11:
+ case 12:
// after finally
// goto while condition
- __goto = 7;
+ __goto = 8;
break;
- case 8:
+ case 9:
// after while
- case 5:
+ case 6:
// break __outer
- __next = [4];
+ __next = [5];
// goto finally
- __goto = 3;
+ __goto = 4;
break;
- case 2:
- // catch
- __handler = null;
- __next = [4];
case 3:
+ // uncaught
+ __next = [2];
+ case 4:
// finally
- __handler = null;
+ __handler = 2;
__returnValue = 3;
// goto return
__goto = 1;
@@ -163,7 +176,7 @@
// goto the next finally handler
__goto = __next.pop();
break;
- case 4:
+ case 5:
// after finally
__returnValue = 4;
// goto return
@@ -171,20 +184,22 @@
break;
case 1:
// return
- return thenHelper(__returnValue, null, __completer, null);
+ return thenHelper(__returnValue, 0, __completer, null);
+ case 2:
+ // rethrow
+ return thenHelper(__currentError, 1, __completer);
}
} catch (__error) {
- if (__handler === null)
- throw __error;
- __result = __error;
+ __currentError = __error;
__goto = __handler;
}
}
- return thenHelper(null, __helper1, __completer, null);
+ return thenHelper(null, __body, __completer, null);
}""");
+
testTransform("""
-function() async {
+function(c) async {
var a, b, c, d, e, f;
a = b++; // post- and preincrements.
b = --b;
@@ -193,45 +208,59 @@
e = foo1()[await foo2()]--;
f = --foo1()[await foo2()];
}""", """
-function() {
- var __goto = 0, __completer = new Completer(), a, b, c, d, e, f, __temp1;
- function __helper(__result) {
+function(c) {
+ var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, a, b, c, d, e, f, __temp1;
+ function __body(__errorCode, __result) {
+ if (__errorCode == 1) {
+ __currentError = __result;
+ __goto = __handler;
+ }
while (true)
- switch (__goto) {
- case 0:
- // Function start
- a = b++;
- b = --b;
- __goto = 1;
- return thenHelper(foo(), __helper, __completer, null);
- case 1:
- // returning from await.
- c = __result.a++;
- __goto = 2;
- return thenHelper(foo(), __helper, __completer, null);
- case 2:
- // returning from await.
- d = ++__result.a;
- __temp1 = foo1();
- __goto = 3;
- return thenHelper(foo2(), __helper, __completer, null);
- case 3:
- // returning from await.
- e = __temp1[__result]--;
- __temp1 = foo1();
- __goto = 4;
- return thenHelper(foo2(), __helper, __completer, null);
- case 4:
- // returning from await.
- f = --__temp1[__result];
- // implicit return
- return thenHelper(null, null, __completer, null);
+ try {
+ switch (__goto) {
+ case 0:
+ // Function start
+ a = b++;
+ b = --b;
+ __goto = 2;
+ return thenHelper(foo(), __body, __completer);
+ case 2:
+ // returning from await.
+ c = __result.a++;
+ __goto = 3;
+ return thenHelper(foo(), __body, __completer);
+ case 3:
+ // returning from await.
+ d = ++__result.a;
+ __temp1 = foo1();
+ __goto = 4;
+ return thenHelper(foo2(), __body, __completer);
+ case 4:
+ // returning from await.
+ e = __temp1[__result]--;
+ __temp1 = foo1();
+ __goto = 5;
+ return thenHelper(foo2(), __body, __completer);
+ case 5:
+ // returning from await.
+ f = --__temp1[__result];
+ // implicit return
+ return thenHelper(null, 0, __completer, null);
+ case 1:
+ // rethrow
+ return thenHelper(__currentError, 1, __completer);
+ }
+ } catch (__error) {
+ __currentError = __error;
+ __goto = __handler;
}
+
}
- return thenHelper(null, __helper, __completer, null);
+ return thenHelper(null, __body, __completer, null);
}""");
+
testTransform("""
-function() async {
+function(d2) async {
var a, b, c, d, e, f, g, h; // empty initializer
a = foo1() || await foo2(); // short circuiting operators
b = await foo1() || foo2();
@@ -242,119 +271,133 @@
g = await foo1() && await foo2();
h = foo1() && foo2();
}""", """
-function() {
- var __goto = 0, __completer = new Completer(), a, b, c, d, e, f, g, h, __temp1;
- function __helper(__result) {
+function(d2) {
+ var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, a, b, c, d, e, f, g, h, __temp1;
+ function __body(__errorCode, __result) {
+ if (__errorCode == 1) {
+ __currentError = __result;
+ __goto = __handler;
+ }
while (true)
- switch (__goto) {
- case 0:
- // Function start
- __temp1 = foo1();
- if (__temp1) {
- // goto then
- __goto = 1;
+ try {
+ switch (__goto) {
+ case 0:
+ // Function start
+ __temp1 = foo1();
+ if (__temp1) {
+ // goto then
+ __goto = 2;
+ break;
+ } else
+ __result = __temp1;
+ // goto join
+ __goto = 3;
break;
- } else
- __result = __temp1;
- // goto join
- __goto = 2;
- break;
- case 1:
- // then
- __goto = 3;
- return thenHelper(foo2(), __helper, __completer, null);
- case 3:
- // returning from await.
- case 2:
- // join
- a = __result;
- __goto = 4;
- return thenHelper(foo1(), __helper, __completer, null);
- case 4:
- // returning from await.
- b = __result || foo2();
- __goto = 7;
- return thenHelper(foo1(), __helper, __completer, null);
- case 7:
- // returning from await.
- __temp1 = __result;
- if (__temp1) {
- // goto then
+ case 2:
+ // then
+ __goto = 4;
+ return thenHelper(foo2(), __body, __completer);
+ case 4:
+ // returning from await.
+ case 3:
+ // join
+ a = __result;
__goto = 5;
+ return thenHelper(foo1(), __body, __completer);
+ case 5:
+ // returning from await.
+ b = __result || foo2();
+ __goto = 8;
+ return thenHelper(foo1(), __body, __completer);
+ case 8:
+ // returning from await.
+ __temp1 = __result;
+ if (__temp1) {
+ // goto then
+ __goto = 6;
+ break;
+ } else
+ __result = __temp1;
+ // goto join
+ __goto = 7;
break;
- } else
- __result = __temp1;
- // goto join
- __goto = 6;
- break;
- case 5:
- // then
- __temp1 = foo3;
- __goto = 8;
- return thenHelper(foo2(), __helper, __completer, null);
- case 8:
- // returning from await.
- __result = __temp1(__result);
- case 6:
- // join
- c = __result;
- d = foo1() || foo2();
- __temp1 = foo1();
- if (__temp1)
- __result = __temp1;
- else {
- // goto then
+ case 6:
+ // then
+ __temp1 = foo3;
__goto = 9;
+ return thenHelper(foo2(), __body, __completer);
+ case 9:
+ // returning from await.
+ __result = __temp1(__result);
+ case 7:
+ // join
+ c = __result;
+ d = foo1() || foo2();
+ __temp1 = foo1();
+ if (__temp1)
+ __result = __temp1;
+ else {
+ // goto then
+ __goto = 10;
+ break;
+ }
+ // goto join
+ __goto = 11;
break;
- }
- // goto join
- __goto = 10;
- break;
- case 9:
- // then
- __goto = 11;
- return thenHelper(foo2(), __helper, __completer, null);
- case 11:
- // returning from await.
- case 10:
- // join
- e = __result;
- __goto = 12;
- return thenHelper(foo1(), __helper, __completer, null);
- case 12:
- // returning from await.
- f = __result && foo2();
- __goto = 15;
- return thenHelper(foo1(), __helper, __completer, null);
- case 15:
- // returning from await.
- __temp1 = __result;
- if (__temp1)
- __result = __temp1;
- else {
- // goto then
+ case 10:
+ // then
+ __goto = 12;
+ return thenHelper(foo2(), __body, __completer);
+ case 12:
+ // returning from await.
+ case 11:
+ // join
+ e = __result;
__goto = 13;
+ return thenHelper(foo1(), __body, __completer);
+ case 13:
+ // returning from await.
+ f = __result && foo2();
+ __goto = 16;
+ return thenHelper(foo1(), __body, __completer);
+ case 16:
+ // returning from await.
+ __temp1 = __result;
+ if (__temp1)
+ __result = __temp1;
+ else {
+ // goto then
+ __goto = 14;
+ break;
+ }
+ // goto join
+ __goto = 15;
break;
- }
- // goto join
- __goto = 14;
- break;
- case 13:
- // then
- __goto = 16;
- return thenHelper(foo2(), __helper, __completer, null);
- case 16:
- // returning from await.
- case 14:
- // join
- g = __result;
- h = foo1() && foo2();
- // implicit return
- return thenHelper(null, null, __completer, null);
+ case 14:
+ // then
+ __goto = 17;
+ return thenHelper(foo2(), __body, __completer);
+ case 17:
+ // returning from await.
+ case 15:
+ // join
+ g = __result;
+ h = foo1() && foo2();
+ // implicit return
+ return thenHelper(null, 0, __completer, null);
+ case 1:
+ // rethrow
+ return thenHelper(__currentError, 1, __completer);
+ }
+ } catch (__error) {
+ __currentError = __error;
+ __goto = __handler;
}
+
}
- return thenHelper(null, __helper, __completer, null);
+ return thenHelper(null, __body, __completer, null);
}""");
+
testTransform("""
function(x, y) async {
while (true) {
@@ -372,75 +415,89 @@
}
}""", """
function(x, y) {
- var __goto = 0, __completer = new Completer();
- function __helper(__result) {
+ var __goto = 0, __completer = new Completer(), __handler = 1, __currentError;
+ function __body(__errorCode, __result) {
+ if (__errorCode == 1) {
+ __currentError = __result;
+ __goto = __handler;
+ }
while (true)
- switch (__goto) {
- case 0:
- // Function start
- case 1:
- // while condition
- case 3:
- // switch
- switch (y) {
- case 0:
- // goto case
- __goto = 5;
- break;
- case 1:
- // goto case
- __goto = 6;
- break;
- case 1:
- // goto case
- __goto = 7;
- break;
- case 2:
- // goto case
- __goto = 8;
- break;
- }
- // goto after switch
- __goto = 4;
- break;
- case 5:
- // case
- case 6:
- // case
- __goto = 9;
- return thenHelper(foo(), __helper, __completer, null);
- case 9:
- // returning from await.
- // goto while condition
- __goto = 1;
- break;
- case 7:
- // case
- __goto = 10;
- return thenHelper(foo(), __helper, __completer, null);
- case 10:
- // returning from await.
- // goto after switch
- __goto = 4;
- break;
- case 8:
- // case
- foo();
- case 4:
- // after switch
- // goto while condition
- __goto = 1;
- break;
- case 2:
- // after while
- // implicit return
- return thenHelper(null, null, __completer, null);
+ try {
+ switch (__goto) {
+ case 0:
+ // Function start
+ case 2:
+ // while condition
+ case 4:
+ // switch
+ switch (y) {
+ case 0:
+ // goto case
+ __goto = 6;
+ break;
+ case 1:
+ // goto case
+ __goto = 7;
+ break;
+ case 1:
+ // goto case
+ __goto = 8;
+ break;
+ case 2:
+ // goto case
+ __goto = 9;
+ break;
+ }
+ // goto after switch
+ __goto = 5;
+ break;
+ case 6:
+ // case
+ case 7:
+ // case
+ __goto = 10;
+ return thenHelper(foo(), __body, __completer);
+ case 10:
+ // returning from await.
+ // goto while condition
+ __goto = 2;
+ break;
+ case 8:
+ // case
+ __goto = 11;
+ return thenHelper(foo(), __body, __completer);
+ case 11:
+ // returning from await.
+ // goto after switch
+ __goto = 5;
+ break;
+ case 9:
+ // case
+ foo();
+ case 5:
+ // after switch
+ // goto while condition
+ __goto = 2;
+ break;
+ case 3:
+ // after while
+ // implicit return
+ return thenHelper(null, 0, __completer, null);
+ case 1:
+ // rethrow
+ return thenHelper(__currentError, 1, __completer);
+ }
+ } catch (__error) {
+ __currentError = __error;
+ __goto = __handler;
}
+
}
- return thenHelper(null, __helper, __completer, null);
+ return thenHelper(null, __body, __completer, null);
}""");
+
testTransform("""
-function() async {
+function(f) async {
do {
var a = await foo();
if (a) // If with no awaits in body
@@ -450,51 +507,64 @@
} while (await foo());
}
""", """
-function() {
- var __goto = 0, __completer = new Completer(), a;
- function __helper(__result) {
+function(f) {
+ var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, a;
+ function __body(__errorCode, __result) {
+ if (__errorCode == 1) {
+ __currentError = __result;
+ __goto = __handler;
+ }
while (true)
- switch (__goto) {
- case 0:
- // Function start
- case 1:
- // do body
- __goto = 4;
- return thenHelper(foo(), __helper, __completer, null);
- case 4:
- // returning from await.
- a = __result;
- if (a) {
- // goto after do
- __goto = 3;
- break;
- } else {
- // goto do condition
- __goto = 2;
- break;
- }
- case 2:
- // do condition
- __goto = 5;
- return thenHelper(foo(), __helper, __completer, null);
- case 5:
- // returning from await.
- if (__result) {
- // goto do body
- __goto = 1;
- break;
- }
- case 3:
- // after do
- // implicit return
- return thenHelper(null, null, __completer, null);
+ try {
+ switch (__goto) {
+ case 0:
+ // Function start
+ case 2:
+ // do body
+ __goto = 5;
+ return thenHelper(foo(), __body, __completer);
+ case 5:
+ // returning from await.
+ a = __result;
+ if (a) {
+ // goto after do
+ __goto = 4;
+ break;
+ } else {
+ // goto do condition
+ __goto = 3;
+ break;
+ }
+ case 3:
+ // do condition
+ __goto = 6;
+ return thenHelper(foo(), __body, __completer);
+ case 6:
+ // returning from await.
+ if (__result) {
+ // goto do body
+ __goto = 2;
+ break;
+ }
+ case 4:
+ // after do
+ // implicit return
+ return thenHelper(null, 0, __completer, null);
+ case 1:
+ // rethrow
+ return thenHelper(__currentError, 1, __completer);
+ }
+ } catch (__error) {
+ __currentError = __error;
+ __goto = __handler;
}
+
}
- return thenHelper(null, __helper, __completer, null);
+ return thenHelper(null, __body, __completer, null);
}""");
testTransform("""
-function() async {
+function(g) async {
for (var i = 0; i < await foo1(); i += await foo2()) {
if (foo(i))
continue;
@@ -508,76 +578,89 @@
}
}
""", """
-function() {
- var __goto = 0, __completer = new Completer(), __returnValue, i, __temp1;
- function __helper(__result) {
+function(g) {
+ var __goto = 0, __completer = new Completer(), __handler = 2, __currentError, __returnValue, i, __temp1;
+ function __body(__errorCode, __result) {
+ if (__errorCode == 1) {
+ __currentError = __result;
+ __goto = __handler;
+ }
while (true)
- switch (__goto) {
- case 0:
- // Function start
- i = 0;
- case 2:
- // for condition
- __temp1 = i;
- __goto = 5;
- return thenHelper(foo1(), __helper, __completer, null);
- case 5:
- // returning from await.
- if (!(__temp1 < __result)) {
- // goto after for
- __goto = 4;
+ try {
+ switch (__goto) {
+ case 0:
+ // Function start
+ i = 0;
+ case 3:
+ // for condition
+ __temp1 = i;
+ __goto = 6;
+ return thenHelper(foo1(), __body, __completer);
+ case 6:
+ // returning from await.
+ if (!(__temp1 < __result)) {
+ // goto after for
+ __goto = 5;
+ break;
+ }
+ if (foo(i)) {
+ // goto for update
+ __goto = 4;
+ break;
+ } else {
+ // goto after for
+ __goto = 5;
+ break;
+ }
+ __goto = !foo(i) ? 7 : 8;
break;
- }
- if (foo(i)) {
- // goto for update
+ case 7:
+ // then
+ __goto = 9;
+ return thenHelper(foo(), __body, __completer);
+ case 9:
+ // returning from await.
+ // goto return
+ __goto = 1;
+ break;
+ case 8:
+ // join
+ __temp1 = print;
+ __goto = 10;
+ return thenHelper(foo(i), __body, __completer);
+ case 10:
+ // returning from await.
+ __temp1(__result);
+ case 4:
+ // for update
+ __goto = 11;
+ return thenHelper(foo2(), __body, __completer);
+ case 11:
+ // returning from await.
+ i = __result;
+ // goto for condition
__goto = 3;
break;
- } else {
- // goto after for
- __goto = 4;
- break;
- }
- __goto = !foo(i) ? 6 : 7;
- break;
- case 6:
- // then
- __goto = 8;
- return thenHelper(foo(), __helper, __completer, null);
- case 8:
- // returning from await.
- // goto return
- __goto = 1;
- break;
- case 7:
- // join
- __temp1 = print;
- __goto = 9;
- return thenHelper(foo(i), __helper, __completer, null);
- case 9:
- // returning from await.
- __temp1(__result);
- case 3:
- // for update
- __goto = 10;
- return thenHelper(foo2(), __helper, __completer, null);
- case 10:
- // returning from await.
- i = __result;
- // goto for condition
- __goto = 2;
- break;
- case 4:
- // after for
- case 1:
- // return
- return thenHelper(__returnValue, null, __completer, null);
+ case 5:
+ // after for
+ case 1:
+ // return
+ return thenHelper(__returnValue, 0, __completer, null);
+ case 2:
+ // rethrow
+ return thenHelper(__currentError, 1, __completer);
+ }
+ } catch (__error) {
+ __currentError = __error;
+ __goto = __handler;
}
+
}
- return thenHelper(null, __helper, __completer, null);
+ return thenHelper(null, __body, __completer, null);
}""");
testTransform("""
-function(a) async {
+function(a, h) async {
var x = {"a": foo1(), "b": await foo2(), "c": foo3()};
x["a"] = 2; // Different assignments
(await foo()).a = 3;
@@ -586,65 +669,79 @@
(await foo1())[await foo2()] = await foo3(6);
}
""", """
-function(a) {
- var __goto = 0, __completer = new Completer(), x, __temp1, __temp2;
- function __helper(__result) {
+function(a, h) {
+ var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, x, __temp1, __temp2;
+ function __body(__errorCode, __result) {
+ if (__errorCode == 1) {
+ __currentError = __result;
+ __goto = __handler;
+ }
while (true)
- switch (__goto) {
- case 0:
- // Function start
- __temp1 = foo1();
- __goto = 1;
- return thenHelper(foo2(), __helper, __completer, null);
- case 1:
- // returning from await.
- x = {a: __temp1, b: __result, c: foo3()};
- x.a = 2;
- __goto = 2;
- return thenHelper(foo(), __helper, __completer, null);
- case 2:
- // returning from await.
- __result.a = 3;
- __temp1 = x;
- __goto = 3;
- return thenHelper(foo(), __helper, __completer, null);
- case 3:
- // returning from await.
- __temp1[__result] = 4;
- __temp1 = x;
- __goto = 4;
- return thenHelper(foo1(), __helper, __completer, null);
- case 4:
- // returning from await.
- __temp2 = __result;
- __goto = 5;
- return thenHelper(foo2(), __helper, __completer, null);
- case 5:
- // returning from await.
- __temp1[__temp2.a = __result] = 5;
- __goto = 6;
- return thenHelper(foo1(), __helper, __completer, null);
- case 6:
- // returning from await.
- __temp1 = __result;
- __goto = 7;
- return thenHelper(foo2(), __helper, __completer, null);
- case 7:
- // returning from await.
- __temp2 = __result;
- __goto = 8;
- return thenHelper(foo3(6), __helper, __completer, null);
- case 8:
- // returning from await.
- __temp1[__temp2] = __result;
- // implicit return
- return thenHelper(null, null, __completer, null);
+ try {
+ switch (__goto) {
+ case 0:
+ // Function start
+ __temp1 = foo1();
+ __goto = 2;
+ return thenHelper(foo2(), __body, __completer);
+ case 2:
+ // returning from await.
+ x = {a: __temp1, b: __result, c: foo3()};
+ x.a = 2;
+ __goto = 3;
+ return thenHelper(foo(), __body, __completer);
+ case 3:
+ // returning from await.
+ __result.a = 3;
+ __temp1 = x;
+ __goto = 4;
+ return thenHelper(foo(), __body, __completer);
+ case 4:
+ // returning from await.
+ __temp1[__result] = 4;
+ __temp1 = x;
+ __goto = 5;
+ return thenHelper(foo1(), __body, __completer);
+ case 5:
+ // returning from await.
+ __temp2 = __result;
+ __goto = 6;
+ return thenHelper(foo2(), __body, __completer);
+ case 6:
+ // returning from await.
+ __temp1[__temp2.a = __result] = 5;
+ __goto = 7;
+ return thenHelper(foo1(), __body, __completer);
+ case 7:
+ // returning from await.
+ __temp1 = __result;
+ __goto = 8;
+ return thenHelper(foo2(), __body, __completer);
+ case 8:
+ // returning from await.
+ __temp2 = __result;
+ __goto = 9;
+ return thenHelper(foo3(6), __body, __completer);
+ case 9:
+ // returning from await.
+ __temp1[__temp2] = __result;
+ // implicit return
+ return thenHelper(null, 0, __completer, null);
+ case 1:
+ // rethrow
+ return thenHelper(__currentError, 1, __completer);
+ }
+ } catch (__error) {
+ __currentError = __error;
+ __goto = __handler;
}
+
}
- return thenHelper(null, __helper, __completer, null);
+ return thenHelper(null, __body, __completer, null);
}""");
+
testTransform("""
-function(c) async {
+function(c, i) async {
try {
var x = c ? await foo() : foo(); // conditional
var y = {};
@@ -659,103 +756,115 @@
}
}
""", """
-function(c) {
- var __goto = 0, __completer = new Completer(), __handler = null, x, y, __error1, __error2;
- function __helper(__result) {
+function(c, i) {
+ var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, x, y, __error1, __error2;
+ function __body(__errorCode, __result) {
+ if (__errorCode == 1) {
+ __currentError = __result;
+ __goto = __handler;
+ }
while (true)
try {
switch (__goto) {
case 0:
// Function start
- __handler = 1;
- __goto = c ? 4 : 6;
- break;
- case 4:
- // then
- __goto = 7;
- return thenHelper(foo(), __helper, __completer, function(__error) {
- __goto = 1;
- __helper(__error);
- });
- case 7:
- // returning from await.
- // goto join
- __goto = 5;
+ __handler = 3;
+ __goto = c ? 6 : 8;
break;
case 6:
+ // then
+ __goto = 9;
+ return thenHelper(foo(), __body, __completer);
+ case 9:
+ // returning from await.
+ // goto join
+ __goto = 7;
+ break;
+ case 8:
// else
__result = foo();
- case 5:
+ case 7:
// join
x = __result;
y = {};
- __next = [3];
- __handler = null;
+ __handler = 1;
// goto after finally
- __goto = 3;
+ __goto = 5;
break;
- case 1:
+ case 3:
// catch
- __handler = null;
- __error1 = __result;
- __handler = 8;
- __goto = c ? 11 : 13;
+ __handler = 2;
+ __error1 = __currentError;
+ __handler = 11;
+ __goto = c ? 14 : 16;
break;
- case 11:
- // then
- __goto = 14;
- return thenHelper(fooError(__error1), __helper, __completer, function(__error) {
- __goto = 8;
- __helper(__error);
- });
case 14:
+ // then
+ __goto = 17;
+ return thenHelper(fooError(__error1), __body, __completer);
+ case 17:
// returning from await.
// goto join
- __goto = 12;
+ __goto = 15;
break;
- case 13:
+ case 16:
// else
__result = fooError(__error1);
- case 12:
+ case 15:
// join
x = __result;
- __next = [10];
+ __next = [13];
// goto finally
- __goto = 9;
+ __goto = 12;
break;
- case 8:
+ case 11:
// catch
- __handler = null;
- __error2 = __result;
+ __handler = 10;
+ __error2 = __currentError;
y.x = foo(__error2);
- __handler = null;
- __next = [10];
- case 9:
+ __next = [13];
+ // goto finally
+ __goto = 12;
+ break;
+ case 10:
+ // uncaught
+ __next = [2];
+ case 12:
// finally
- __handler = null;
+ __handler = 2;
foo(x);
// goto the next finally handler
__goto = __next.pop();
break;
- case 10:
+ case 13:
// after finally
- case 3:
+ // goto after finally
+ __goto = 5;
+ break;
+ case 2:
+ // uncaught
+ // goto rethrow
+ __goto = 1;
+ break;
+ case 5:
// after finally
// implicit return
- return thenHelper(null, null, __completer, null);
+ return thenHelper(null, 0, __completer, null);
+ case 1:
+ // rethrow
+ return thenHelper(__currentError, 1, __completer);
}
} catch (__error) {
- if (__handler === null)
- throw __error;
- __result = __error;
+ __currentError = __error;
__goto = __handler;
}
}
- return thenHelper(null, __helper, __completer, null);
+ return thenHelper(null, __body, __completer, null);
}""");
+
testTransform("""
-function(x, y) async {
+function(x, y, j) async {
print(await(foo(x))); // calls
(await print)(foo(x));
print(foo(await x));
@@ -763,57 +872,71 @@
print(foo(x, await y, z));
}
""", """
-function(x, y) {
- var __goto = 0, __completer = new Completer(), __temp1, __temp2, __temp3;
- function __helper(__result) {
+function(x, y, j) {
+ var __goto = 0, __completer = new Completer(), __handler = 1, __currentError, __temp1, __temp2, __temp3;
+ function __body(__errorCode, __result) {
+ if (__errorCode == 1) {
+ __currentError = __result;
+ __goto = __handler;
+ }
while (true)
- switch (__goto) {
- case 0:
- // Function start
- __temp1 = print;
- __goto = 1;
- return thenHelper(foo(x), __helper, __completer, null);
- case 1:
- // returning from await.
- __temp1(__result);
- __goto = 2;
- return thenHelper(print, __helper, __completer, null);
- case 2:
- // returning from await.
- __result(foo(x));
- __temp1 = print;
- __temp2 = foo;
- __goto = 3;
- return thenHelper(x, __helper, __completer, null);
- case 3:
- // returning from await.
- __temp1(__temp2(__result));
- __temp1 = print;
- __temp2 = foo;
- __goto = 5;
- return thenHelper(x, __helper, __completer, null);
- case 5:
- // returning from await.
- __goto = 4;
- return thenHelper(__temp1(__temp2(__result)), __helper, __completer, null);
- case 4:
- // returning from await.
- __temp1 = print;
- __temp2 = foo;
- __temp3 = x;
- __goto = 6;
- return thenHelper(y, __helper, __completer, null);
- case 6:
- // returning from await.
- __temp1(__temp2(__temp3, __result, z));
- // implicit return
- return thenHelper(null, null, __completer, null);
+ try {
+ switch (__goto) {
+ case 0:
+ // Function start
+ __temp1 = print;
+ __goto = 2;
+ return thenHelper(foo(x), __body, __completer);
+ case 2:
+ // returning from await.
+ __temp1(__result);
+ __goto = 3;
+ return thenHelper(print, __body, __completer);
+ case 3:
+ // returning from await.
+ __result(foo(x));
+ __temp1 = print;
+ __temp2 = foo;
+ __goto = 4;
+ return thenHelper(x, __body, __completer);
+ case 4:
+ // returning from await.
+ __temp1(__temp2(__result));
+ __temp1 = print;
+ __temp2 = foo;
+ __goto = 6;
+ return thenHelper(x, __body, __completer);
+ case 6:
+ // returning from await.
+ __goto = 5;
+ return thenHelper(__temp1(__temp2(__result)), __body, __completer);
+ case 5:
+ // returning from await.
+ __temp1 = print;
+ __temp2 = foo;
+ __temp3 = x;
+ __goto = 7;
+ return thenHelper(y, __body, __completer);
+ case 7:
+ // returning from await.
+ __temp1(__temp2(__temp3, __result, z));
+ // implicit return
+ return thenHelper(null, 0, __completer, null);
+ case 1:
+ // rethrow
+ return thenHelper(__currentError, 1, __completer);
+ }
+ } catch (__error) {
+ __currentError = __error;
+ __goto = __handler;
}
+
}
- return thenHelper(null, __helper, __completer, null);
+ return thenHelper(null, __body, __completer, null);
}""");
+
testTransform("""
-function(x, y) async {
+function(x, y, k) async {
while (await(foo())) {
lab: { // labelled statement
switch(y) {
@@ -838,112 +961,125 @@
}
}
}""", """
-function(x, y) {
- var __goto = 0, __completer = new Completer(), __returnValue, __temp1;
- function __helper(__result) {
+function(x, y, k) {
+ var __goto = 0, __completer = new Completer(), __handler = 2, __currentError, __returnValue, __temp1;
+ function __body(__errorCode, __result) {
+ if (__errorCode == 1) {
+ __currentError = __result;
+ __goto = __handler;
+ }
while (true)
- switch (__goto) {
- case 0:
- // Function start
- case 2:
- // while condition
- __goto = 4;
- return thenHelper(foo(), __helper, __completer, null);
- case 4:
- // returning from await.
- if (!__result) {
- // goto after while
+ try {
+ switch (__goto) {
+ case 0:
+ // Function start
+ case 3:
+ // while condition
+ __goto = 5;
+ return thenHelper(foo(), __body, __completer);
+ case 5:
+ // returning from await.
+ if (!__result) {
+ // goto after while
+ __goto = 4;
+ break;
+ }
+ case 7:
+ // continue lab
+ case 8:
+ // switch
+ __temp1 = y;
+ if (__temp1 === 0) {
+ // goto case
+ __goto = 10;
+ break;
+ }
+ if (__temp1 === 0) {
+ // goto case
+ __goto = 11;
+ break;
+ }
+ __goto = 13;
+ return thenHelper(bar(), __body, __completer);
+ case 13:
+ // returning from await.
+ if (__temp1 === __result) {
+ // goto case
+ __goto = 12;
+ break;
+ }
+ if (__temp1 === x) {
+ // goto case
+ __goto = 14;
+ break;
+ }
+ // goto default
+ __goto = 15;
+ break;
+ case 10:
+ // case
+ foo();
+ case 11:
+ // case
+ __temp1 = print;
+ __goto = 16;
+ return thenHelper(foo1(x), __body, __completer);
+ case 16:
+ // returning from await.
+ __temp1(__result);
+ __returnValue = y;
+ // goto return
+ __goto = 1;
+ break;
+ case 12:
+ // case
+ __temp1 = print;
+ __goto = 17;
+ return thenHelper(foobar(x), __body, __completer);
+ case 17:
+ // returning from await.
+ __temp1(__result);
+ __returnValue = y;
+ // goto return
+ __goto = 1;
+ break;
+ case 14:
+ // case
+ if (a) {
+ throw new Error();
+ } else {
+ // goto while condition
+ __goto = 3;
+ break;
+ }
+ case 15:
+ // default
+ // goto break lab
+ __goto = 6;
+ break;
+ case 9:
+ // after switch
+ foo();
+ case 6:
+ // break lab
+ // goto while condition
__goto = 3;
break;
- }
- case 6:
- // continue lab
- case 7:
- // switch
- __temp1 = y;
- if (__temp1 === 0) {
- // goto case
- __goto = 9;
- break;
- }
- if (__temp1 === 0) {
- // goto case
- __goto = 10;
- break;
- }
- __goto = 12;
- return thenHelper(bar(), __helper, __completer, null);
- case 12:
- // returning from await.
- if (__temp1 === __result) {
- // goto case
- __goto = 11;
- break;
- }
- if (__temp1 === x) {
- // goto case
- __goto = 13;
- break;
- }
- // goto default
- __goto = 14;
- break;
- case 9:
- // case
- foo();
- case 10:
- // case
- __temp1 = print;
- __goto = 15;
- return thenHelper(foo1(x), __helper, __completer, null);
- case 15:
- // returning from await.
- __temp1(__result);
- __returnValue = y;
- // goto return
- __goto = 1;
- break;
- case 11:
- // case
- __temp1 = print;
- __goto = 16;
- return thenHelper(foobar(x), __helper, __completer, null);
- case 16:
- // returning from await.
- __temp1(__result);
- __returnValue = y;
- // goto return
- __goto = 1;
- break;
- case 13:
- // case
- if (a) {
- throw new Error();
- } else {
- // goto while condition
- __goto = 2;
- break;
- }
- case 14:
- // default
- // goto break lab
- __goto = 5;
- break;
- case 8:
- // after switch
- foo();
- case 5:
- // break lab
- // goto while condition
- __goto = 2;
- break;
- case 3:
- // after while
- case 1:
- // return
- return thenHelper(__returnValue, null, __completer, null);
+ case 4:
+ // after while
+ case 1:
+ // return
+ return thenHelper(__returnValue, 0, __completer, null);
+ case 2:
+ // rethrow
+ return thenHelper(__currentError, 1, __completer);
+ }
+ } catch (__error) {
+ __currentError = __error;
+ __goto = __handler;
}
+
}
- return thenHelper(null, __helper, __completer, null);
+ return thenHelper(null, __body, __completer, null);
}""");
}
diff --git a/tests/compiler/dart2js/mock_libraries.dart b/tests/compiler/dart2js/mock_libraries.dart
index ab820a4..ffa2dab 100644
--- a/tests/compiler/dart2js/mock_libraries.dart
+++ b/tests/compiler/dart2js/mock_libraries.dart
@@ -98,6 +98,7 @@
'assertIsSubtype': 'assertIsSubtype(subtype, supertype, message) {}',
'assertSubtype': 'assertSubtype(object, isField, checks, asField) {}',
'assertSubtypeOfRuntimeType': 'assertSubtypeOfRuntimeType(object, type) {}',
+ 'asyncHelper': 'asyncHelper(object, asyncBody, completer) {}',
'boolConversionCheck': 'boolConversionCheck(x) {}',
'boolTypeCast': 'boolTypeCast(value) {}',
'boolTypeCheck': 'boolTypeCheck(value) {}',
@@ -209,8 +210,6 @@
'stringTypeCheck': 'stringTypeCheck(x) {}',
'subtypeCast': 'subtypeCast(object, isField, checks, asField) {}',
'subtypeOfRuntimeTypeCast': 'subtypeOfRuntimeTypeCast(object, type) {}',
- 'thenHelper':
- 'thenHelper(object, helperCallback, completer, errorCallback) {}',
'throwAbstractClassInstantiationError':
'throwAbstractClassInstantiationError(className) {}',
'throwCyclicInit': 'throwCyclicInit(staticName) {}',
diff --git a/tests/compiler/dart2js_extra/21166_test.dart b/tests/compiler/dart2js_extra/21166_test.dart
new file mode 100644
index 0000000..bc8f63b
--- /dev/null
+++ b/tests/compiler/dart2js_extra/21166_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2015, 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.
+
+// Regression test for http://dartbug.com/21166/
+// Fails when compiling with --checked.
+
+var a = [];
+
+void doStuff() {
+ if (a.length) { // This triggers a TypeConversion to bool in checked mode.
+ var element = a[0]; // This triggers a bounds check but a.length will have
+ a.remove(element); // type [empty].
+ }
+}
+
+main() {
+ a.add(1);
+ a.add(2);
+ try {
+ doStuff(); // This is expected to fail but not crash the compiler.
+ } catch (_) {}
+}
+
+
diff --git a/tests/language/async_return_types_test.dart b/tests/language/async_return_types_test.dart
new file mode 100644
index 0000000..83eb9a8
--- /dev/null
+++ b/tests/language/async_return_types_test.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2015, 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:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+Future foo1() async {
+ return 3;
+}
+
+Future<int> foo2() async {
+ return 3;
+}
+
+Future<int> /// wrongTypeParameter: static type warning
+foo3() async {
+ return "String";
+}
+
+// Future<int, String> is treated like Future<dynamic>
+Future<int, String> /// tooManyTypeParameters: static type warning
+foo4() async {
+ return "String";
+}
+
+int /// wrongReturnType: static type warning, dynamic type error
+foo5() async {
+ return 3;
+}
+
+Future<int> foo6() async {
+ // This is fine, the future is flattened
+ return new Future<int>.value(3);
+}
+
+Future<Future<int>> /// nestedFuture: static type warning
+foo7() async {
+ return new Future<int>.value(3);
+}
+
+test() async {
+ Expect.equals(3, await foo1());
+ Expect.equals(3, await foo2());
+ Expect.equals("String", await foo3());
+ Expect.equals("String", await foo4());
+ Expect.equals(3, await foo5());
+ Expect.equals(3, await await foo6());
+ Expect.equals(3, await await foo7());
+}
+
+main() {
+ asyncTest(test);
+}
\ No newline at end of file
diff --git a/tests/language/async_throw_in_catch_test.dart b/tests/language/async_throw_in_catch_test.dart
new file mode 100644
index 0000000..1cb741e
--- /dev/null
+++ b/tests/language/async_throw_in_catch_test.dart
@@ -0,0 +1,440 @@
+// Copyright (c) 2015, 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:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+class Tracer {
+ final String expected;
+ final String name;
+ int counter = 0;
+
+ Tracer(this.expected, [this.name]);
+
+ void trace(msg) {
+ if (name != null) {
+ print("Tracing $name: $msg");
+ }
+ Expect.equals(expected[counter], msg);
+ counter++;
+ }
+
+ void done() {
+ Expect.equals(expected.length, counter, "Received too few traces");
+ }
+}
+
+foo1(Tracer tracer) async {
+ try {
+ tracer.trace("a");
+ // This await forces dart2js to rewrite the try into a state machine
+ // instead of relying on the existing structure.
+ await new Future.value(3); /// forceAwait: ok
+ tracer.trace("b");
+ throw "Error";
+ } catch (error) {
+ tracer.trace("c");
+ Expect.equals("Error", error);
+ throw "Error2";
+ tracer.trace("d");
+ } finally {
+ tracer.trace("e");
+ }
+ tracer.trace("f");
+}
+
+foo2(Tracer tracer) async {
+ try {
+ tracer.trace("a");
+ await new Future.value(3); /// forceAwait: continued
+ tracer.trace("b");
+ throw "Error";
+ tracer.trace("c");
+ } catch (error) {
+ tracer.trace("d");
+ Expect.equals("Error", error);
+ await new Future.error("Error2");
+ } finally {
+ tracer.trace("e");
+ }
+ tracer.trace("f");
+}
+
+foo3(Tracer tracer) async {
+ try {
+ tracer.trace("a");
+ await new Future.value(3); /// forceAwait: continued
+ tracer.trace("b");
+ throw "Error";
+ tracer.trace("c");
+ } catch (error) {
+ Expect.equals("Error", error);
+ tracer.trace("d");
+ return;
+ } finally {
+ tracer.trace("e");
+ }
+ tracer.trace("f");
+}
+
+foo4(Tracer tracer) async {
+ try {
+ try {
+ await new Future.value(3); /// forceAwait: continued
+ tracer.trace("a");
+ throw "Error";
+ } catch(error) {
+ tracer.trace("b");
+ Expect.equals("Error", error);
+ throw "Error2";
+ }
+ } catch(error) {
+ Expect.equals("Error2", error);
+ tracer.trace("c");
+ }
+ tracer.trace("d");
+
+}
+
+foo5(Tracer tracer) async {
+ try {
+ tracer.trace("a");
+ try {
+ await new Future.value(3); /// forceAwait: continued
+ tracer.trace("b");
+ throw "Error";
+ } catch(error) {
+ tracer.trace("c");
+ Expect.equals("Error", error);
+ throw "Error2";
+ }
+ } finally {
+ tracer.trace("d");
+ }
+ tracer.trace("e");
+
+}
+
+foo6(Tracer tracer) async {
+ try {
+ try {
+ await new Future.value(3); /// forceAwait: continued
+ tracer.trace("a");
+ throw "Error";
+ } catch(error) {
+ tracer.trace("b");
+ Expect.equals("Error", error);
+ throw "Error2";
+ } finally {
+ tracer.trace("c");
+ throw "Error3";
+ }
+ } catch(error) {
+ tracer.trace("d");
+ Expect.equals("Error3", error);
+ }
+ tracer.trace("e");
+}
+
+foo7(Tracer tracer) async {
+ try {
+ try {
+ await new Future.value(3); /// forceAwait: continued
+ tracer.trace("a");
+ throw "Error";
+ } catch(error) {
+ Expect.equals("Error", error);
+ tracer.trace("b");
+ throw "Error2";
+ } finally {
+ tracer.trace("c");
+ throw "Error3";
+ }
+ } finally {
+ tracer.trace("d");
+ }
+ tracer.trace("e");
+}
+
+foo8(Tracer tracer) async {
+ try {
+ try {
+ await new Future.value(3); /// forceAwait: continued
+ tracer.trace("a");
+ throw "Error";
+ } catch(error) {
+ Expect.equals("Error", error);
+ tracer.trace("b");
+ return;
+ } finally {
+ tracer.trace("c");
+ throw "Error3";
+ }
+ } finally {
+ tracer.trace("d");
+ }
+ tracer.trace("e");
+}
+
+foo9(Tracer tracer) async {
+ try {
+ while(true) {
+ try {
+ await new Future.value(3); /// forceAwait: continued
+ tracer.trace("a");
+ throw "Error";
+ } catch(error) {
+ Expect.equals("Error", error);
+ tracer.trace("b");
+ return;
+ } finally {
+ tracer.trace("c");
+ break;
+ }
+ tracer.trace("d");
+ }
+ } finally {
+ tracer.trace("e");
+ }
+ tracer.trace("f");
+}
+
+foo10(Tracer tracer) async {
+ try {
+ int i = 0;
+ while (true) {
+ try {
+ try {
+ tracer.trace("a");
+ throw "Error";
+ } catch (error) {
+ tracer.trace("b");
+ try {
+ await new Future.value(3); /// forceAwait: continued
+ throw "Error2";
+ } catch(error) {
+ tracer.trace("c");
+ } finally {
+ tracer.trace("d");
+ }
+ tracer.trace("e");
+ throw "Error3";
+ } finally {
+ tracer.trace("f");
+ // Continue and breaks 'eats' Error3.
+ if (i == 0) continue;
+ if (i == 1) break;
+ }
+ } finally {
+ tracer.trace("g");
+ i++;
+ }
+ }
+ } finally {
+ tracer.trace("h");
+ }
+ tracer.trace("i");
+}
+
+foo11(Tracer tracer) async {
+ try {
+ bool firstTime = true;
+ while(true) {
+ tracer.trace("a");
+ if (firstTime) {
+ try {
+ await new Future.value(3); /// forceAwait: continued
+ tracer.trace("b");
+ throw "Error";
+ } catch(error) {
+ Expect.equals("Error", error);
+ tracer.trace("c");
+ firstTime = false;
+ continue;
+ } finally {
+ tracer.trace("d");
+ }
+ } else {
+ tracer.trace("e");
+ return;
+ }
+ }
+ } finally {
+ tracer.trace("f");
+ }
+ tracer.trace("g");
+}
+
+foo12(Tracer tracer) async {
+ try {
+ bool firstTime = true;
+ while(true) {
+ tracer.trace("a");
+ if (firstTime) {
+ try {
+ await new Future.value(3); /// forceAwait: continued
+ tracer.trace("b");
+ throw "Error";
+ } catch(error) {
+ Expect.equals("Error", error);
+ tracer.trace("c");
+ firstTime = false;
+ continue;
+ } finally {
+ tracer.trace("d");
+ break;
+ }
+ } else {
+ tracer.trace("e");
+ return;
+ }
+ }
+ } finally {
+ tracer.trace("f");
+ }
+ tracer.trace("g");
+}
+
+foo13(Tracer tracer) async {
+ try {
+ try {
+ tracer.trace("a");
+ return;
+ } catch (error) {
+ tracer.trace("b");
+ } finally {
+ tracer.trace("c");
+ try {
+ try {
+ await new Future.value(3); /// forceAwait: continued
+ tracer.trace("d");
+ throw "Error";
+ } finally {
+ tracer.trace("e");
+ }
+ } finally {
+ tracer.trace("f");
+ }
+ }
+ } finally {
+ tracer.trace("g");
+ }
+ tracer.trace("h");
+}
+
+foo14(Tracer tracer) async {
+ try {
+ try {
+ tracer.trace("a");
+ throw "Error";
+ } catch (error) {
+ tracer.trace("b");
+ try {
+ await new Future.value(3); /// forceAwait: continued
+ throw "Error2";
+ } catch(error) {
+ tracer.trace("c");
+ } finally {
+ tracer.trace("d");
+ }
+ tracer.trace("e");
+ throw "Error3";
+ } finally {
+ tracer.trace("f");
+ }
+ } finally {
+ tracer.trace("g");
+ }
+ tracer.trace("h");
+}
+
+foo15(Tracer tracer) async {
+ try {
+ try {
+ tracer.trace("a");
+ throw "Error";
+ } catch (error) {
+ tracer.trace("b");
+ try {
+ await new Future.value(3); /// forceAwait: continued
+ throw "Error2";
+ } catch(error) {
+ tracer.trace("c");
+ } finally {
+ tracer.trace("d");
+ }
+ tracer.trace("e");
+ throw "Error3";
+ } finally {
+ tracer.trace("f");
+ return;
+ }
+ } finally {
+ tracer.trace("g");
+ }
+ tracer.trace("h");
+}
+
+foo16(Tracer tracer) async {
+ try {
+ try {
+ tracer.trace("a");
+ throw "Error";
+ } catch (error) {
+ tracer.trace("b");
+ try {
+ await new Future.value(3); /// forceAwait: continued
+ throw "Error2";
+ } catch(error) {
+ tracer.trace("c");
+ } finally {
+ tracer.trace("d");
+ return;
+ }
+ tracer.trace("e");
+ throw "Error3";
+ } finally {
+ tracer.trace("f");
+ }
+ } finally {
+ tracer.trace("g");
+ }
+ tracer.trace("h");
+}
+
+runTest(expectedTrace, fun, [expectedError]) async {
+ Tracer tracer = new Tracer(expectedTrace);
+ try {
+ await fun(tracer);
+ } catch (error) {
+ Expect.equals(expectedError, error);
+ tracer.trace("X");
+ }
+ tracer.done();
+}
+
+test() async {
+ await runTest("abceX", foo1, "Error2");
+ await runTest("abdeX", foo2, "Error2");
+ await runTest("abde", foo3);
+ await runTest("abcd", foo4);
+ await runTest("abcdX", foo5, "Error2");
+ await runTest("abcde", foo6);
+ await runTest("abcdX", foo7, "Error3");
+ await runTest("abcdX", foo8, "Error3");
+ await runTest("abcef", foo9);
+ await runTest("abcdefgabcdefghi", foo10);
+ await runTest("abcdaef", foo11);
+ await runTest("abcdfg", foo12);
+ await runTest("acdefgX", foo13, "Error");
+ await runTest("abcdefgX", foo14, "Error3");
+ await runTest("abcdefgX", foo14, "Error3");
+ await runTest("abcdefg", foo15);
+ await runTest("abcdfg", foo16);
+}
+
+void main() {
+ asyncTest(test);
+}
\ No newline at end of file
diff --git a/tests/language/asyncstar_throw_in_catch_test.dart b/tests/language/asyncstar_throw_in_catch_test.dart
new file mode 100644
index 0000000..a6f6a33
--- /dev/null
+++ b/tests/language/asyncstar_throw_in_catch_test.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2015, 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:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+class Tracer {
+ final String expected;
+ final String name;
+ int counter = 0;
+
+ Tracer(this.expected, [this.name]);
+
+ void trace(msg) {
+ if (name != null) {
+ print("Tracing $name: $msg");
+ }
+ Expect.equals(expected[counter], msg);
+ counter++;
+ }
+
+ void done() {
+ Expect.equals(expected.length, counter, "Received too few traces");
+ }
+}
+
+foo1(Tracer tracer) async* {
+ try {
+ tracer.trace("a");
+ await new Future.value(3);
+ tracer.trace("b");
+ throw "Error";
+ } catch (e) {
+ tracer.trace("c");
+ yield 1;
+ tracer.trace("d");
+ yield 2;
+ tracer.trace("e");
+ await new Future.error("Error2");
+ } finally {
+ tracer.trace("f");
+ }
+ tracer.trace("g");
+}
+
+test() async {
+ Tracer tracer;
+
+ Completer foo1Done = new Completer();
+ tracer = new Tracer("abcdf");
+ var subscription;
+ subscription = foo1(tracer).listen((event) async {
+ await subscription.cancel();
+ tracer.done();
+ foo1Done.complete(null);
+ });
+ await foo1Done.future;
+}
+
+
+void main() {
+ asyncTest(test);
+}
\ No newline at end of file
diff --git a/tests/language/language.status b/tests/language/language.status
index 733ba43..71c570c 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -55,7 +55,9 @@
async_await_syntax_test/d10a: CompileTimeError # Issue 21404
[ $compiler == none || ($compiler == dart2dart && $builder_tag != new_backend) ]
+async_throw_in_catch_test: Crash # Issue 22445, 22446
compile_time_constant_c_test/01: Fail # Issue 21000
+asyncstar_throw_in_catch_test: CompileTimeError # Issue 21404
async_await_syntax_test/a03a: CompileTimeError # Issue 21404
async_await_syntax_test/a03b: CompileTimeError # Issue 21404
async_await_syntax_test/a11d: CompileTimeError # Issue 21404
@@ -66,6 +68,8 @@
sync_generator3_test/test2: Fail # Issue 22300
[ $compiler == none && ($runtime == drt || $runtime == dartium|| $runtime == ContentShellOnAndroid) ]
+async_throw_in_catch_test: Timeout # Issue 22445, 22446
+asyncstar_throw_in_catch_test: RuntimeError # Issue 21404
async_await_syntax_test/a03a: RuntimeError # Issue 21404
async_await_syntax_test/a03b: RuntimeError # Issue 21404
async_await_syntax_test/a09a: RuntimeError # Issue 21404
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index 357491a..67fe963 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -3,9 +3,13 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dartanalyzer ]
-
+async_return_types_test/wrongTypeParameter: MissingStaticWarning # Issue 22410
+async_return_types_test/wrongReturnType: MissingStaticWarning # Issue 22410
+async_return_types_test/nestedFuture: MissingStaticWarning # Issue 22410
await_backwards_compatibility_test/none: CompileTimeError # Issue 22052
await_test: CompileTimeError # Issue 22052
+asyncstar_yield_test: StaticWarning # Issue 22411
+sync_generator1_test/01: MissingStaticWarning # Issue 22412
sync_generator2_test/01: MissingCompileTimeError # Issue 22252
sync_generator2_test/02: MissingCompileTimeError # Issue 22252
@@ -26,6 +30,7 @@
async_await_syntax_test/a10a: MissingStaticWarning
async_await_syntax_test/b10a: MissingStaticWarning
async_await_syntax_test/c10a: MissingStaticWarning
+async_await_syntax_test/d08b: MissingStaticWarning # Issue 22412
async_await_syntax_test/d10a: MissingStaticWarning
# Runtime negative test. No static errors or warnings.
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 40de933..8048046 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -2,10 +2,6 @@
# 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.
-[ $compiler == dart2js && $checked ]
-await_future_test: RuntimeError # Issue 22332
-async_test/none: RuntimeError # Issue 22332
-
[ $compiler == dart2js ]
syncstar_yield_test/copyParameters: RuntimeError # Issue 22322
sync_generator2_test/07: MissingCompileTimeError # Issue 22324
@@ -194,6 +190,7 @@
label_test: Skip
[ $compiler == dart2dart && $builder_tag == new_backend ]
+asyncstar_throw_in_catch_test: CompileTimeError # Issue 21404
await_for_test: RuntimeError # Issue 22051
await_regression_test: RuntimeError # Issue 22051
async_await_syntax_test/a06a: RuntimeError # Issue 22051
diff --git a/tests/language/sync_generator3_test.dart b/tests/language/sync_generator3_test.dart
index d84275e..a993a27 100644
--- a/tests/language/sync_generator3_test.dart
+++ b/tests/language/sync_generator3_test.dart
@@ -34,14 +34,12 @@
}
test2() {
- var s;
- try {
- s = g().toString();
- } catch (e) {
- Expect.equals("pow!", e);
- Expect.equals("(a, b)", s);
- print(s);
- }
+ Iterator i = g().iterator;
+ Expect.isTrue(i.moveNext());
+ Expect.equals("a", i.current);
+ Expect.isTrue(i.moveNext());
+ Expect.equals("b", i.current);
+ Expect.throws(() => i.moveNext(), (error) => error == "pow!");
}
main() {
diff --git a/tests/standalone/io/http_bind_test.dart b/tests/standalone/io/http_bind_test.dart
new file mode 100644
index 0000000..a399b19
--- /dev/null
+++ b/tests/standalone/io/http_bind_test.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2013, 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 'dart:convert';
+
+import 'package:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+
+testBindShared(String host, bool v6Only) async {
+ asyncStart();
+
+ // Sent a single request using a new HttpClient to ensure a new TCP
+ // connnection is used.
+ Future singleRequest(host, port, statusCode) async {
+ var client = new HttpClient();
+ var request = await client.open('GET', host, port, '/');
+ var response = await request.close();
+ await response.drain();
+ Expect.equals(statusCode, response.statusCode);
+ client.close(force: true);
+ }
+
+ Completer server1Request = new Completer();
+ Completer server2Request = new Completer();
+
+ var server1 = await HttpServer.bind(host, 0, v6Only: v6Only, shared: true);
+ var port = server1.port;
+ Expect.isTrue(port > 0);
+
+ var server2 = await HttpServer.bind(host, port, v6Only: v6Only, shared: true);
+ Expect.equals(server1.address.address, server2.address.address);
+ Expect.equals(port, server2.port);
+
+ server1.listen((request) {
+ server1Request.complete();
+ request.response.statusCode = 501;
+ request.response.close();
+ });
+
+ await singleRequest(host, port, 501);
+ await server1.close();
+
+ server2.listen((request) {
+ server2Request.complete();
+ request.response.statusCode = 502;
+ request.response.close();
+ });
+
+ await singleRequest(host, port, 502);
+ await server2.close();
+
+ await server1Request.future;
+ await server2Request.future;
+
+ asyncEnd();
+}
+
+void main() {
+ for (var host in ['127.0.0.1', '::1']) {
+ testBindShared(host, false);
+ testBindShared(host, true);
+ }
+}
diff --git a/tools/VERSION b/tools/VERSION
index 9130654..d7305aa 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
MINOR 9
PATCH 0
PRERELEASE 8
-PRERELEASE_PATCH 2
+PRERELEASE_PATCH 3