diff --git a/pkg/async_helper/lib/async_helper.dart b/pkg/async_helper/lib/async_helper.dart index f1a84b369f7..72a391f03a0 100644 --- a/pkg/async_helper/lib/async_helper.dart +++ b/pkg/async_helper/lib/async_helper.dart @@ -61,3 +61,8 @@ void asyncEnd() { print('unittest-suite-success'); } } + +void asyncTest(Future f()) { + asyncStart(); + f().whenComplete(() => asyncEnd()); +} \ No newline at end of file diff --git a/sdk/lib/_internal/compiler/compiler.dart b/sdk/lib/_internal/compiler/compiler.dart index abeb36c4594..215f248749e 100644 --- a/sdk/lib/_internal/compiler/compiler.dart +++ b/sdk/lib/_internal/compiler/compiler.dart @@ -92,19 +92,21 @@ Future compile(Uri script, libraryRoot, packageRoot, options); - compiler.run(script); - String code = compiler.assembledCode; - if (code != null && outputProvider != null) { - String outputType = 'js'; - if (options.contains('--output-type=dart')) { - outputType = 'dart'; + // TODO(ahe): Use the value of the future (which signals success or failure). + return compiler.run(script).then((_) { + String code = compiler.assembledCode; + if (code != null && outputProvider != null) { + String outputType = 'js'; + if (options.contains('--output-type=dart')) { + outputType = 'dart'; + } + outputProvider('', outputType) + ..add(code) + ..close(); + code = ''; // Non-null signals success. } - outputProvider('', outputType) - ..add(code) - ..close(); - code = ''; // Non-null signals success. - } - return new Future.value(code); + return code; + }); } /** diff --git a/sdk/lib/_internal/compiler/implementation/apiimpl.dart b/sdk/lib/_internal/compiler/implementation/apiimpl.dart index b15631a731f..d211e9415c0 100644 --- a/sdk/lib/_internal/compiler/implementation/apiimpl.dart +++ b/sdk/lib/_internal/compiler/implementation/apiimpl.dart @@ -133,12 +133,10 @@ class Compiler extends leg.Compiler { return "lib/$path"; } - elements.LibraryElement scanBuiltinLibrary(String path) { + Future scanBuiltinLibrary(String path) { Uri uri = libraryRoot.resolve(lookupLibraryPath(path)); Uri canonicalUri = new Uri(scheme: "dart", path: path); - elements.LibraryElement library = - libraryLoader.loadLibrary(uri, null, canonicalUri); - return library; + return libraryLoader.loadLibrary(uri, null, canonicalUri); } void log(message) { @@ -157,30 +155,37 @@ class Compiler extends leg.Compiler { /** * Reads the script designated by [readableUri]. */ - leg.Script readScript(Uri readableUri, [tree.Node node]) { + Future readScript(Uri readableUri, + [elements.Element element, tree.Node node]) { if (!readableUri.isAbsolute) { internalError('Relative uri $readableUri provided to readScript(Uri)', node: node); } - return fileReadingTask.measure(() { - Uri resourceUri = translateUri(readableUri, node); - String text = ""; - try { - // TODO(ahe): We expect the future to be complete and call value - // directly. In effect, we don't support truly asynchronous API. - text = deprecatedFutureValue(provider(resourceUri)); - } catch (exception) { + + // TODO(johnniwinther): Add [:report(..., {Element element}):] to + // report methods in Compiler. + void reportReadError(String exception) { + withCurrentElement(element, () { reportError(node, leg.MessageKind.READ_SCRIPT_ERROR, {'uri': readableUri, 'exception': exception}); - return null; - } + }); + } + + Uri resourceUri = translateUri(readableUri, node); + // TODO(johnniwinther): Wrap the result from [provider] in a specialized + // [Future] to ensure that we never execute an asynchronous action without setting + // up the current element of the compiler. + return new Future.sync(() => provider(resourceUri)).then((String text) { SourceFile sourceFile = new SourceFile(resourceUri.toString(), text); // We use [readableUri] as the URI for the script since need to preserve // the scheme in the script because [Script.uri] is used for resolving // relative URIs mentioned in the script. See the comment on // [LibraryLoader] for more details. return new leg.Script(readableUri, sourceFile); + }).catchError((error) { + reportReadError(error); + return null; }); } @@ -254,18 +259,19 @@ class Compiler extends leg.Compiler { return packageRoot.resolve(uri.path); } - bool run(Uri uri) { + Future run(Uri uri) { log('Allowed library categories: $allowedLibraryCategories'); - bool success = super.run(uri); - int cumulated = 0; - for (final task in tasks) { - cumulated += task.timing; - log('${task.name} took ${task.timing}msec'); - } - int total = totalCompileTime.elapsedMilliseconds; - log('Total compile-time ${total}msec;' - ' unaccounted ${total - cumulated}msec'); - return success; + return super.run(uri).then((bool success) { + int cumulated = 0; + for (final task in tasks) { + cumulated += task.timing; + log('${task.name} took ${task.timing}msec'); + } + int total = totalCompileTime.elapsedMilliseconds; + log('Total compile-time ${total}msec;' + ' unaccounted ${total - cumulated}msec'); + return success; + }); } void reportDiagnostic(leg.SourceSpan span, String message, diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart index 7e543d0ca65..158bb57edb1 100644 --- a/sdk/lib/_internal/compiler/implementation/compiler.dart +++ b/sdk/lib/_internal/compiler/implementation/compiler.dart @@ -36,7 +36,6 @@ abstract class WorkItem { assert(invariant(element, element.isDeclaration)); } - void run(Compiler compiler, Enqueuer world); } @@ -81,11 +80,6 @@ class PostProcessTask { PostProcessTask(this.element, this.action); } -class ReadingFilesTask extends CompilerTask { - ReadingFilesTask(Compiler compiler) : super(compiler); - String get name => 'Reading input files'; -} - abstract class Backend { final Compiler compiler; final ConstantSystem constantSystem; @@ -253,7 +247,9 @@ abstract class Backend { void registerStaticUse(Element element, Enqueuer enqueuer) {} - void onLibraryLoaded(LibraryElement library, Uri uri) {} + Future onLibraryLoaded(LibraryElement library, Uri uri) { + return new Future.value(); + } void registerMetadataInstantiatedType(DartType type, TreeElements elements) {} void registerMetadataStaticUse(Element element) {} @@ -512,7 +508,6 @@ abstract class Compiler implements DiagnosticListener { ConstantHandler constantHandler; ConstantHandler metadataHandler; EnqueueTask enqueuer; - CompilerTask fileReadingTask; DeferredLoadTask deferredLoadTask; MirrorUsageAnalyzerTask mirrorUsageAnalyzerTask; ContainerTracer containerTracer; @@ -614,7 +609,6 @@ abstract class Compiler implements DiagnosticListener { validator = new TreeValidatorTask(this); tasks = [ - fileReadingTask = new ReadingFilesTask(this), libraryLoader = new LibraryLoaderTask(this), scanner = new ScannerTask(this), dietParser = new DietParserTask(this), @@ -731,14 +725,15 @@ abstract class Compiler implements DiagnosticListener { reportDiagnostic(null, message, api.Diagnostic.VERBOSE_INFO); } - bool run(Uri uri) { + Future run(Uri uri) { totalCompileTime.start(); - try { - runCompiler(uri); - } on CompilerCancelledException catch (exception) { - log('Error: $exception'); - return false; - } catch (exception) { + + return new Future.sync(() => runCompiler(uri)).catchError((error) { + if (error is CompilerCancelledException) { + log('Error: $error'); + return false; + } + try { if (!hasCrashed) { hasCrashed = true; @@ -750,12 +745,13 @@ abstract class Compiler implements DiagnosticListener { } catch (doubleFault) { // Ignoring exceptions in exception handling. } - rethrow; - } finally { + throw error; + }).whenComplete(() { tracer.close(); totalCompileTime.stop(); - } - return !compilationFailed; + }).then((_) { + return !compilationFailed; + }); } bool hasIsolateSupport() => isolateLibrary != null; @@ -764,7 +760,7 @@ abstract class Compiler implements DiagnosticListener { * This method is called before [library] import and export scopes have been * set up. */ - void onLibraryLoaded(LibraryElement library, Uri uri) { + Future onLibraryLoaded(LibraryElement library, Uri uri) { if (dynamicClass != null) { // When loading the built-in libraries, dynamicClass is null. We // take advantage of this as core imports js_helper and sees [dynamic] @@ -791,12 +787,12 @@ abstract class Compiler implements DiagnosticListener { findRequiredElement(library, const SourceString('DeferredLibrary')); } else if (isolateHelperLibrary == null && (uri == new Uri(scheme: 'dart', path: '_isolate_helper'))) { - isolateHelperLibrary = scanBuiltinLibrary('_isolate_helper'); + isolateHelperLibrary = library; } else if (foreignLibrary == null && (uri == new Uri(scheme: 'dart', path: '_foreign_helper'))) { - foreignLibrary = scanBuiltinLibrary('_foreign_helper'); + foreignLibrary = library; } - backend.onLibraryLoaded(library, uri); + return backend.onLibraryLoaded(library, uri); } Element findRequiredElement(LibraryElement library, SourceString name) { @@ -824,7 +820,7 @@ abstract class Compiler implements DiagnosticListener { } } - LibraryElement scanBuiltinLibrary(String filename); + Future scanBuiltinLibrary(String filename); void initializeSpecialClasses() { final List missingCoreClasses = []; @@ -902,26 +898,32 @@ abstract class Compiler implements DiagnosticListener { listClass.lookupConstructor(callConstructor); } - void scanBuiltinLibraries() { - jsHelperLibrary = scanBuiltinLibrary('_js_helper'); - interceptorsLibrary = scanBuiltinLibrary('_interceptors'); - assertMethod = jsHelperLibrary.find(const SourceString('assertHelper')); - identicalFunction = coreLibrary.find(const SourceString('identical')); + Future scanBuiltinLibraries() { + return scanBuiltinLibrary('_js_helper').then((LibraryElement library) { + jsHelperLibrary = library; + return scanBuiltinLibrary('_interceptors'); + }).then((LibraryElement library) { + interceptorsLibrary = library; - initializeSpecialClasses(); + assertMethod = jsHelperLibrary.find(const SourceString('assertHelper')); + identicalFunction = coreLibrary.find(const SourceString('identical')); - functionClass.ensureResolved(this); - functionApplyMethod = - functionClass.lookupLocalMember(const SourceString('apply')); - jsInvocationMirrorClass.ensureResolved(this); - invokeOnMethod = jsInvocationMirrorClass.lookupLocalMember(INVOKE_ON); + initializeSpecialClasses(); - if (preserveComments) { - var uri = new Uri(scheme: 'dart', path: 'mirrors'); - LibraryElement libraryElement = - libraryLoader.loadLibrary(uri, null, uri); - documentClass = libraryElement.find(const SourceString('Comment')); - } + functionClass.ensureResolved(this); + functionApplyMethod = + functionClass.lookupLocalMember(const SourceString('apply')); + jsInvocationMirrorClass.ensureResolved(this); + invokeOnMethod = jsInvocationMirrorClass.lookupLocalMember(INVOKE_ON); + + if (preserveComments) { + var uri = new Uri(scheme: 'dart', path: 'mirrors'); + return libraryLoader.loadLibrary(uri, null, uri).then( + (LibraryElement libraryElement) { + documentClass = libraryElement.find(const SourceString('Comment')); + }); + } + }); } void importHelperLibrary(LibraryElement library) { @@ -936,28 +938,39 @@ abstract class Compiler implements DiagnosticListener { */ Uri resolvePatchUri(String dartLibraryPath); - void runCompiler(Uri uri) { + Future runCompiler(Uri uri) { // TODO(ahe): This prevents memory leaks when invoking the compiler // multiple times. Implement a better mechanism where StringWrapper // instances are shared on a per library basis. SourceString.canonicalizedValues.clear(); assert(uri != null || analyzeOnly); - scanBuiltinLibraries(); - if (librariesToAnalyzeWhenRun != null) { - for (Uri libraryUri in librariesToAnalyzeWhenRun) { - log('analyzing $libraryUri ($buildId)'); - libraryLoader.loadLibrary(libraryUri, null, libraryUri); + return scanBuiltinLibraries().then((_) { + if (librariesToAnalyzeWhenRun != null) { + return Future.forEach(librariesToAnalyzeWhenRun, (libraryUri) { + log('analyzing $libraryUri ($buildId)'); + return libraryLoader.loadLibrary(libraryUri, null, libraryUri); + }); } - } - if (uri != null) { - if (analyzeOnly) { - log('analyzing $uri ($buildId)'); - } else { - log('compiling $uri ($buildId)'); + }).then((_) { + if (uri != null) { + if (analyzeOnly) { + log('analyzing $uri ($buildId)'); + } else { + log('compiling $uri ($buildId)'); + } + return libraryLoader.loadLibrary(uri, null, uri) + .then((LibraryElement library) { + mainApp = library; + }); } - mainApp = libraryLoader.loadLibrary(uri, null, uri); - } + }).then((_) { + compileLoadedLibraries(); + }); + } + + /// Performs the compilation when all libraries have been loaded. + void compileLoadedLibraries() { Element main = null; if (mainApp != null) { main = mainApp.find(MAIN); @@ -973,8 +986,8 @@ abstract class Compiler implements DiagnosticListener { mainApp, MessageKind.GENERIC, {'text': 'Error: Could not find "${MAIN.slowToString()}". ' - 'No source will be analyzed. ' - 'Use "--analyze-all" to analyze all code in the library.'}); + 'No source will be analyzed. ' + 'Use "--analyze-all" to analyze all code in the library.'}); } } else { if (!main.isFunction()) { @@ -990,7 +1003,7 @@ abstract class Compiler implements DiagnosticListener { parameter, MessageKind.GENERIC, {'text': - 'Error: "${MAIN.slowToString()}" cannot have parameters.'}); + 'Error: "${MAIN.slowToString()}" cannot have parameters.'}); }); } @@ -1046,7 +1059,8 @@ abstract class Compiler implements DiagnosticListener { backend.enableNoSuchMethod(enqueuer.codegen); } if (compileAll) { - libraries.forEach((_, lib) => fullyEnqueueLibrary(lib, enqueuer.codegen)); + libraries.forEach((_, lib) => fullyEnqueueLibrary(lib, + enqueuer.codegen)); } processQueue(enqueuer.codegen, main); enqueuer.codegen.logSummary(log); @@ -1373,7 +1387,7 @@ abstract class Compiler implements DiagnosticListener { * * See [LibraryLoader] for terminology on URIs. */ - Script readScript(Uri readableUri, [Node node]) { + Future