95b1b8d756
(Part of https://github.com/dart-lang/sdk/issues/63288) This change migrates the front_end package to use the new constructor declaration syntax, described in https://github.com/dart-lang/language/blob/main/accepted/future-releases/primary-constructors/feature-specification.md#abbreviations-of-in-body-constructor-declarations. This change was performed in an automated fashion, by (a) enabling the lints `unnecessary_type_name_in_constructor` and `unnecessary_const_in_enum_constructor`, (b) fixing the resulting lint failures using `dart fix`, and then (c) reformatting the affected files. To ease code review, I've reverted unrelated formatting changes. Change-Id: I6b48c0f1c762c3fa132fbd79382496ca6a6a6964 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/508368 Reviewed-by: Konstantin Shcheglov <scheglov@google.com> SLSA-Policy-Verified: SLSA Policy Verification Service <devtools-gerritcodereview-exitgate@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
787 lines
23 KiB
Dart
787 lines
23 KiB
Dart
// 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:io" show File, IOSink;
|
|
import 'dart:typed_data' show Uint8List;
|
|
|
|
import 'package:_fe_analyzer_shared/src/util/colors.dart' as colors;
|
|
import "package:front_end/src/api_prototype/compiler_options.dart"
|
|
show CompilerOptions, CfeDiagnosticMessage;
|
|
import 'package:front_end/src/api_prototype/experimental_flags.dart';
|
|
import 'package:front_end/src/api_prototype/expression_compilation_tools.dart'
|
|
show createDefinitionsWithTypes, createTypeParametersWithBounds;
|
|
import 'package:front_end/src/api_prototype/incremental_kernel_generator.dart'
|
|
show IncrementalCompilerResult;
|
|
import "package:front_end/src/api_prototype/memory_file_system.dart"
|
|
show MemoryFileSystem;
|
|
import "package:front_end/src/api_prototype/terminal_color_support.dart"
|
|
show printDiagnosticMessage;
|
|
import 'package:front_end/src/base/compiler_context.dart' show CompilerContext;
|
|
import 'package:front_end/src/base/incremental_compiler.dart'
|
|
show IncrementalCompiler;
|
|
import 'package:front_end/src/base/processed_options.dart'
|
|
show ProcessedOptions;
|
|
import 'package:front_end/src/compute_platform_binaries_location.dart'
|
|
show computePlatformBinariesLocation;
|
|
import 'package:front_end/src/kernel/utils.dart'
|
|
show serializeComponent, serializeProcedure;
|
|
import 'package:front_end/src/source/source_loader.dart';
|
|
import 'package:front_end/src/testing/compiler_common.dart';
|
|
import "package:kernel/ast.dart"
|
|
show
|
|
Class,
|
|
Component,
|
|
Constructor,
|
|
DartType,
|
|
DynamicType,
|
|
Field,
|
|
Library,
|
|
Member,
|
|
Procedure,
|
|
TreeNode,
|
|
TypeParameter,
|
|
Variable;
|
|
import 'package:kernel/target/targets.dart' show TargetFlags;
|
|
import 'package:kernel/text/ast_to_text.dart' show Printer;
|
|
import "package:testing/src/log.dart" show splitLines;
|
|
import "package:testing/testing.dart"
|
|
show Chain, ChainContext, Result, Step, TestDescription;
|
|
import 'package:vm/modular/target/vm.dart' show VmTarget;
|
|
import "package:yaml/yaml.dart" show YamlMap, YamlList, loadYamlNode;
|
|
|
|
import 'testing_utils.dart' show checkEnvironment;
|
|
import 'utils/kernel_chain.dart' show runDiff, openWrite;
|
|
import 'utils/suite_utils.dart';
|
|
import 'testing/environment_keys.dart';
|
|
|
|
class Context extends ChainContext {
|
|
final CompilerContext compilerContext;
|
|
final List<CfeDiagnosticMessage> errors;
|
|
|
|
@override
|
|
final List<Step> steps;
|
|
|
|
final bool fuzz;
|
|
final Set<Uri> fuzzedLibraries = {};
|
|
int fuzzCompiles = 0;
|
|
|
|
new(this.compilerContext, this.errors, bool updateExpectations, this.fuzz)
|
|
: steps = <Step>[
|
|
const ReadTest(),
|
|
const CompileExpression(),
|
|
new MatchProcedureExpectations(
|
|
".expect",
|
|
updateExpectations: updateExpectations,
|
|
),
|
|
const OutputParametersMatches(),
|
|
];
|
|
|
|
ProcessedOptions get options => compilerContext.options;
|
|
|
|
MemoryFileSystem get fileSystem => options.fileSystem as MemoryFileSystem;
|
|
|
|
Future<T> runInContext<T>(Future<T> action(CompilerContext c)) {
|
|
return compilerContext.runInContext<T>(action);
|
|
}
|
|
|
|
void reset() {
|
|
errors.clear();
|
|
}
|
|
|
|
List<CfeDiagnosticMessage> takeErrors() {
|
|
List<CfeDiagnosticMessage> result = new List<CfeDiagnosticMessage>.from(
|
|
errors,
|
|
);
|
|
errors.clear();
|
|
return result;
|
|
}
|
|
}
|
|
|
|
class CompilationResult {
|
|
Library? compiledInLibrary;
|
|
Procedure? compiledProcedure;
|
|
List<CfeDiagnosticMessage> errors;
|
|
|
|
new(this.compiledInLibrary, this.compiledProcedure, this.errors);
|
|
|
|
String printResult(Uri entryPoint, Context context) {
|
|
StringBuffer buffer = new StringBuffer();
|
|
buffer.write("Errors: {\n");
|
|
for (CfeDiagnosticMessage error in errors) {
|
|
for (String message in error.plainTextFormatted) {
|
|
for (String line in splitLines(message)) {
|
|
buffer.write(" ");
|
|
buffer.write(line);
|
|
}
|
|
buffer.write("\n");
|
|
// TODO(jensj): Ignore context for now.
|
|
// Remove once we have positions on type parameters.
|
|
break;
|
|
}
|
|
}
|
|
buffer.write("}\n");
|
|
if (compiledProcedure == null) {
|
|
buffer.write("<no procedure>");
|
|
} else {
|
|
Printer printer = new Printer(buffer, showLibraryForNames: true);
|
|
printer.writeProcedureInLibrary(compiledProcedure!, compiledInLibrary!);
|
|
printer.writeConstantTable(new Component());
|
|
}
|
|
Uri base = entryPoint.resolve(".");
|
|
return "$buffer".replaceAll("$base", "org-dartlang-testcase:///");
|
|
}
|
|
}
|
|
|
|
class TestCase {
|
|
final TestDescription description;
|
|
|
|
final Map<String, String> sources;
|
|
|
|
final Uri entryPoint;
|
|
|
|
final List<String> definitions;
|
|
|
|
final List<String> definitionTypes;
|
|
|
|
final List<String> typeDefinitions;
|
|
|
|
final List<String> typeBounds;
|
|
|
|
final List<String> typeDefaults;
|
|
|
|
final bool isStaticMethod;
|
|
|
|
final Uri library;
|
|
|
|
final String? className;
|
|
|
|
final String? methodName;
|
|
|
|
final int? offset;
|
|
|
|
final String? scriptUri;
|
|
|
|
String expression;
|
|
|
|
List<CompilationResult> results = [];
|
|
|
|
new(
|
|
this.description,
|
|
this.sources,
|
|
this.entryPoint,
|
|
this.definitions,
|
|
this.definitionTypes,
|
|
this.typeDefinitions,
|
|
this.typeBounds,
|
|
this.typeDefaults,
|
|
this.isStaticMethod,
|
|
this.library,
|
|
this.className,
|
|
this.methodName,
|
|
this.offset,
|
|
this.scriptUri,
|
|
this.expression,
|
|
);
|
|
|
|
@override
|
|
String toString() {
|
|
return "TestCase("
|
|
"$sources, "
|
|
"$entryPoint, "
|
|
"$definitions, "
|
|
"$definitionTypes, "
|
|
"$typeDefinitions,"
|
|
"$typeBounds,"
|
|
"$typeDefaults,"
|
|
"$library, "
|
|
"$className, "
|
|
"static = $isStaticMethod)";
|
|
}
|
|
}
|
|
|
|
class OutputParametersMatches
|
|
extends Step<List<TestCase>, List<TestCase>, Context> {
|
|
const new();
|
|
|
|
@override
|
|
String get name => "output parameters matches";
|
|
|
|
@override
|
|
Future<Result<List<TestCase>>> run(List<TestCase> tests, Context context) {
|
|
for (TestCase test in tests) {
|
|
for (CompilationResult result in test.results) {
|
|
Procedure? compiledProcedure = result.compiledProcedure;
|
|
if (compiledProcedure == null) continue;
|
|
if (compiledProcedure.function.namedParameters.isNotEmpty) {
|
|
return Future.value(
|
|
fail(tests, "Compiled expression contains named parameters."),
|
|
);
|
|
}
|
|
List<Variable> positionals =
|
|
compiledProcedure.function.positionalParameters;
|
|
if (positionals.length != test.definitions.length) {
|
|
return Future.value(
|
|
fail(
|
|
tests,
|
|
"Compiled expression contains a wrong number of "
|
|
"positional parameters: Expected ${test.definitions.length} "
|
|
"(${test.definitions.join(", ")}) "
|
|
"but had ${positionals.length} "
|
|
"(${positionals.map((p) => p.name).join(", ")}).",
|
|
),
|
|
);
|
|
}
|
|
for (int i = 0; i < positionals.length; i++) {
|
|
if (positionals[i].name != test.definitions[i]) {
|
|
return Future.value(
|
|
fail(
|
|
tests,
|
|
"Compiled expression doesn't contain '${test.definitions[i]}' "
|
|
"but '${positionals[i].name}' as positional parameter $i.",
|
|
),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Future.value(pass(tests));
|
|
}
|
|
}
|
|
|
|
class MatchProcedureExpectations
|
|
extends Step<List<TestCase>, List<TestCase>, Context> {
|
|
final String suffix;
|
|
final bool updateExpectations;
|
|
|
|
const new(this.suffix, {this.updateExpectations = false});
|
|
|
|
@override
|
|
String get name => "match expectations";
|
|
|
|
@override
|
|
Future<Result<List<TestCase>>> run(
|
|
List<TestCase> tests,
|
|
Context context,
|
|
) async {
|
|
String actual = "";
|
|
for (TestCase test in tests) {
|
|
String primary = test.results.first.printResult(test.entryPoint, context);
|
|
actual += primary;
|
|
for (int i = 1; i < test.results.length; ++i) {
|
|
String secondary = test.results[i].printResult(
|
|
test.entryPoint,
|
|
context,
|
|
);
|
|
if (primary != secondary) {
|
|
return fail(
|
|
tests,
|
|
"Multiple expectations don't match on $test:"
|
|
"\nFirst expectation:\n$actual\n"
|
|
"\nSecond expectation:\n$secondary\n",
|
|
);
|
|
}
|
|
}
|
|
}
|
|
TestCase test = tests.first;
|
|
Uri testUri = test.description.uri;
|
|
File expectedFile = new File("${testUri.toFilePath()}$suffix");
|
|
if (await expectedFile.exists()) {
|
|
String expected = await expectedFile.readAsString();
|
|
if (expected.replaceAll("\r\n", "\n").trim() != actual.trim()) {
|
|
if (!updateExpectations) {
|
|
String diff = await runDiff(expectedFile.uri, actual);
|
|
return fail(
|
|
tests,
|
|
"$testUri doesn't match ${expectedFile.uri}\n$diff",
|
|
);
|
|
}
|
|
} else {
|
|
return pass(tests);
|
|
}
|
|
}
|
|
if (updateExpectations) {
|
|
await openWrite(expectedFile.uri, (IOSink sink) {
|
|
sink.writeln(actual.trim());
|
|
});
|
|
return pass(tests);
|
|
} else {
|
|
return fail(tests, """
|
|
Please create file ${expectedFile.path} with this content:
|
|
$actual""");
|
|
}
|
|
}
|
|
}
|
|
|
|
class ReadTest extends Step<TestDescription, List<TestCase>, Context> {
|
|
const new();
|
|
|
|
@override
|
|
String get name => "read test";
|
|
|
|
@override
|
|
Future<Result<List<TestCase>>> run(
|
|
TestDescription description,
|
|
Context context,
|
|
) async {
|
|
context.reset();
|
|
Uri uri = description.uri;
|
|
String contents = await new File.fromUri(uri).readAsString();
|
|
|
|
Uri entryPoint = toTestUri('main.dart');
|
|
List<String> definitions = <String>[];
|
|
List<String> definitionTypes = <String>[];
|
|
List<String> typeDefinitions = <String>[];
|
|
List<String> typeBounds = <String>[];
|
|
List<String> typeDefaults = <String>[];
|
|
bool isStaticMethod = false;
|
|
Uri? library;
|
|
String? className;
|
|
String? methodName;
|
|
int? offset;
|
|
String? scriptUri;
|
|
String? expression;
|
|
|
|
dynamic maps = loadYamlNode(contents, sourceUrl: uri);
|
|
if (maps is YamlMap) maps = [maps];
|
|
|
|
final List<TestCase> tests = [];
|
|
Map<String, String> sources = {};
|
|
for (YamlMap map in maps) {
|
|
for (String key in map.keys) {
|
|
dynamic value = map[key];
|
|
if (key == "sources") {
|
|
if (value is String) {
|
|
sources['main.dart'] = value;
|
|
} else if (value is YamlMap) {
|
|
value.forEach((key, value) {
|
|
sources[key as String] = value as String;
|
|
});
|
|
}
|
|
} else if (key == "entry_point") {
|
|
entryPoint = toTestUri(value as String);
|
|
} else if (key == "position") {
|
|
Uri uri = entryPoint.resolveUri(Uri.parse(value as String));
|
|
library = uri.removeFragment();
|
|
if (uri.fragment != '') {
|
|
className = uri.fragment;
|
|
}
|
|
} else if (key == "method") {
|
|
methodName = value as String;
|
|
} else if (key == "definitions") {
|
|
definitions = (value as YamlList).map((x) => x as String).toList();
|
|
} else if (key == "definition_types") {
|
|
definitionTypes = (value as YamlList)
|
|
.map((x) => x as String)
|
|
.toList();
|
|
} else if (key == "type_definitions") {
|
|
typeDefinitions = (value as YamlList)
|
|
.map((x) => x as String)
|
|
.toList();
|
|
} else if (key == "type_bounds") {
|
|
typeBounds = (value as YamlList).map((x) => x as String).toList();
|
|
} else if (key == "type_defaults") {
|
|
typeDefaults = (value as YamlList).map((x) => x as String).toList();
|
|
} else if (key == "static") {
|
|
isStaticMethod = value;
|
|
} else if (key == "expression") {
|
|
expression = value;
|
|
} else if (key == "offset") {
|
|
offset = value;
|
|
} else if (key == "scriptUri") {
|
|
Uri uri = entryPoint.resolveUri(Uri.parse(value as String));
|
|
scriptUri = uri.toString();
|
|
} else {
|
|
throw new UnsupportedError("Unknown key: ${key}");
|
|
}
|
|
}
|
|
library ??= entryPoint;
|
|
if (expression == null) {
|
|
return new Result.fail(tests, "No expression to compile.");
|
|
}
|
|
|
|
TestCase test = new TestCase(
|
|
description,
|
|
sources,
|
|
entryPoint,
|
|
definitions,
|
|
definitionTypes,
|
|
typeDefinitions,
|
|
typeBounds,
|
|
typeDefaults,
|
|
isStaticMethod,
|
|
library,
|
|
className,
|
|
methodName,
|
|
offset,
|
|
scriptUri,
|
|
expression,
|
|
);
|
|
tests.add(test);
|
|
}
|
|
return new Result.pass(tests);
|
|
}
|
|
}
|
|
|
|
class CompileExpression extends Step<List<TestCase>, List<TestCase>, Context> {
|
|
const new();
|
|
|
|
@override
|
|
String get name => "compile expression";
|
|
|
|
// Compile [test.expression], update [test.errors] with results.
|
|
// As a side effect - verify that generated procedure can be serialized.
|
|
Future<void> compileExpression(
|
|
TestCase test,
|
|
IncrementalCompiler compiler,
|
|
IncrementalCompilerResult compilerResult,
|
|
Context context,
|
|
) async {
|
|
Map<String, DartType>? definitions = createDefinitionsWithTypes(
|
|
compilerResult.classHierarchy.knownLibraries,
|
|
test.definitionTypes,
|
|
test.definitions,
|
|
);
|
|
|
|
if (definitions == null) {
|
|
definitions = {};
|
|
for (String name in test.definitions) {
|
|
definitions[name] = new DynamicType();
|
|
}
|
|
}
|
|
List<TypeParameter>? typeParams = createTypeParametersWithBounds(
|
|
compilerResult.classHierarchy.knownLibraries,
|
|
test.typeBounds,
|
|
test.typeDefaults,
|
|
test.typeDefinitions,
|
|
);
|
|
if (typeParams == null) {
|
|
typeParams = [];
|
|
for (String name in test.typeDefinitions) {
|
|
typeParams.add(
|
|
new TypeParameter(name, new DynamicType(), new DynamicType()),
|
|
);
|
|
}
|
|
}
|
|
|
|
SourceLoader loader = compiler.kernelTargetForTesting!.loader;
|
|
Library? libraryLookup =
|
|
(loader.lookupCompilationUnit(test.library) ??
|
|
loader.lookupCompilationUnitByFileUri(test.library))
|
|
?.libraryBuilder
|
|
.library;
|
|
|
|
Procedure? compiledProcedure = await compiler.compileExpression(
|
|
test.expression,
|
|
definitions,
|
|
typeParams,
|
|
"debugExpr",
|
|
test.library,
|
|
className: test.className,
|
|
methodName: test.methodName,
|
|
isStatic: test.isStaticMethod,
|
|
scriptUri: test.scriptUri,
|
|
offset: test.offset ?? TreeNode.noOffset,
|
|
);
|
|
List<CfeDiagnosticMessage> errors = context.takeErrors();
|
|
test.results.add(
|
|
new CompilationResult(libraryLookup, compiledProcedure, errors),
|
|
);
|
|
if (compiledProcedure != null) {
|
|
// Confirm we can serialize generated procedure.
|
|
compilerResult.component.computeCanonicalNames();
|
|
List<int> list = serializeProcedure(compiledProcedure);
|
|
assert(list.length > 0);
|
|
}
|
|
|
|
if (context.fuzz) {
|
|
await fuzz(compiler, compilerResult, context);
|
|
}
|
|
}
|
|
|
|
Future<void> fuzz(
|
|
IncrementalCompiler compiler,
|
|
IncrementalCompilerResult compilerResult,
|
|
Context context,
|
|
) async {
|
|
for (Library lib in compilerResult.classHierarchy.knownLibraries) {
|
|
if (!context.fuzzedLibraries.add(lib.importUri)) continue;
|
|
|
|
for (Member m in lib.members) {
|
|
await fuzzMember(m, compiler, lib.importUri, context);
|
|
}
|
|
|
|
for (Class c in lib.classes) {
|
|
for (Member m in c.members) {
|
|
await fuzzMember(m, compiler, lib.importUri, context);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> fuzzMember(
|
|
Member m,
|
|
IncrementalCompiler compiler,
|
|
Uri libraryUri,
|
|
Context context,
|
|
) async {
|
|
String expression = m.name.text;
|
|
if (m is Field || (m is Procedure && m.isGetter)) {
|
|
// fields and getters are fine as-is
|
|
} else if (m is Procedure && !m.isGetter) {
|
|
expression = "$expression()";
|
|
} else if (m is Constructor) {
|
|
if (m.parent is! Class) {
|
|
return;
|
|
}
|
|
Class parent = m.parent as Class;
|
|
if (m.name.text != "") {
|
|
expression = "${parent.name}.${m.name.text}()";
|
|
} else {
|
|
expression = "${parent.name}()";
|
|
}
|
|
} else {
|
|
throw "Didn't know ${m.runtimeType}";
|
|
}
|
|
|
|
String? className;
|
|
if (m.parent is Class && m is! Constructor) {
|
|
Class parent = m.parent as Class;
|
|
className = parent.name;
|
|
}
|
|
|
|
await fuzzTryCompile(
|
|
compiler,
|
|
"$expression",
|
|
libraryUri,
|
|
className,
|
|
!m.isInstanceMember,
|
|
context,
|
|
);
|
|
if (className != null && !m.isInstanceMember) {
|
|
await fuzzTryCompile(
|
|
compiler,
|
|
"$className.$expression",
|
|
libraryUri,
|
|
null,
|
|
!m.isInstanceMember,
|
|
context,
|
|
);
|
|
}
|
|
await fuzzTryCompile(
|
|
compiler,
|
|
"$expression.toString()",
|
|
libraryUri,
|
|
className,
|
|
!m.isInstanceMember,
|
|
context,
|
|
);
|
|
if (className != null && !m.isInstanceMember) {
|
|
await fuzzTryCompile(
|
|
compiler,
|
|
"$className.$expression.toString()",
|
|
libraryUri,
|
|
null,
|
|
!m.isInstanceMember,
|
|
context,
|
|
);
|
|
}
|
|
await fuzzTryCompile(
|
|
compiler,
|
|
"$expression.toString() == '42'",
|
|
libraryUri,
|
|
className,
|
|
!m.isInstanceMember,
|
|
context,
|
|
);
|
|
if (className != null && !m.isInstanceMember) {
|
|
await fuzzTryCompile(
|
|
compiler,
|
|
"$className.$expression.toString() == '42'",
|
|
libraryUri,
|
|
null,
|
|
!m.isInstanceMember,
|
|
context,
|
|
);
|
|
}
|
|
await fuzzTryCompile(
|
|
compiler,
|
|
"() { var x = $expression.toString(); x == '42'; }()",
|
|
libraryUri,
|
|
className,
|
|
!m.isInstanceMember,
|
|
context,
|
|
);
|
|
if (className != null && !m.isInstanceMember) {
|
|
await fuzzTryCompile(
|
|
compiler,
|
|
"() { var x = $className.$expression.toString(); x == '42'; }()",
|
|
libraryUri,
|
|
null,
|
|
!m.isInstanceMember,
|
|
context,
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<void> fuzzTryCompile(
|
|
IncrementalCompiler compiler,
|
|
String expression,
|
|
Uri libraryUri,
|
|
String? className,
|
|
bool isStatic,
|
|
Context context,
|
|
) async {
|
|
context.fuzzCompiles++;
|
|
print(
|
|
"Fuzz compile #${context.fuzzCompiles} "
|
|
"('$expression' in $libraryUri $className)",
|
|
);
|
|
Procedure? compiledProcedure = await compiler.compileExpression(
|
|
expression,
|
|
{},
|
|
[],
|
|
"debugExpr",
|
|
libraryUri,
|
|
className: className,
|
|
isStatic: isStatic,
|
|
);
|
|
context.takeErrors();
|
|
if (compiledProcedure != null) {
|
|
// Confirm we can serialize generated procedure.
|
|
List<int> list = serializeProcedure(compiledProcedure);
|
|
assert(list.length > 0);
|
|
}
|
|
}
|
|
|
|
@override
|
|
Future<Result<List<TestCase>>> run(
|
|
List<TestCase> tests,
|
|
Context context,
|
|
) async {
|
|
for (TestCase test in tests) {
|
|
test.sources.forEach((String fileName, String source) {
|
|
context.fileSystem
|
|
.entityForUri(toTestUri(fileName))
|
|
.writeAsStringSync(source);
|
|
});
|
|
|
|
IncrementalCompiler sourceCompiler = new IncrementalCompiler(
|
|
context.compilerContext,
|
|
);
|
|
IncrementalCompilerResult sourceCompilerResult = await sourceCompiler
|
|
.computeDelta(entryPoints: [test.entryPoint]);
|
|
Component component = sourceCompilerResult.component;
|
|
List<CfeDiagnosticMessage> errors = context.takeErrors();
|
|
if (!errors.isEmpty) {
|
|
return fail(
|
|
tests,
|
|
"Couldn't compile entry-point: "
|
|
"${errors.map((e) => e.plainTextFormatted.first).toList()}",
|
|
);
|
|
}
|
|
Uri dillFileUri = toTestUri("${test.description.shortName}.dill");
|
|
Uint8List dillData = await serializeComponent(component);
|
|
context.fileSystem.entityForUri(dillFileUri).writeAsBytesSync(dillData);
|
|
Set<Uri> beforeFuzzedLibraries = context.fuzzedLibraries.toSet();
|
|
await compileExpression(
|
|
test,
|
|
sourceCompiler,
|
|
sourceCompilerResult,
|
|
context,
|
|
);
|
|
|
|
IncrementalCompiler dillCompiler = new IncrementalCompiler(
|
|
context.compilerContext,
|
|
dillFileUri,
|
|
);
|
|
IncrementalCompilerResult dillCompilerResult = await dillCompiler
|
|
.computeDelta(entryPoints: [test.entryPoint]);
|
|
component = dillCompilerResult.component;
|
|
component.computeCanonicalNames();
|
|
|
|
errors = context.takeErrors();
|
|
// Since it compiled successfully from source, the bootstrap-from-Dill
|
|
// should also succeed without errors.
|
|
assert(errors.isEmpty);
|
|
|
|
context.fuzzedLibraries.clear();
|
|
context.fuzzedLibraries.addAll(beforeFuzzedLibraries);
|
|
await compileExpression(test, dillCompiler, dillCompilerResult, context);
|
|
}
|
|
return new Result.pass(tests);
|
|
}
|
|
}
|
|
|
|
Future<Context> createContext(
|
|
Chain suite,
|
|
Map<String, String> environment,
|
|
) async {
|
|
const Set<String> knownEnvironmentKeys = {
|
|
EnvironmentKeys.updateExpectations,
|
|
EnvironmentKeys.fuzz,
|
|
};
|
|
checkEnvironment(environment, knownEnvironmentKeys);
|
|
|
|
final Uri base = Uri.parse("org-dartlang-test:///");
|
|
|
|
/// Unused because we supply entry points to [computeDelta] directly above.
|
|
final Uri entryPoint = base.resolve("nothing.dart");
|
|
|
|
/// The custom URI used to locate the dill file in the MemoryFileSystem.
|
|
final Uri sdkSummary = base.resolve("vm_platform.dill");
|
|
|
|
/// The actual location of the dill file.
|
|
final Uri sdkSummaryFile = computePlatformBinariesLocation(
|
|
forceBuildDir: true,
|
|
).resolve("vm_platform.dill");
|
|
|
|
final MemoryFileSystem fs = new MemoryFileSystem(base);
|
|
|
|
fs
|
|
.entityForUri(sdkSummary)
|
|
.writeAsBytesSync(await new File.fromUri(sdkSummaryFile).readAsBytes());
|
|
|
|
final List<CfeDiagnosticMessage> errors = <CfeDiagnosticMessage>[];
|
|
|
|
final CompilerOptions optionBuilder = new CompilerOptions()
|
|
..target = new VmTarget(new TargetFlags())
|
|
..verbose = true
|
|
..omitPlatform = true
|
|
..fileSystem = fs
|
|
..sdkSummary = sdkSummary
|
|
..onDiagnostic = (CfeDiagnosticMessage message) {
|
|
printDiagnosticMessage(message, print);
|
|
errors.add(message);
|
|
}
|
|
..environmentDefines = const {}
|
|
..explicitExperimentalFlags = {}
|
|
..allowedExperimentalFlagsForTesting = const AllowedExperimentalFlags();
|
|
|
|
final ProcessedOptions options = new ProcessedOptions(
|
|
options: optionBuilder,
|
|
inputs: [entryPoint],
|
|
);
|
|
|
|
final bool updateExpectations =
|
|
environment[EnvironmentKeys.updateExpectations] == "true";
|
|
|
|
final bool fuzz = environment[EnvironmentKeys.fuzz] == "true";
|
|
|
|
final CompilerContext compilerContext = new CompilerContext(options);
|
|
|
|
// Disable colors to ensure that expectation files are the same across
|
|
// platforms and independent of stdin/stderr.
|
|
colors.enableColors = false;
|
|
|
|
return new Context(compilerContext, errors, updateExpectations, fuzz);
|
|
}
|
|
|
|
void main([List<String> arguments = const []]) => internalMain(
|
|
createContext,
|
|
arguments: arguments,
|
|
displayName: "expression suite",
|
|
configurationPath: "../testing.json",
|
|
);
|