anchor.diff:                new Future<CompilerContext>.value(context),
             errorOnMissingInput: false);
     context.disableColors();
  -  return new TypePromotionLookAheadContext(context);
  +  return new TypePromotionLookAheadContext(
  +      context, environment["updateExpectations"] == "true");
   }
   
   class TypePromotionLookAheadContext extends ChainContext {
     final CompilerContext context;
  +
     final List<Step> steps = const <Step>[
       const Read(),
       const Scan(),
  -    const TypePromotionLookAheadStep()
  +    const TypePromotionLookAheadStep(),
  +    const CheckTypePromotionResult(),
     ];
   
  -  TypePromotionLookAheadContext(this.context);
  -}
  -
  -class TypePromotionLookAheadStep
  -    extends Step<ScannedFile, Null, TypePromotionLookAheadContext> {
  +  final bool updateExpectations;
  +
  +  final ExpectationSet expectationSet =
  +      new ExpectationSet.fromJsonList(jsonDecode(EXPECTATIONS));
  +
  +  TypePromotionLookAheadContext(this.context, this.updateExpectations);
  +
  +  Expectation get expectationFileMismatch =>
  +      expectationSet["ExpectationFileMismatch"];
  +
  +  Expectation get expectationFileMissing =>
  +      expectationSet["ExpectationFileMissing"];
  +}
  +
  +class TypePromotionLookAheadStep extends Step<ScannedFile, TypePromotionResult,
  +    TypePromotionLookAheadContext> {
     const TypePromotionLookAheadStep();
   
     String get name => "Type Promotion Look Ahead";
   
  -  Future<Result<Null>> run(
  +  Future<Result<TypePromotionResult>> run(
         ScannedFile file, TypePromotionLookAheadContext context) async {
       return context.context
  -        .runInContext<Result<Null>>((CompilerContext c) async {
  -      c.uriToSource[file.file.uri] =
  -          new Source(file.result.lineStarts, file.file.bytes);
  -      Parser parser = new Parser(new TestListener(file.file.uri));
  +        .runInContext<Result<TypePromotionResult>>((CompilerContext c) async {
  +      Uri uri = file.file.uri;
  +      c.uriToSource[uri] = new Source(file.result.lineStarts, file.file.bytes);
  +      StringBuffer buffer = new StringBuffer();
  +      Parser parser = new Parser(new TestListener(uri, buffer));
         try {
           parser.parseUnit(file.result.tokens);
         } finally {
  -        c.uriToSource.remove(file.file.uri);
  -      }
  -      return pass(null);
  +        c.uriToSource.remove(uri);
  +      }
  +      return pass(new TypePromotionResult(uri, "$buffer"));
       });
     }
   }
   
   class TestState extends TypePromotionState {
  -  TestState(Uri uri) : super(uri);
  +  final StringBuffer buffer;
  +
  +  TestState(Uri uri, this.buffer) : super(uri);
  +
  +  void note(String message, Token token) {
  +    buffer.writeln(CompilerContext.current.format(
  +        debugMessage(message, uri, token.charOffset, token.lexeme.length),
  +        Severity.context));
  +  }
   
     @override
     void checkEmpty(Token token) {
  
positive.code: 
    @override
    void registerWrite(UnspecifiedDeclaration declaration, Token token) {
      trace("Write to ${declaration.name}", token);
    }
  
    @override
    void registerPromotionCandidate(
        UnspecifiedDeclaration declaration, Token token) {
      trace("Possible promotion of ${declaration.name}", token);
    }
  
    @override
  
negative.code:   String toString() => "<<$name@$charOffset>>";
  }
  
  class TypePromotionResult {
    final Uri uri;
  
    final String trace;
  
    const TypePromotionResult(this.uri, this.trace);
  }
  
  class CheckTypePromotionResult
      extends Step<TypePromotionResult, Null, TypePromotionLookAheadContext> {
    const CheckTypePromotionResult();
  
    String get name => "Check Type Promotion Result";
  
    Future<Result<Null>> run(
        TypePromotionResult result, TypePromotionLookAheadContext context) async {
      Uri uri = result.uri;
      String actual = result.trace.trim();
      if (actual.isNotEmpty) {
        actual += "\n";
      }
      File expectedFile = new File("${uri.toFilePath()}.type_promotion.expect");
      if (await expectedFile.exists()) {
        String expected = await expectedFile.readAsString();
        if (expected != actual) {
          if (context.updateExpectations) {
            return updateExpectationFile(expectedFile.uri, actual);
          }
          String diff = await runDiff(expectedFile.uri, actual);
          return new Result<Null>(null, context.expectationFileMismatch,
              "$uri doesn't match ${expectedFile.uri}\n$diff", null);
        }
        return pass(null);
      } else {
        if (actual.isEmpty) return pass(null);
        if (context.updateExpectations) {
          return updateExpectationFile(expectedFile.uri, actual);
        }
        return new Result<Null>(
            null,
            context.expectationFileMissing,
            """
  Please create file ${expectedFile.path} with this content:
  $actual""",
            null);
      }
    }
  
    Future<Result<Null>> updateExpectationFile(Uri uri, String actual) async {
      if (actual.isEmpty) {
        await new File.fromUri(uri).delete();
      } else {
        await openWrite(uri, (IOSink sink) {
          sink.write(actual);
        });
      }
      return pass(null);
    }
  }
  
  main([List<String> arguments = const []]) =>
      runMe(arguments, createContext, "../../testing.json");
  