CompilerContext always expects a Future now

This change is made because we were incorrectly calling
CompilerContext.clear *before* running the main compilation
task which is async.

Change-Id: I7181af33fe733e5bc653fa742b9e06782f4278d0
Reviewed-on: https://dart-review.googlesource.com/58201
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
Reviewed-by: Dan Rubel <danrubel@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/test/generated/parser_forest_test.dart b/pkg/analyzer/test/generated/parser_forest_test.dart
index b1b4491..e428f1c 100644
--- a/pkg/analyzer/test/generated/parser_forest_test.dart
+++ b/pkg/analyzer/test/generated/parser_forest_test.dart
@@ -9,16 +9,18 @@
 import 'parser_test.dart';
 
 main() async {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(ClassMemberParserTest_Forest);
-    defineReflectiveTests(ComplexParserTest_Forest);
-    defineReflectiveTests(ErrorParserTest_Forest);
-    defineReflectiveTests(ExpressionParserTest_Forest);
-    defineReflectiveTests(FormalParameterParserTest_Forest);
-    defineReflectiveTests(RecoveryParserTest_Forest);
-    defineReflectiveTests(SimpleParserTest_Forest);
-    defineReflectiveTests(StatementParserTest_Forest);
-    defineReflectiveTests(TopLevelParserTest_Forest);
+  await CompilerTestContext.runWithTestOptions((_) {
+    defineReflectiveSuite(() {
+      defineReflectiveTests(ClassMemberParserTest_Forest);
+      defineReflectiveTests(ComplexParserTest_Forest);
+      defineReflectiveTests(ErrorParserTest_Forest);
+      defineReflectiveTests(ExpressionParserTest_Forest);
+      defineReflectiveTests(FormalParameterParserTest_Forest);
+      defineReflectiveTests(RecoveryParserTest_Forest);
+      defineReflectiveTests(SimpleParserTest_Forest);
+      defineReflectiveTests(StatementParserTest_Forest);
+      defineReflectiveTests(TopLevelParserTest_Forest);
+    });
   });
 }
 
diff --git a/pkg/analyzer/test/src/fasta/body_builder_test_helper.dart b/pkg/analyzer/test/src/fasta/body_builder_test_helper.dart
index fc243e5..827a00a 100644
--- a/pkg/analyzer/test/src/fasta/body_builder_test_helper.dart
+++ b/pkg/analyzer/test/src/fasta/body_builder_test_helper.dart
@@ -40,27 +40,125 @@
 import '../../generated/parser_test.dart';
 import '../../generated/test_support.dart';
 
+Element _buildElement(kernel.Class coreType) {
+  ClassElementImpl element =
+      new ClassElementImpl(coreType.name, coreType.fileOffset);
+  element.typeParameters = coreType.typeParameters.map((parameter) {
+    TypeParameterElementImpl element =
+        new TypeParameterElementImpl(parameter.name, parameter.fileOffset);
+    element.type = new TypeParameterTypeImpl(element);
+    return element;
+  }).toList();
+  return element;
+}
+
+class CompilerTestContext extends CompilerContext {
+  KernelTarget kernelTarget;
+  TypeProvider _typeProvider;
+
+  CompilerTestContext(ProcessedOptions options) : super(options);
+
+  Uri get entryPoint => options.inputs.single;
+
+  static Future<T> runWithTestOptions<T>(
+      Future<T> action(CompilerTestContext c)) async {
+    // TODO(danrubel): Consider HybridFileSystem.
+    final MemoryFileSystem fs =
+        new MemoryFileSystem(Uri.parse("org-dartlang-test:///"));
+
+    /// The custom URI used to locate the dill file in the MemoryFileSystem.
+    final Uri sdkSummary = fs.currentDirectory.resolve("vm_platform.dill");
+
+    /// The in memory test code URI
+    final Uri entryPoint = fs.currentDirectory.resolve("main.dart");
+
+    // Read the dill file containing kernel platform summaries into memory.
+    List<int> sdkSummaryBytes = await new File.fromUri(
+            computePlatformBinariesLocation().resolve("vm_platform.dill"))
+        .readAsBytes();
+    fs.entityForUri(sdkSummary).writeAsBytesSync(sdkSummaryBytes);
+
+    final CompilerOptions optionBuilder = new CompilerOptions()
+      ..strongMode = false // TODO(danrubel): enable strong mode.
+      ..reportMessages = true
+      ..verbose = false
+      ..fileSystem = fs
+      ..sdkSummary = sdkSummary
+      ..onProblem = (FormattedMessage problem, Severity severity,
+          List<FormattedMessage> context) {
+        // TODO(danrubel): Capture problems and check against expectations.
+//        print(problem.formatted);
+      };
+
+    final ProcessedOptions options =
+        new ProcessedOptions(optionBuilder, [entryPoint]);
+
+    UriTranslatorImpl uriTranslator = await options.getUriTranslator();
+
+    return await new CompilerTestContext(options)
+        .runInContext<T>((CompilerContext _c) async {
+      CompilerTestContext c = _c;
+      DillTarget dillTarget = new DillTarget(
+          new Ticker(isVerbose: false), uriTranslator, options.target);
+
+      c.kernelTarget = new KernelTarget(fs, true, dillTarget, uriTranslator);
+
+      // Load the dill file containing platform code.
+      dillTarget.loader.read(Uri.parse('dart:core'), -1, fileUri: sdkSummary);
+      kernel.Component sdkComponent =
+          kernel.loadComponentFromBytes(sdkSummaryBytes);
+      dillTarget.loader
+          .appendLibraries(sdkComponent, byteCount: sdkSummaryBytes.length);
+      await dillTarget.buildOutlines();
+      await c.kernelTarget.buildOutlines();
+      c.kernelTarget.computeCoreTypes();
+      assert(c.kernelTarget.loader.coreTypes != null);
+
+      // Initialize the typeProvider if types should be resolved.
+      Map<String, Element> map = <String, Element>{};
+      var coreTypes = c.kernelTarget.loader.coreTypes;
+      for (var coreType in [
+        coreTypes.boolClass,
+        coreTypes.doubleClass,
+        coreTypes.functionClass,
+        coreTypes.futureClass,
+        coreTypes.futureOrClass,
+        coreTypes.intClass,
+        coreTypes.iterableClass,
+        coreTypes.iteratorClass,
+        coreTypes.listClass,
+        coreTypes.mapClass,
+        coreTypes.nullClass,
+        coreTypes.numClass,
+        coreTypes.objectClass,
+        coreTypes.stackTraceClass,
+        coreTypes.streamClass,
+        coreTypes.stringClass,
+        coreTypes.symbolClass,
+        coreTypes.typeClass
+      ]) {
+        map[coreType.name] = _buildElement(coreType);
+      }
+      Namespace namespace = new Namespace(map);
+      c._typeProvider =
+          new TypeProviderImpl.forNamespaces(namespace, namespace);
+
+      T result;
+      Completer<T> completer = new Completer<T>();
+      tearDownAll(() => completer.complete(result));
+      result = await action(c);
+      return completer.future;
+    });
+  }
+
+  static CompilerTestContext get current => CompilerContext.current;
+}
+
 /// Implementation of [AbstractParserTestCase] specialized for testing building
 /// Analyzer AST using the fasta [Forest] API.
 class FastaBodyBuilderTestCase extends Object
     with ParserTestHelpers
     implements AbstractParserTestCase {
-  // TODO(danrubel): Consider HybridFileSystem.
-  static final MemoryFileSystem fs =
-      new MemoryFileSystem(Uri.parse("org-dartlang-test:///"));
-
-  /// The custom URI used to locate the dill file in the MemoryFileSystem.
-  static final Uri sdkSummary = fs.currentDirectory.resolve("vm_platform.dill");
-
-  /// The in memory test code URI
-  static final Uri entryPoint = fs.currentDirectory.resolve("main.dart");
-
-  static ProcessedOptions options;
-
-  static KernelTarget kernelTarget;
-
-  static TypeProvider _typeProvider;
-
   final bool resolveTypes;
 
   String content;
@@ -73,7 +171,7 @@
 
   analyzer.Parser get parser => new ParserProxy(this);
 
-  TypeProvider get typeProvider => _typeProvider;
+  TypeProvider get typeProvider => CompilerTestContext.current._typeProvider;
 
   @override
   void assertNoErrors() {
@@ -396,156 +494,68 @@
     return statement.variables;
   }
 
-  Future setUp() async {
-    // TODO(danrubel): Tear down once all tests in group have been run.
-    if (options != null) {
-      return;
-    }
-
-    // Read the dill file containing kernel platform summaries into memory.
-    List<int> sdkSummaryBytes = await new File.fromUri(
-            computePlatformBinariesLocation().resolve("vm_platform.dill"))
-        .readAsBytes();
-    fs.entityForUri(sdkSummary).writeAsBytesSync(sdkSummaryBytes);
-
-    final CompilerOptions optionBuilder = new CompilerOptions()
-      ..strongMode = false // TODO(danrubel): enable strong mode.
-      ..reportMessages = true
-      ..verbose = false
-      ..fileSystem = fs
-      ..sdkSummary = sdkSummary
-      ..onProblem = (FormattedMessage problem, Severity severity,
-          List<FormattedMessage> context) {
-        // TODO(danrubel): Capture problems and check against expectations.
-//        print(problem.formatted);
-      };
-
-    options = new ProcessedOptions(optionBuilder, [entryPoint]);
-
-    UriTranslatorImpl uriTranslator = await options.getUriTranslator();
-
-    await CompilerContext.runWithOptions(options, (CompilerContext c) async {
-      DillTarget dillTarget = new DillTarget(
-          new Ticker(isVerbose: false), uriTranslator, options.target);
-
-      kernelTarget = new KernelTarget(fs, true, dillTarget, uriTranslator);
-
-      // Load the dill file containing platform code.
-      dillTarget.loader.read(Uri.parse('dart:core'), -1, fileUri: sdkSummary);
-      kernel.Component sdkComponent =
-          kernel.loadComponentFromBytes(sdkSummaryBytes);
-      dillTarget.loader
-          .appendLibraries(sdkComponent, byteCount: sdkSummaryBytes.length);
-      await dillTarget.buildOutlines();
-      await kernelTarget.buildOutlines();
-      kernelTarget.computeCoreTypes();
-      assert(kernelTarget.loader.coreTypes != null);
-
-      // Initialize the typeProvider if types should be resolved.
-      Map<String, Element> map = <String, Element>{};
-      var coreTypes = kernelTarget.loader.coreTypes;
-      for (var coreType in [
-        coreTypes.boolClass,
-        coreTypes.doubleClass,
-        coreTypes.functionClass,
-        coreTypes.futureClass,
-        coreTypes.futureOrClass,
-        coreTypes.intClass,
-        coreTypes.iterableClass,
-        coreTypes.iteratorClass,
-        coreTypes.listClass,
-        coreTypes.mapClass,
-        coreTypes.nullClass,
-        coreTypes.numClass,
-        coreTypes.objectClass,
-        coreTypes.stackTraceClass,
-        coreTypes.streamClass,
-        coreTypes.stringClass,
-        coreTypes.symbolClass,
-        coreTypes.typeClass
-      ]) {
-        map[coreType.name] = _buildElement(coreType);
-      }
-      Namespace namespace = new Namespace(map);
-      _typeProvider = new TypeProviderImpl.forNamespaces(namespace, namespace);
-    });
-  }
-
-  Element _buildElement(kernel.Class coreType) {
-    ClassElementImpl element =
-        new ClassElementImpl(coreType.name, coreType.fileOffset);
-    element.typeParameters = coreType.typeParameters.map((parameter) {
-      TypeParameterElementImpl element =
-          new TypeParameterElementImpl(parameter.name, parameter.fileOffset);
-      element.type = new TypeParameterTypeImpl(element);
-      return element;
-    }).toList();
-    return element;
-  }
-
   T _parse<T>(
       String source, void parseFunction(Parser parser, Token previousToken),
       {bool inAsync: false, bool inCatchBlock: false}) {
     ScannerResult scan = scanString(source);
 
-    return CompilerContext.runWithOptions(options, (CompilerContext c) {
-      KernelLibraryBuilder library = new KernelLibraryBuilder(
-        entryPoint,
-        entryPoint,
-        kernelTarget.loader,
-        null /* actualOrigin */,
-        null /* enclosingLibrary */,
-      );
-      List<KernelTypeVariableBuilder> typeVariableBuilders =
-          <KernelTypeVariableBuilder>[];
-      List<KernelFormalParameterBuilder> formalParameterBuilders =
-          <KernelFormalParameterBuilder>[];
-      KernelProcedureBuilder procedureBuilder = new KernelProcedureBuilder(
-          null /* metadata */,
-          Modifier.staticMask /* or Modifier.varMask */,
-          kernelTarget.dynamicType,
-          "analyzerTest",
-          typeVariableBuilders,
-          formalParameterBuilders,
-          kernel.ProcedureKind.Method,
-          library,
-          -1 /* charOffset */,
-          -1 /* charOpenParenOffset */,
-          -1 /* charEndOffset */);
-
-      TypeInferrerDisabled typeInferrer =
-          new TypeInferrerDisabled(new TypeSchemaEnvironment(
-        kernelTarget.loader.coreTypes,
-        kernelTarget.loader.hierarchy,
-        // TODO(danrubel): Enable strong mode.
-        false /* strong mode */,
-      ));
-
-      AstBodyBuilder builder = new AstBodyBuilder(
+    CompilerTestContext c = CompilerTestContext.current;
+    KernelLibraryBuilder library = new KernelLibraryBuilder(
+      c.entryPoint,
+      c.entryPoint,
+      c.kernelTarget.loader,
+      null /* actualOrigin */,
+      null /* enclosingLibrary */,
+    );
+    List<KernelTypeVariableBuilder> typeVariableBuilders =
+        <KernelTypeVariableBuilder>[];
+    List<KernelFormalParameterBuilder> formalParameterBuilders =
+        <KernelFormalParameterBuilder>[];
+    KernelProcedureBuilder procedureBuilder = new KernelProcedureBuilder(
+        null /* metadata */,
+        Modifier.staticMask /* or Modifier.varMask */,
+        c.kernelTarget.dynamicType,
+        "analyzerTest",
+        typeVariableBuilders,
+        formalParameterBuilders,
+        kernel.ProcedureKind.Method,
         library,
-        procedureBuilder,
-        new UnlinkedScope(),
-        null,
-        kernelTarget.loader.hierarchy,
-        kernelTarget.loader.coreTypes,
-        null /* classBuilder */,
-        false /* isInstanceMember */,
-        null /* uri */,
-        typeInferrer,
-        typeProvider,
-      )..constantContext = ConstantContext.none; // .inferred ?
+        -1 /* charOffset */,
+        -1 /* charOpenParenOffset */,
+        -1 /* charEndOffset */);
 
-      Parser parser = new Parser(builder);
-      if (inAsync) {
-        parser.asyncState = AsyncModifier.Async;
-      }
-      if (inCatchBlock) {
-        builder.inCatchBlock = inCatchBlock;
-      }
-      parseFunction(parser, parser.syntheticPreviousToken(scan.tokens));
-      // TODO(brianwilkerson) Check `expectedEndOffset` if it is not `null`.
-      return builder.pop();
-    });
+    TypeInferrerDisabled typeInferrer =
+        new TypeInferrerDisabled(new TypeSchemaEnvironment(
+      c.kernelTarget.loader.coreTypes,
+      c.kernelTarget.loader.hierarchy,
+      // TODO(danrubel): Enable strong mode.
+      false /* strong mode */,
+    ));
+
+    AstBodyBuilder builder = new AstBodyBuilder(
+      library,
+      procedureBuilder,
+      new UnlinkedScope(),
+      null,
+      c.kernelTarget.loader.hierarchy,
+      c.kernelTarget.loader.coreTypes,
+      null /* classBuilder */,
+      false /* isInstanceMember */,
+      null /* uri */,
+      typeInferrer,
+      typeProvider,
+    )..constantContext = ConstantContext.none; // .inferred ?
+
+    Parser parser = new Parser(builder);
+    if (inAsync) {
+      parser.asyncState = AsyncModifier.Async;
+    }
+    if (inCatchBlock) {
+      builder.inCatchBlock = inCatchBlock;
+    }
+    parseFunction(parser, parser.syntheticPreviousToken(scan.tokens));
+    // TODO(brianwilkerson) Check `expectedEndOffset` if it is not `null`.
+    return builder.pop();
   }
 }
 
diff --git a/pkg/analyzer/test/src/fasta/resolution_test.dart b/pkg/analyzer/test/src/fasta/resolution_test.dart
index 0eedb6b..9105bf8 100644
--- a/pkg/analyzer/test/src/fasta/resolution_test.dart
+++ b/pkg/analyzer/test/src/fasta/resolution_test.dart
@@ -11,8 +11,10 @@
 import 'body_builder_test_helper.dart';
 
 main() async {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(ResolutionTest);
+  await CompilerTestContext.runWithTestOptions((_) {
+    defineReflectiveSuite(() {
+      defineReflectiveTests(ResolutionTest);
+    });
   });
 }
 
diff --git a/pkg/front_end/lib/src/fasta/compiler_context.dart b/pkg/front_end/lib/src/fasta/compiler_context.dart
index 1795c7e..2eda950 100644
--- a/pkg/front_end/lib/src/fasta/compiler_context.dart
+++ b/pkg/front_end/lib/src/fasta/compiler_context.dart
@@ -4,7 +4,7 @@
 
 library fasta.compiler_context;
 
-import 'dart:async' show Zone, runZoned;
+import 'dart:async' show Future, Zone, runZoned;
 
 import 'package:kernel/ast.dart' show Source;
 
@@ -101,25 +101,23 @@
 
   /// Perform [action] in a [Zone] where [this] will be available as
   /// `CompilerContext.current`.
-  T runInContext<T>(T action(CompilerContext c)) {
-    try {
-      return runZoned(() => action(this),
-          zoneValues: {compilerContextKey: this});
-    } finally {
-      clear();
-    }
+  Future<T> runInContext<T>(Future<T> action(CompilerContext c)) {
+    return runZoned(
+        () => new Future<T>.sync(() => action(this)).whenComplete(clear),
+        zoneValues: {compilerContextKey: this});
   }
 
   /// Perform [action] in a [Zone] where [options] will be available as
   /// `CompilerContext.current.options`.
-  static T runWithOptions<T>(
-      ProcessedOptions options, T action(CompilerContext c)) {
+  static Future<T> runWithOptions<T>(
+      ProcessedOptions options, Future<T> action(CompilerContext c)) {
     return new CompilerContext(options).runInContext(action);
   }
 
-  static T runWithDefaultOptions<T>(T action(CompilerContext c)) {
-    var options = new ProcessedOptions(new CompilerOptions());
-    return new CompilerContext(options).runInContext(action);
+  static Future<T> runWithDefaultOptions<T>(
+      Future<T> action(CompilerContext c)) {
+    return new CompilerContext(new ProcessedOptions(new CompilerOptions()))
+        .runInContext(action);
   }
 
   static bool get enableColors {
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index 0cfc1d8a..2a95602 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -89,7 +89,7 @@
       {Uri entryPoint, bool fullComponent: false}) async {
     ticker.reset();
     entryPoint ??= context.options.inputs.single;
-    return context.runInContext<Future<Component>>((CompilerContext c) async {
+    return context.runInContext<Component>((CompilerContext c) async {
       IncrementalCompilerData data = new IncrementalCompilerData();
 
       bool bypassCache = false;
diff --git a/pkg/front_end/test/fasta/expression_test.dart b/pkg/front_end/test/fasta/expression_test.dart
index ee56f71..91f716e 100644
--- a/pkg/front_end/test/fasta/expression_test.dart
+++ b/pkg/front_end/test/fasta/expression_test.dart
@@ -66,7 +66,7 @@
 
   MemoryFileSystem get fileSystem => options.fileSystem;
 
-  T runInContext<T>(T action(CompilerContext c)) {
+  Future<T> runInContext<T>(Future<T> action(CompilerContext c)) {
     return compilerContext.runInContext<T>(action);
   }
 
diff --git a/pkg/front_end/test/fasta/incremental_test.dart b/pkg/front_end/test/fasta/incremental_test.dart
index 401d89b..d6e5f8d 100644
--- a/pkg/front_end/test/fasta/incremental_test.dart
+++ b/pkg/front_end/test/fasta/incremental_test.dart
@@ -70,7 +70,7 @@
 
   MemoryFileSystem get fileSystem => options.fileSystem;
 
-  T runInContext<T>(T action(CompilerContext c)) {
+  Future<T> runInContext<T>(Future<T> action(CompilerContext c)) {
     return compilerContext.runInContext<T>(action);
   }
 
diff --git a/pkg/front_end/tool/_fasta/compile_platform.dart b/pkg/front_end/tool/_fasta/compile_platform.dart
index 1b47a33..fd26f5f 100644
--- a/pkg/front_end/tool/_fasta/compile_platform.dart
+++ b/pkg/front_end/tool/_fasta/compile_platform.dart
@@ -44,8 +44,8 @@
       await compilePlatform(arguments);
     } on deprecated_InputError catch (e) {
       exitCode = 1;
-      CompilerContext.runWithDefaultOptions(
-          (c) => c.report(deprecated_InputError.toMessage(e), Severity.error));
+      await CompilerContext.runWithDefaultOptions((c) => new Future<void>.sync(
+          () => c.report(deprecated_InputError.toMessage(e), Severity.error)));
       return null;
     }
   }
diff --git a/pkg/front_end/tool/_fasta/entry_points.dart b/pkg/front_end/tool/_fasta/entry_points.dart
index 026bccd..b2a1d8f 100644
--- a/pkg/front_end/tool/_fasta/entry_points.dart
+++ b/pkg/front_end/tool/_fasta/entry_points.dart
@@ -121,8 +121,8 @@
       return await withGlobalOptions("compile", arguments, true,
           (CompilerContext c, _) => batchCompileImpl(c));
     } on deprecated_InputError catch (e) {
-      CompilerContext.runWithDefaultOptions(
-          (c) => c.report(deprecated_InputError.toMessage(e), Severity.error));
+      await CompilerContext.runWithDefaultOptions((c) => new Future<void>.sync(
+          () => c.report(deprecated_InputError.toMessage(e), Severity.error)));
       return false;
     }
   }
@@ -173,8 +173,8 @@
     });
   } on deprecated_InputError catch (e) {
     exitCode = 1;
-    CompilerContext.runWithDefaultOptions(
-        (c) => c.report(deprecated_InputError.toMessage(e), Severity.error));
+    await CompilerContext.runWithDefaultOptions((c) => new Future<void>.sync(
+        () => c.report(deprecated_InputError.toMessage(e), Severity.error)));
     return null;
   }
 }
@@ -192,8 +192,8 @@
     });
   } on deprecated_InputError catch (e) {
     exitCode = 1;
-    CompilerContext.runWithDefaultOptions(
-        (c) => c.report(deprecated_InputError.toMessage(e), Severity.error));
+    await CompilerContext.runWithDefaultOptions((c) => new Future<void>.sync(
+        () => c.report(deprecated_InputError.toMessage(e), Severity.error)));
     return null;
   }
 }