blob: 398f5a146ca9d632047dd6a0a5be38f6bbf53663 [file] [log] [blame]
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:convert' show jsonDecode;
import 'package:front_end/src/base/processed_options.dart'
show ProcessedOptions;
import 'package:front_end/src/fasta/builder/builder.dart' show Builder;
import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
import 'package:front_end/src/fasta/messages.dart'
show LocatedMessage, templateUnspecified;
import 'package:front_end/src/fasta/parser.dart' show Parser;
import 'package:front_end/src/fasta/scanner.dart' show Token;
import 'package:front_end/src/fasta/severity.dart' show Severity;
import 'package:front_end/src/fasta/source/type_promotion_look_ahead_listener.dart'
import 'package:kernel/ast.dart' show Source;
import 'package:testing/testing.dart'
show Chain, ChainContext, ExpectationSet, Future, Result, Step, runMe;
import '../utils/kernel_chain.dart' show MatchContext;
import '../utils/scanner_chain.dart' show Read, Scan, ScannedFile;
const String EXPECTATIONS = '''
"name": "ExpectationFileMismatch",
"group": "Fail"
"name": "ExpectationFileMissing",
"group": "Fail"
Future<ChainContext> createContext(
Chain suite, Map<String, String> environment) async {
CompilerContext context =
await CompilerContext.runWithOptions<CompilerContext>(
new ProcessedOptions(),
(CompilerContext context) =>
new Future<CompilerContext>.value(context),
errorOnMissingInput: false);
return new TypePromotionLookAheadContext(
context, environment["updateExpectations"] == "true");
class TypePromotionLookAheadContext extends ChainContext with MatchContext {
final CompilerContext context;
final List<Step> steps = const <Step>[
const Read(),
const Scan(),
const TypePromotionLookAheadStep(),
const CheckTypePromotionResult(),
final bool updateExpectations;
final ExpectationSet expectationSet =
new ExpectationSet.fromJsonList(jsonDecode(EXPECTATIONS));
TypePromotionLookAheadContext(this.context, this.updateExpectations);
class TypePromotionLookAheadStep extends Step<ScannedFile, TypePromotionResult,
TypePromotionLookAheadContext> {
const TypePromotionLookAheadStep();
String get name => "Type Promotion Look Ahead";
Future<Result<TypePromotionResult>> run(
ScannedFile file, TypePromotionLookAheadContext context) async {
return context.context
.runInContext<Result<TypePromotionResult>>((CompilerContext c) async {
Uri uri = file.file.uri;
c.uriToSource[uri] =
new Source(file.result.lineStarts, file.file.bytes, uri, uri);
StringBuffer buffer = new StringBuffer();
Parser parser = new Parser(new TestListener(uri, buffer));
try {
} finally {
return pass(new TypePromotionResult(uri, "$buffer"));
class TestState extends TypePromotionState {
final StringBuffer buffer;
TestState(Uri uri, this.buffer) : super(uri);
void note(String message, Token token) {
debugMessage(message, uri, token.charOffset, token.lexeme.length),
void checkEmpty(Token token) {
if (stack.isNotEmpty) {
throw CompilerContext.current.format(
debugMessage("Stack not empty", uri, token?.charOffset ?? -1,
token?.length ?? 1),
void declareIdentifier(Token token) {
trace("Declared ${token.lexeme}", token);
Builder nullValue(String name, Token token) {
return new DebugDeclaration(name, uri, token?.charOffset ?? -1);
void registerWrite(UnspecifiedDeclaration declaration, Token token) {
note("Write to ${}@${declaration.charOffset}", token);
void registerPromotionCandidate(
UnspecifiedDeclaration declaration, Token token) {
note("Possible promotion of ${}@${declaration.charOffset}",
void report(LocatedMessage message, Severity severity,
{List<LocatedMessage> context}) {, severity, context: context);
void trace(String message, Token token) {
debugMessage(message, uri, token?.charOffset ?? -1, token?.length ?? 1),
for (Object o in stack) {
String s = " $o";
int index = s.indexOf("\n");
if (index != -1) {
s = s.substring(0, index) + "...";
LocatedMessage debugMessage(String text, Uri uri, int offset, int length) {
return templateUnspecified
.withLocation(uri, offset, length);
class TestListener extends TypePromotionLookAheadListener {
TestListener(Uri uri, StringBuffer buffer)
: super(new TestState(uri, buffer));
void debugEvent(String name, Token token) {
state.trace(name, token);
class DebugDeclaration extends Builder {
final String name;
final Uri fileUri;
int charOffset;
DebugDeclaration(, this.fileUri, this.charOffset);
Builder get parent => null;
String get fullNameForErrors => name;
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) {
return context.match<Null>(
".type_promotion.expect", result.trace, result.uri, null);
main([List<String> arguments = const []]) =>
runMe(arguments, createContext, configurationPath: "../../testing.json");