Version 2.10.0-93.0.dev
Merge commit '34052bf2bbe2477d22bc4ef96b774067a86f68e3' into 'dev'
diff --git a/pkg/dev_compiler/bin/dartdevc.dart b/pkg/dev_compiler/bin/dartdevc.dart
index a906e00..68246e3 100755
--- a/pkg/dev_compiler/bin/dartdevc.dart
+++ b/pkg/dev_compiler/bin/dartdevc.dart
@@ -12,6 +12,7 @@
import 'dart:isolate';
import 'package:bazel_worker/bazel_worker.dart';
import 'package:dev_compiler/src/compiler/shared_command.dart';
+import 'package:dev_compiler/src/kernel/expression_compiler_worker.dart';
/// The entry point for the Dart Dev Compiler.
///
@@ -28,6 +29,18 @@
await _CompilerWorker(parsedArgs, workerConnection).run();
} else if (parsedArgs.isBatch) {
await runBatch(parsedArgs);
+ } else if (parsedArgs.isExpressionCompiler) {
+ ExpressionCompilerWorker worker;
+ if (sendPort != null) {
+ var receivePort = ReceivePort();
+ sendPort.send(receivePort.sendPort);
+ worker = await ExpressionCompilerWorker.createFromArgs(parsedArgs.rest,
+ requestStream: receivePort.cast<Map<String, dynamic>>(),
+ sendResponse: sendPort.send);
+ } else {
+ worker = await ExpressionCompilerWorker.createFromArgs(parsedArgs.rest);
+ }
+ await worker.start();
} else {
var result = await compile(parsedArgs);
exitCode = result.exitCode;
diff --git a/pkg/dev_compiler/lib/dev_compiler.dart b/pkg/dev_compiler/lib/dev_compiler.dart
index dedfc72..ca0a8bd 100644
--- a/pkg/dev_compiler/lib/dev_compiler.dart
+++ b/pkg/dev_compiler/lib/dev_compiler.dart
@@ -8,4 +8,5 @@
export 'src/compiler/shared_command.dart' show SharedCompilerOptions;
export 'src/kernel/command.dart' show jsProgramToCode;
export 'src/kernel/compiler.dart' show ProgramCompiler;
+export 'src/kernel/expression_compiler.dart' show ExpressionCompiler;
export 'src/kernel/target.dart' show DevCompilerTarget;
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_command.dart b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
index 2761eb0..358f238 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_command.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
@@ -61,6 +61,14 @@
/// runtime can enable synchronous stack trace deobsfuscation.
final bool inlineSourceMap;
+ /// Whether to emit the full compiled kernel.
+ ///
+ /// This is used by expression compiler worker, launched from the debugger
+ /// in webdev and google3 scenarios, for expression evaluation features.
+ /// Full kernel for compiled files is needed to be able to compile
+ /// expressions on demand in the current scope of a breakpoint.
+ final bool emitFullCompiledKernel;
+
/// Whether to emit a summary file containing API signatures.
///
/// This is required for a modular build process.
@@ -113,6 +121,7 @@
this.enableAsserts = true,
this.replCompile = false,
this.emitDebugMetadata = false,
+ this.emitFullCompiledKernel = false,
this.summaryModules = const {},
this.moduleFormats = const [],
this.moduleName,
@@ -129,6 +138,8 @@
enableAsserts: args['enable-asserts'] as bool,
replCompile: args['repl-compile'] as bool,
emitDebugMetadata: args['experimental-emit-debug-metadata'] as bool,
+ emitFullCompiledKernel:
+ args['experimental-output-compiled-kernel'] as bool,
summaryModules:
_parseCustomSummaryModules(args['summary'] as List<String>),
moduleFormats: parseModuleFormatOption(args),
@@ -181,6 +192,12 @@
help: 'Experimental option for compiler development.\n'
'Output a metadata file for debug tools next to the .js output.',
defaultsTo: false,
+ hide: true)
+ ..addFlag('experimental-output-compiled-kernel',
+ help: 'Experimental option for compiler development.\n'
+ 'Output a full kernel file for currently compiled module next to '
+ 'the .js output.',
+ defaultsTo: false,
hide: true);
}
@@ -490,6 +507,17 @@
/// See also [isBatchOrWorker].
final bool isBatch;
+ /// Whether to run in `--experimental-expression-compiler` mode.
+ ///
+ /// This is a special mode that is optimized for only compiling expressions.
+ ///
+ /// All dependencies must come from precompiled dill files, and those must
+ /// be explicitly invalidated as needed between expression compile requests.
+ /// Invalidation of dill is performed using [updateDeps] from the client (i.e.
+ /// debugger) and should be done every time a dill file changes, for example,
+ /// on hot reload or rebuild.
+ final bool isExpressionCompiler;
+
/// Whether to run in `--bazel_worker` mode, e.g. for Bazel builds.
///
/// Similar to [isBatch] but with a different protocol.
@@ -507,11 +535,14 @@
/// Note that this only makes sense when also reusing results.
final bool useIncrementalCompiler;
- ParsedArguments._(this.rest,
- {this.isBatch = false,
- this.isWorker = false,
- this.reuseResult = false,
- this.useIncrementalCompiler = false});
+ ParsedArguments._(
+ this.rest, {
+ this.isBatch = false,
+ this.isWorker = false,
+ this.reuseResult = false,
+ this.useIncrementalCompiler = false,
+ this.isExpressionCompiler = false,
+ });
/// Preprocess arguments to determine whether DDK is used in batch mode or as a
/// persistent worker.
@@ -530,6 +561,7 @@
var isBatch = false;
var reuseResult = false;
var useIncrementalCompiler = false;
+ var isExpressionCompiler = false;
Iterable<String> argsToParse = args;
@@ -548,6 +580,8 @@
reuseResult = true;
} else if (arg == '--use-incremental-compiler') {
useIncrementalCompiler = true;
+ } else if (arg == '--experimental-expression-compiler') {
+ isExpressionCompiler = true;
} else {
newArgs.add(arg);
}
@@ -556,7 +590,8 @@
isWorker: isWorker,
isBatch: isBatch,
reuseResult: reuseResult,
- useIncrementalCompiler: useIncrementalCompiler);
+ useIncrementalCompiler: useIncrementalCompiler,
+ isExpressionCompiler: isExpressionCompiler);
}
/// Whether the compiler is running in [isBatch] or [isWorker] mode.
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index ba80022..6598642 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -361,7 +361,7 @@
'the --summarize option is not supported.');
return CompilerResult(64);
}
- // TODO(jmesserly): CFE mutates the Kernel tree, so we can't save the dill
+ // Note: CFE mutates the Kernel tree, so we can't save the dill
// file if we successfully reused a cached library. If compiler state is
// unchanged, it means we used the cache.
//
@@ -376,6 +376,27 @@
kernel.BinaryPrinter(sink).writeComponentFile(component);
outFiles.add(sink.flush().then((_) => sink.close()));
}
+ if (argResults['experimental-output-compiled-kernel'] as bool) {
+ if (outPaths.length > 1) {
+ print(
+ 'If multiple output files (found ${outPaths.length}) are specified, '
+ 'the --experimental-output-compiled-kernel option is not supported.');
+ return CompilerResult(64);
+ }
+ // Note: CFE mutates the Kernel tree, so we can't save the dill
+ // file if we successfully reused a cached library. If compiler state is
+ // unchanged, it means we used the cache.
+ //
+ // In that case, we need to unbind canonical names, because they could be
+ // bound already from the previous compile.
+ if (identical(compilerState, oldCompilerState)) {
+ compiledLibraries.unbindCanonicalNames();
+ }
+ var sink =
+ File(p.withoutExtension(outPaths.first) + '.full.dill').openWrite();
+ kernel.BinaryPrinter(sink).writeComponentFile(compiledLibraries);
+ outFiles.add(sink.flush().then((_) => sink.close()));
+ }
if (argResults['summarize-text'] as bool) {
if (outPaths.length > 1) {
print(
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index a040dc9..96575f1 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -2930,11 +2930,16 @@
_staticTypeContext.enterLibrary(_currentLibrary);
_currentClass = cls;
- // emit function with additional information,
- // such as types that are used in the expression
+ // Emit function with additional information, such as types that are used
+ // in the expression. Note that typeTable can be null if this function is
+ // called from the expression compilation service, since we currently do
+ // not optimize for size of generated javascript in that scenario.
+ // TODO: figure whether or when optimizing for build time vs JavaScript
+ // size on expression evaluation is better.
+ // Issue: https://github.com/dart-lang/sdk/issues/43288
var fun = _emitFunction(functionNode, name);
- var items = _typeTable.discharge();
- var body = js_ast.Block([...items, ...fun.body.statements]);
+ var items = _typeTable?.discharge();
+ var body = js_ast.Block([...?items, ...fun.body.statements]);
return js_ast.Fun(fun.params, body);
}
@@ -3450,7 +3455,7 @@
if (fileUri == null) return null;
try {
var loc = _component.getLocation(fileUri, offset);
- if (loc == null) return null;
+ if (loc == null || loc.line < 0) return null;
return SourceLocation(offset,
sourceUrl: fileUri, line: loc.line - 1, column: loc.column - 1);
} on StateError catch (_) {
diff --git a/pkg/frontend_server/lib/src/expression_compiler.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
similarity index 94%
rename from pkg/frontend_server/lib/src/expression_compiler.dart
rename to pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
index a64a904..2b26a3f 100644
--- a/pkg/frontend_server/lib/src/expression_compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
@@ -1,6 +1,6 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+// Copyright (c) 2020, 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:async';
import 'dart:io';
@@ -210,6 +210,7 @@
final IncrementalCompiler _compiler;
final ProgramCompiler _kernel2jsCompiler;
final Component _component;
+ final List<String> errors;
DiagnosticMessageHandler onDiagnostic;
void _log(String message) {
@@ -222,7 +223,7 @@
}
ExpressionCompiler(this._compiler, this._kernel2jsCompiler, this._component,
- {this.verbose, this.onDiagnostic});
+ {this.verbose, this.onDiagnostic, this.errors});
/// Compiles [expression] in [libraryUri] at [line]:[column] to JavaScript
/// in [moduleName].
@@ -425,11 +426,15 @@
scope.cls?.name,
scope.procedure.isStatic);
- // TODO(annagrin): The condition below seems to be always false.
- // Errors are still correctly reported in the frontent_server,
- // but we end up doing unnesessary work below.
- // Add communication of error state from compiler here.
- if (_compiler.context.errors.length > 0) {
+ // TODO: make this code clear and assumptions enforceable
+ // https://github.com/dart-lang/sdk/issues/43273
+ //
+ // We assume here that ExpressionCompiler is always created using
+ // onDisgnostic method that adds to the error list that is passed
+ // to the same invocation of the ExpressionCompiler constructor.
+ // We only use the error list once - below, to detect if the frontend
+ // compilation of the expression has failed.
+ if (errors.isNotEmpty) {
return null;
}
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
new file mode 100644
index 0000000..9cb61dc
--- /dev/null
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
@@ -0,0 +1,473 @@
+// Copyright (c) 2020, 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:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:_fe_analyzer_shared/src/messages/diagnostic_message.dart';
+import 'package:_fe_analyzer_shared/src/messages/severity.dart';
+import 'package:args/args.dart';
+import 'package:build_integration/file_system/multi_root.dart';
+import 'package:front_end/src/api_prototype/compiler_options.dart';
+import 'package:front_end/src/api_prototype/experimental_flags.dart';
+import 'package:front_end/src/api_prototype/file_system.dart';
+import 'package:front_end/src/api_unstable/ddc.dart';
+import 'package:kernel/ast.dart' show Component, Library;
+import 'package:kernel/target/targets.dart' show TargetFlags;
+import 'package:meta/meta.dart';
+import 'package:vm/http_filesystem.dart';
+
+import '../compiler/js_names.dart';
+import '../compiler/shared_command.dart';
+import 'command.dart';
+import 'compiler.dart';
+import 'expression_compiler.dart';
+import 'target.dart';
+
+/// A wrapper around asset server that redirects file read requests
+/// to http get requests to the asset server.
+class AssetFileSystem extends HttpAwareFileSystem {
+ final String server;
+ final String port;
+
+ AssetFileSystem(FileSystem original, this.server, this.port)
+ : super(original);
+
+ Uri resourceUri(Uri uri) =>
+ Uri.parse('http://$server:$port/getResource?uri=${uri.toString()}');
+
+ @override
+ FileSystemEntity entityForUri(Uri uri) {
+ if (uri.scheme == 'file') {
+ return super.entityForUri(uri);
+ }
+
+ // pass the uri to the asset server in the debugger
+ return HttpFileSystemEntity(this, resourceUri(uri));
+ }
+}
+
+/// The service that handles expression compilation requests from
+/// the debugger.
+///
+/// See design documentation and discussion in
+/// http://go/dart_expression_evaluation_webdev_google3
+///
+///
+/// [ExpressionCompilerWorker] listens to input stream of compile expression
+/// requests and outputs responses.
+///
+/// Debugger can run the service by running the dartdevc main in an isolate,
+/// which sets up the request stream and response callback using send ports.
+///
+/// Debugger also can pass an asset server's host and port so the service
+/// can read dill files from the [AssetFileSystem] that talks to the asset
+/// server behind the scenes over http.
+///
+/// Protocol:
+///
+/// - debugger and dartdevc expression evaluation service perform the initial
+/// handshake to establish two-way communication:
+///
+/// - debugger creates an isolate using dartdevc's main method with
+/// '--experimental-expression-compiler' flag and passes a send port
+/// to dartdevc for sending responces from the service to the debugger.
+///
+/// - dartdevc creates a new send port to receive requests on, and sends
+/// it back to the debugger, for sending requests to the service.
+///
+/// - debugger can now send two types of requests to the dartdevc service.
+/// The service handles the requests sequentially in a first come, first
+/// serve order.
+///
+/// - [UpdateDepsRequest]:
+/// This request is sent on (re-)build, making the dartdevc load all
+/// newly built full kernel files for given modules.
+///
+/// - [CompileExpressionRequest]:
+/// This request is sent any time an evaluateInFrame request is made to
+/// the debugger's VM service at a breakpoint - for example, on typing
+/// in an expression evaluation box, on hover over, evaluation of
+/// conditional breakpoints, evaluation of expressions in a watch window.
+///
+/// - Debugger closes the requests stream on exit, which effectively stops
+/// the service
+class ExpressionCompilerWorker {
+ final Stream<Map<String, dynamic>> requestStream;
+ final void Function(Map<String, dynamic>) sendResponse;
+
+ final _libraryForUri = <Uri, Library>{};
+ final _componentForLibrary = <Library, Component>{};
+ final _componentForModuleName = <String, Component>{};
+ final _componentModuleNames = <Component, String>{};
+ final ProcessedOptions _processedOptions;
+ final Component _sdkComponent;
+
+ ExpressionCompilerWorker._(this._processedOptions, this._sdkComponent,
+ this.requestStream, this.sendResponse);
+
+ static Future<ExpressionCompilerWorker> createFromArgs(
+ List<String> args, {
+ Stream<Map<String, dynamic>> requestStream,
+ void Function(Map<String, dynamic>) sendResponse,
+ }) {
+ // We are destructive on `args`, so make a copy.
+ args = args.toList();
+ var environmentDefines = parseAndRemoveDeclaredVariables(args);
+ var parsedArgs = argParser.parse(args);
+
+ FileSystem fileSystem = StandardFileSystem.instance;
+ var multiRoots = (parsedArgs['multi-root'] as Iterable<String>)
+ .map(Uri.base.resolve)
+ .toList();
+ var multiRootScheme = parsedArgs['multi-root-scheme'] as String;
+ if (multiRoots.isNotEmpty) {
+ fileSystem = MultiRootFileSystem(multiRootScheme, multiRoots, fileSystem);
+ }
+ var assetServerAddress = parsedArgs['asset-server-address'] as String;
+ if (assetServerAddress != null) {
+ var assetServerPort = parsedArgs['asset-server-port'] as String;
+ fileSystem = AssetFileSystem(
+ fileSystem, assetServerAddress, assetServerPort ?? '8080');
+ }
+ var experimentalFlags = parseExperimentalFlags(
+ parseExperimentalArguments(
+ parsedArgs['enable-experiment'] as List<String>),
+ onError: (e) => throw e);
+ return create(
+ librariesSpecificationUri:
+ _argToUri(parsedArgs['libraries-file'] as String),
+ packagesFile: _argToUri(parsedArgs['packages-file'] as String),
+ sdkSummary: _argToUri(parsedArgs['dart-sdk-summary'] as String),
+ fileSystem: fileSystem,
+ environmentDefines: environmentDefines,
+ experimentalFlags: experimentalFlags,
+ sdkRoot: _argToUri(parsedArgs['sdk-root'] as String),
+ trackWidgetCreation: parsedArgs['track-widget-creation'] as bool,
+ soundNullSafety: parsedArgs['sound-null-safety'] as bool,
+ verbose: parsedArgs['verbose'] as bool,
+ requestStream: requestStream,
+ sendResponse: sendResponse,
+ );
+ }
+
+ static List<String> errors = <String>[];
+ static List<String> warnings = <String>[];
+
+ /// Create the worker and load the sdk outlines.
+ static Future<ExpressionCompilerWorker> create({
+ @required Uri librariesSpecificationUri,
+ @required Uri sdkSummary,
+ @required FileSystem fileSystem,
+ Uri packagesFile,
+ Map<String, String> environmentDefines = const {},
+ Map<ExperimentalFlag, bool> experimentalFlags = const {},
+ Uri sdkRoot,
+ bool trackWidgetCreation = false,
+ bool soundNullSafety = false,
+ bool verbose = false,
+ Stream<Map<String, dynamic>> requestStream, // Defaults to read from stdin
+ void Function(Map<String, dynamic>)
+ sendResponse, // Defaults to write to stdout
+ }) async {
+ var options = CompilerOptions()
+ ..compileSdk = false
+ ..sdkRoot = sdkRoot
+ ..sdkSummary = sdkSummary
+ ..packagesFileUri = packagesFile
+ ..librariesSpecificationUri = librariesSpecificationUri
+ ..target = DevCompilerTarget(
+ TargetFlags(trackWidgetCreation: trackWidgetCreation))
+ ..fileSystem = fileSystem
+ ..omitPlatform = true
+ ..environmentDefines = environmentDefines
+ ..experimentalFlags = experimentalFlags
+ ..onDiagnostic = _onDiagnosticHandler(errors, warnings)
+ ..nnbdMode = soundNullSafety ? NnbdMode.Strong : NnbdMode.Weak
+ ..verbose = verbose;
+ requestStream ??= stdin
+ .transform(utf8.decoder.fuse(json.decoder))
+ .cast<Map<String, dynamic>>();
+ sendResponse ??= (Map<String, dynamic> response) =>
+ stdout.writeln(json.encode(response));
+ var processedOpts = ProcessedOptions(options: options);
+
+ var sdkComponent = await CompilerContext(processedOpts)
+ .runInContext<Component>((CompilerContext c) async {
+ return processedOpts.loadSdkSummary(null);
+ });
+
+ return ExpressionCompilerWorker._(
+ processedOpts, sdkComponent, requestStream, sendResponse)
+ .._update(sdkComponent, dartSdkModule);
+ }
+
+ /// Starts listening and responding to commands.
+ ///
+ /// Completes when the [requestStream] closes and we finish handling the
+ /// requests.
+ Future<void> start() async {
+ await for (var request in requestStream) {
+ try {
+ var command = request['command'] as String;
+ switch (command) {
+ case 'UpdateDeps':
+ sendResponse(
+ await _updateDeps(UpdateDepsRequest.fromJson(request)));
+ break;
+ case 'CompileExpression':
+ sendResponse(await _compileExpression(
+ CompileExpressionRequest.fromJson(request)));
+ break;
+ default:
+ throw ArgumentError(
+ 'Unrecognized command `$command`, full request was `$request`');
+ }
+ } catch (e, s) {
+ sendResponse({
+ 'exception': '$e',
+ 'stackTrace': '$s',
+ 'succeeded': false,
+ });
+ }
+ }
+ }
+
+ /// Handles a `CompileExpression` request.
+ Future<Map<String, dynamic>> _compileExpression(
+ CompileExpressionRequest request) async {
+ var libraryUri = Uri.parse(request.libraryUri);
+ if (libraryUri.scheme == 'dart') {
+ // compiling expressions inside the SDK currently fails because
+ // SDK kernel outlines do not contain information that is needed
+ // to detect the scope for expression evaluation - such as local
+ // symbols and source file line starts.
+ throw Exception('Expression compilation inside SDK is not supported yet');
+ }
+
+ var originalComponent = _componentForModuleName[request.moduleName];
+ if (originalComponent == null) {
+ throw ArgumentError(
+ 'Unable to find library `$libraryUri`, it must be loaded first.');
+ }
+
+ var component = _sdkComponent;
+
+ if (libraryUri.scheme != 'dart') {
+ var libraries =
+ _collectTransitiveDependencies(originalComponent, _sdkComponent);
+ component = Component(
+ libraries: libraries,
+ nameRoot: originalComponent.root,
+ uriToSource: originalComponent.uriToSource,
+ );
+ }
+
+ errors.clear();
+ warnings.clear();
+
+ var incrementalCompiler = IncrementalCompiler.forExpressionCompilationOnly(
+ CompilerContext(_processedOptions), component);
+
+ var finalComponent =
+ await incrementalCompiler.computeDelta(entryPoints: [libraryUri]);
+ finalComponent.computeCanonicalNames();
+
+ if (errors.isNotEmpty) {
+ return {
+ 'errors': errors,
+ 'warnings': warnings,
+ 'compiledProcedure': null,
+ 'succeeded': errors.isEmpty,
+ };
+ }
+
+ var compiler = ProgramCompiler(
+ finalComponent,
+ incrementalCompiler.getClassHierarchy(),
+ SharedCompilerOptions(
+ sourceMap: true, summarizeApi: false, moduleName: request.moduleName),
+ _componentForLibrary,
+ _componentModuleNames,
+ coreTypes: incrementalCompiler.getCoreTypes(),
+ );
+
+ var expressionCompiler = ExpressionCompiler(
+ incrementalCompiler,
+ compiler,
+ finalComponent,
+ verbose: _processedOptions.verbose,
+ onDiagnostic: _onDiagnosticHandler(errors, warnings),
+ errors: errors,
+ );
+
+ var compiledProcedure = await expressionCompiler.compileExpressionToJs(
+ request.libraryUri,
+ request.line,
+ request.column,
+ request.jsModules,
+ request.jsScope,
+ request.moduleName,
+ request.expression);
+
+ return {
+ 'errors': errors,
+ 'warnings': warnings,
+ 'compiledProcedure': compiledProcedure,
+ 'succeeded': errors.isEmpty,
+ };
+ }
+
+ List<Library> _collectTransitiveDependencies(
+ Component component, Component sdk) {
+ var libraries = <Library>{};
+ libraries.addAll(sdk.libraries);
+
+ var toVisit = <Library>[];
+ toVisit.addAll(component.libraries);
+
+ while (toVisit.isNotEmpty) {
+ var lib = toVisit.removeLast();
+ if (!libraries.contains(lib)) {
+ libraries.add(lib);
+
+ for (var dep in lib.dependencies) {
+ var uri = dep.importedLibraryReference.asLibrary.importUri;
+ var library = _libraryForUri[uri];
+ assert(library == dep.importedLibraryReference.asLibrary);
+ toVisit.add(library);
+ }
+ }
+ }
+
+ return libraries.toList();
+ }
+
+ /// Loads in the specified dill files and invalidates any existing ones.
+ Future<Map<String, dynamic>> _updateDeps(UpdateDepsRequest request) async {
+ for (var input in request.inputs) {
+ var file =
+ _processedOptions.fileSystem.entityForUri(Uri.parse(input.path));
+ var bytes = await file.readAsBytes();
+ var component = await _processedOptions.loadComponent(
+ bytes, _sdkComponent.root,
+ alwaysCreateNewNamedNodes: true);
+ _update(component, input.moduleName);
+ }
+ return {'succeeded': true};
+ }
+
+ void _update(Component component, String moduleName) {
+ // do not update dart sdk
+ if (moduleName == dartSdkModule &&
+ _componentForModuleName.containsKey(moduleName)) {
+ return;
+ }
+
+ // cleanup old components and libraries
+ if (_componentForModuleName.containsKey(moduleName)) {
+ var oldComponent = _componentForModuleName[moduleName];
+ for (var lib in oldComponent.libraries) {
+ _componentForLibrary.remove(lib);
+ _libraryForUri.remove(lib.importUri);
+ }
+ _componentModuleNames.remove(oldComponent);
+ _componentForModuleName.remove(moduleName);
+ }
+
+ // add new components and libraries
+ _componentModuleNames[component] = moduleName;
+ _componentForModuleName[moduleName] = component;
+ for (var lib in component.libraries) {
+ _componentForLibrary[lib] = component;
+ _libraryForUri[lib.importUri] = lib;
+ }
+ }
+}
+
+class CompileExpressionRequest {
+ final int column;
+ final String expression;
+ final Map<String, String> jsModules;
+ final Map<String, String> jsScope;
+ final String libraryUri;
+ final int line;
+ final String moduleName;
+
+ CompileExpressionRequest({
+ @required this.expression,
+ @required this.column,
+ @required this.jsModules,
+ @required this.jsScope,
+ @required this.libraryUri,
+ @required this.line,
+ @required this.moduleName,
+ });
+
+ factory CompileExpressionRequest.fromJson(Map<String, dynamic> json) =>
+ CompileExpressionRequest(
+ expression: json['expression'] as String,
+ line: json['line'] as int,
+ column: json['column'] as int,
+ jsModules: Map<String, String>.from(json['jsModules'] as Map),
+ jsScope: Map<String, String>.from(json['jsScope'] as Map),
+ libraryUri: json['libraryUri'] as String,
+ moduleName: json['moduleName'] as String,
+ );
+}
+
+class UpdateDepsRequest {
+ final List<InputDill> inputs;
+
+ UpdateDepsRequest(this.inputs);
+
+ factory UpdateDepsRequest.fromJson(Map<String, dynamic> json) =>
+ UpdateDepsRequest([
+ for (var input in json['inputs'] as List)
+ InputDill(input['path'] as String, input['moduleName'] as String),
+ ]);
+}
+
+class InputDill {
+ final String moduleName;
+ final String path;
+
+ InputDill(this.path, this.moduleName);
+}
+
+void Function(DiagnosticMessage) _onDiagnosticHandler(
+ List<String> errors, List<String> warnings) =>
+ (DiagnosticMessage message) {
+ switch (message.severity) {
+ case Severity.error:
+ case Severity.internalProblem:
+ errors.add(message.plainTextFormatted.join('\n'));
+ break;
+ case Severity.warning:
+ warnings.add(message.plainTextFormatted.join('\n'));
+ break;
+ case Severity.context:
+ case Severity.ignored:
+ throw 'Unexpected severity: ${message.severity}';
+ }
+ };
+
+final argParser = ArgParser()
+ ..addOption('dart-sdk-summary')
+ ..addMultiOption('enable-experiment',
+ help: 'Enable a language experiment when invoking the CFE.')
+ ..addOption('libraries-file')
+ ..addMultiOption('multi-root')
+ ..addOption('multi-root-scheme', defaultsTo: 'org-dartlang-app')
+ ..addOption('packages-file')
+ ..addOption('sdk-root')
+ ..addOption('asset-server-address')
+ ..addOption('asset-server-port')
+ ..addFlag('track-widget-creation', defaultsTo: false)
+ ..addFlag('sound-null-safety', defaultsTo: false)
+ ..addFlag('verbose', defaultsTo: false);
+
+Uri _argToUri(String uriArg) =>
+ uriArg == null ? null : Uri.base.resolve(uriArg.replaceAll('\\', '/'));
diff --git a/pkg/dev_compiler/pubspec.yaml b/pkg/dev_compiler/pubspec.yaml
index 48ed14f..73cdcc9 100644
--- a/pkg/dev_compiler/pubspec.yaml
+++ b/pkg/dev_compiler/pubspec.yaml
@@ -23,6 +23,8 @@
path: any
source_maps: any
source_span: any
+ vm:
+ path: ../vm
dev_dependencies:
analyzer: any
diff --git a/pkg/frontend_server/test/src/expression_compiler_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
similarity index 95%
rename from pkg/frontend_server/test/src/expression_compiler_test.dart
rename to pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
index 2dabd91..7374f49 100644
--- a/pkg/frontend_server/test/src/expression_compiler_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
@@ -1,6 +1,6 @@
-// Copyright 2020 The Chromium Authors. 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 Platform, File;
+// Copyright (c) 2020, 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 Directory, File;
@@ -11,7 +11,6 @@
show CompilerOptions;
import 'package:front_end/src/compute_platform_binaries_location.dart';
import 'package:front_end/src/fasta/incremental_serializer.dart';
-import 'package:frontend_server/src/expression_compiler.dart';
import 'package:kernel/ast.dart' show Component;
import 'package:kernel/target/targets.dart';
import 'package:path/path.dart' as p;
@@ -29,8 +28,8 @@
bool outlineOnly,
IncrementalSerializer incrementalSerializer])
: super(
- new CompilerContext(
- new ProcessedOptions(options: options, inputs: [entryPoint])),
+ CompilerContext(
+ ProcessedOptions(options: options, inputs: [entryPoint])),
initializeFrom,
outlineOnly,
incrementalSerializer);
@@ -39,8 +38,8 @@
this.entryPoint, Component componentToInitializeFrom,
[bool outlineOnly, IncrementalSerializer incrementalSerializer])
: super.fromComponent(
- new CompilerContext(
- new ProcessedOptions(options: options, inputs: [entryPoint])),
+ CompilerContext(
+ ProcessedOptions(options: options, inputs: [entryPoint])),
componentToInitializeFrom,
outlineOnly,
incrementalSerializer);
@@ -104,6 +103,7 @@
String get package => importUri.toString();
String get file => fileUri.path;
+ @override
String toString() =>
'Name: $name, File: $file, Package: $package, path: $path';
}
@@ -140,13 +140,13 @@
kernel2jsCompiler.emitModule(component);
// create expression compiler
- var evaluator = new ExpressionCompiler(
- compiler, kernel2jsCompiler, component,
+ var evaluator = ExpressionCompiler(compiler, kernel2jsCompiler, component,
verbose: setup.options.verbose,
- onDiagnostic: setup.options.onDiagnostic);
+ onDiagnostic: setup.options.onDiagnostic,
+ errors: setup.errors);
// collect all module names and paths
- Map<Uri, Module> moduleInfo = _collectModules(component);
+ var moduleInfo = _collectModules(component);
var modules =
moduleInfo.map((k, v) => MapEntry<String, String>(v.name, v.path));
@@ -161,7 +161,7 @@
var jsExpression = await evaluator.compileExpressionToJs(
module.package, line, column, modules, scope, module.name, expression);
- if (setup.errors.length > 0) {
+ if (setup.errors.isNotEmpty) {
jsExpression = setup.errors.toString().replaceAll(
RegExp(
r'org-dartlang-debug:synthetic_debug_expression:[0-9]*:[0-9]*:'),
@@ -174,7 +174,7 @@
}
Map<Uri, Module> _collectModules(Component component) {
- Map<Uri, Module> modules = <Uri, Module>{};
+ var modules = <Uri, Module>{};
for (var library in component.libraries) {
modules[library.fileUri] = Module(library.importUri, library.fileUri);
}
@@ -239,10 +239,10 @@
}
int _getEvaluationLine(String source) {
- RegExp placeholderRegExp = RegExp(r'/\* evaluation placeholder \*/');
+ var placeholderRegExp = RegExp(r'/\* evaluation placeholder \*/');
var lines = source.split('\n');
- for (int line = 0; line < lines.length; line++) {
+ for (var line = 0; line < lines.length; line++) {
var content = lines[line];
if (placeholderRegExp.firstMatch(content) != null) {
return line + 1;
@@ -253,10 +253,10 @@
}
void main() {
- SetupCompilerOptions options = SetupCompilerOptions();
+ var options = SetupCompilerOptions();
group('Expression compiler tests in extension method:', () {
- const String source = '''
+ const source = '''
extension NumberParsing on String {
int parseInt() {
var ret = int.parse(this);
@@ -306,7 +306,7 @@
});
group('Expression compiler tests in method:', () {
- const String source = '''
+ const source = '''
extension NumberParsing on String {
int parseInt() {
return int.parse(this);
@@ -559,7 +559,7 @@
});
group('Expression compiler tests in method with no field access:', () {
- const String source = '''
+ const source = '''
extension NumberParsing on String {
int parseInt() {
return int.parse(this);
@@ -720,7 +720,7 @@
});
group('Expression compiler tests in async method:', () {
- const String source = '''
+ const source = '''
class C {
C(int this.field, int this._field);
@@ -780,7 +780,7 @@
});
group('Expression compiler tests in global function:', () {
- const String source = '''
+ const source = '''
extension NumberParsing on String {
int parseInt() {
return int.parse(this);
@@ -1038,7 +1038,7 @@
});
group('Expression compiler tests in closures:', () {
- const String source = r'''
+ const source = r'''
int globalFunction() {
int x = 15;
var c = C(1, 2);
@@ -1102,7 +1102,7 @@
});
group('Expression compiler tests in method with no type use', () {
- const String source = '''
+ const source = '''
abstract class Key {
const factory Key(String value) = ValueKey;
const Key.empty();
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart
new file mode 100644
index 0000000..18fa6ce
--- /dev/null
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart
@@ -0,0 +1,647 @@
+// Copyright (c) 2020, 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:async';
+import 'dart:convert';
+import 'dart:io' show Directory, File, Platform, Process, stderr, stdout;
+
+import 'package:build_integration/file_system/multi_root.dart';
+import 'package:front_end/src/api_prototype/standard_file_system.dart';
+import 'package:front_end/src/compute_platform_binaries_location.dart';
+import 'package:path/path.dart' as p;
+import 'package:pedantic/pedantic.dart';
+import 'package:test/test.dart';
+
+import 'package:dev_compiler/src/kernel/expression_compiler_worker.dart';
+
+/// Verbose mode for debugging
+bool get verbose => false;
+
+class ModuleConfiguration {
+ final String outputPath;
+ final String moduleName;
+ final String libraryUri;
+ final String jsFileName;
+ final String fullDillFileName;
+
+ ModuleConfiguration(
+ {this.outputPath,
+ this.moduleName,
+ this.libraryUri,
+ this.jsFileName,
+ this.fullDillFileName});
+
+ String get jsPath => p.join(outputPath, jsFileName);
+ String get fullDillPath => p.join(outputPath, fullDillFileName);
+}
+
+class TestProjectConfiguration {
+ final Directory rootDirectory;
+ final String outputDir = 'out';
+
+ TestProjectConfiguration(this.rootDirectory);
+
+ ModuleConfiguration get mainModule => ModuleConfiguration(
+ outputPath: outputPath,
+ moduleName: 'packages/_testPackage/main',
+ libraryUri: 'org-dartlang-app:/lib/main.dart',
+ jsFileName: 'main.js',
+ fullDillFileName: 'main.full.dill');
+
+ ModuleConfiguration get testModule => ModuleConfiguration(
+ outputPath: outputPath,
+ moduleName: 'packages/_testPackage/test_library',
+ libraryUri: 'package:_testPackage/test_library.dart',
+ jsFileName: 'test_library.js',
+ fullDillFileName: 'test_library.full.dill');
+
+ ModuleConfiguration get testModule2 => ModuleConfiguration(
+ outputPath: outputPath,
+ moduleName: 'packages/_testPackage/test_library2',
+ libraryUri: 'package:_testPackage/test_library2.dart',
+ jsFileName: 'test_library2.js',
+ fullDillFileName: 'test_library2.full.dill');
+
+ String get root => rootDirectory.path;
+ String get outputPath => p.join(root, outputDir);
+ String get packagesPath => p.join(root, '.packages');
+
+ String get sdkRoot => computePlatformBinariesLocation().path;
+ String get sdkSummaryPath => p.join(sdkRoot, 'ddc_sdk.dill');
+ String get librariesPath => p.join(sdkRoot, 'lib', 'libraries.json');
+
+ void createTestProject() {
+ var pubspec = rootDirectory.uri.resolve('pubspec.yaml');
+ File.fromUri(pubspec)
+ ..createSync()
+ ..writeAsStringSync('''
+name: _testPackage
+version: 1.0.0
+
+environment:
+ sdk: '>=2.8.0 <3.0.0'
+''');
+
+ var packages = rootDirectory.uri.resolve('.packages');
+ File.fromUri(packages)
+ ..createSync()
+ ..writeAsStringSync('''
+_testPackage:lib/
+''');
+
+ var main = rootDirectory.uri.resolve('lib/main.dart');
+ File.fromUri(main)
+ ..createSync(recursive: true)
+ ..writeAsStringSync('''
+import 'package:_testPackage/test_library.dart';
+
+var global = 0;
+
+void main() {
+ var count = 0;
+ // line 7
+ print('Global is: \${++global}');
+ print('Count is: \${++count}');
+
+ B b = new B();
+}
+''');
+
+ var testLibrary = rootDirectory.uri.resolve('lib/test_library.dart');
+ File.fromUri(testLibrary)
+ ..createSync()
+ ..writeAsStringSync('''
+import 'package:_testPackage/test_library2.dart';
+
+int testLibraryFunction(int formal) {
+ return formal; // line 4
+}
+
+int callLibraryFunction2(int formal) {
+ return testLibraryFunction2(formal); // line 8
+}
+
+class B {
+ C c() => new C();
+}
+''');
+
+ var testLibrary2 = rootDirectory.uri.resolve('lib/test_library2.dart');
+ File.fromUri(testLibrary2)
+ ..createSync()
+ ..writeAsStringSync('''
+int testLibraryFunction2(int formal) {
+ return formal; // line 2
+}
+
+class C {
+ int getNumber() => 42;
+}
+''');
+ }
+}
+
+void main() async {
+ group('Expression compiler worker (webdev simulation) - ', () {
+ ExpressionCompilerWorker worker;
+ Future workerDone;
+ StreamController<Map<String, dynamic>> requestController;
+ StreamController<Map<String, dynamic>> responseController;
+ Directory tempDir;
+ TestProjectConfiguration config;
+ List inputs;
+
+ setUpAll(() async {
+ tempDir = Directory.systemTemp.createTempSync('foo bar');
+ config = TestProjectConfiguration(tempDir);
+
+ // simulate webdev
+ config.createTestProject();
+ var kernelGenerator = DDCKernelGenerator(config);
+ await kernelGenerator.generate();
+
+ inputs = [
+ {
+ 'path': config.mainModule.fullDillPath,
+ 'moduleName': config.mainModule.moduleName
+ },
+ {
+ 'path': config.testModule.fullDillPath,
+ 'moduleName': config.testModule.moduleName
+ },
+ {
+ 'path': config.testModule2.fullDillPath,
+ 'moduleName': config.testModule2.moduleName
+ },
+ ];
+ });
+
+ tearDownAll(() async {
+ tempDir.deleteSync(recursive: true);
+ });
+
+ setUp(() async {
+ var fileSystem = MultiRootFileSystem(
+ 'org-dartlang-app', [tempDir.uri], StandardFileSystem.instance);
+
+ requestController = StreamController<Map<String, dynamic>>();
+ responseController = StreamController<Map<String, dynamic>>();
+ worker = await ExpressionCompilerWorker.create(
+ librariesSpecificationUri: Uri.file(config.librariesPath),
+ // We should be able to load everything from dill and not require
+ // source parsing. Webdev and google3 integration currently rely on that.
+ // Make the test fail on source reading by not providing a packages.
+ packagesFile: null,
+ sdkSummary: Uri.file(config.sdkSummaryPath),
+ fileSystem: fileSystem,
+ requestStream: requestController.stream,
+ sendResponse: responseController.add,
+ verbose: verbose,
+ );
+ workerDone = worker.start();
+ });
+
+ tearDown(() async {
+ unawaited(requestController.close());
+ await workerDone;
+ unawaited(responseController.close());
+ });
+
+ test('can load dependencies and compile expressions in sdk', () async {
+ requestController.add({
+ 'command': 'UpdateDeps',
+ 'inputs': inputs,
+ });
+
+ requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'other',
+ 'line': 107,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {'other': 'other'},
+ 'libraryUri': 'dart:collection',
+ 'moduleName': 'dart_sdk',
+ });
+
+ expect(
+ responseController.stream,
+ emitsInOrder([
+ equals({
+ 'succeeded': true,
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'compiledProcedure': contains('return other;'),
+ })
+ ]));
+ }, skip: 'Evaluating expressions in SDK is not supported yet');
+
+ test('can load dependencies and compile expressions in a library',
+ () async {
+ requestController.add({
+ 'command': 'UpdateDeps',
+ 'inputs': inputs,
+ });
+
+ requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'formal',
+ 'line': 4,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {'formal': 'formal'},
+ 'libraryUri': config.testModule.libraryUri,
+ 'moduleName': config.testModule.moduleName,
+ });
+
+ expect(
+ responseController.stream,
+ emitsInOrder([
+ equals({
+ 'succeeded': true,
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'compiledProcedure': contains('return formal;'),
+ })
+ ]));
+ });
+
+ test('can load dependencies and compile expressions in main', () async {
+ requestController.add({
+ 'command': 'UpdateDeps',
+ 'inputs': inputs,
+ });
+
+ requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'count',
+ 'line': 7,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {'count': 'count'},
+ 'libraryUri': config.mainModule.libraryUri,
+ 'moduleName': config.mainModule.moduleName,
+ });
+
+ expect(
+ responseController.stream,
+ emitsInOrder([
+ equals({
+ 'succeeded': true,
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'compiledProcedure': contains('return count;'),
+ })
+ ]));
+ });
+
+ test('can load dependencies and compile transitive expressions in main',
+ () async {
+ requestController.add({
+ 'command': 'UpdateDeps',
+ 'inputs': inputs,
+ });
+
+ requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'B().c().getNumber()',
+ 'line': 7,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {},
+ 'libraryUri': config.mainModule.libraryUri,
+ 'moduleName': config.mainModule.moduleName,
+ });
+
+ expect(
+ responseController.stream,
+ emitsInOrder([
+ equals({
+ 'succeeded': true,
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'compiledProcedure':
+ contains('return new test_library.B.new().c().getNumber()'),
+ })
+ ]));
+ });
+ });
+
+ group('Expression compiler worker (google3 simulation) - ', () {
+ ExpressionCompilerWorker worker;
+ Future workerDone;
+ StreamController<Map<String, dynamic>> requestController;
+ StreamController<Map<String, dynamic>> responseController;
+ Directory tempDir;
+ TestProjectConfiguration config;
+ List inputs;
+
+ setUpAll(() async {
+ tempDir = Directory.systemTemp.createTempSync('foo bar');
+ config = TestProjectConfiguration(tempDir);
+
+ // simulate google3
+ config.createTestProject();
+ var kernelGenerator = BazelKernelWorkerGenerator(config);
+ await kernelGenerator.generate();
+
+ inputs = [
+ {
+ 'path': config.mainModule.fullDillPath,
+ 'moduleName': config.mainModule.moduleName
+ },
+ ];
+ });
+
+ tearDownAll(() async {
+ tempDir.deleteSync(recursive: true);
+ });
+
+ setUp(() async {
+ var fileSystem = MultiRootFileSystem(
+ 'org-dartlang-app', [tempDir.uri], StandardFileSystem.instance);
+
+ requestController = StreamController<Map<String, dynamic>>();
+ responseController = StreamController<Map<String, dynamic>>();
+ worker = await ExpressionCompilerWorker.create(
+ librariesSpecificationUri: Uri.file(config.librariesPath),
+ packagesFile: null,
+ sdkSummary: Uri.file(config.sdkSummaryPath),
+ fileSystem: fileSystem,
+ requestStream: requestController.stream,
+ sendResponse: responseController.add,
+ verbose: verbose,
+ );
+ workerDone = worker.start();
+ });
+
+ tearDown(() async {
+ unawaited(requestController.close());
+ await workerDone;
+ unawaited(responseController.close());
+ });
+
+ test('can load dependencies and compile expressions in sdk', () async {
+ requestController.add({
+ 'command': 'UpdateDeps',
+ 'inputs': inputs,
+ });
+
+ requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'other',
+ 'line': 107,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {'other': 'other'},
+ 'libraryUri': 'dart:collection',
+ 'moduleName': 'dart_sdk',
+ });
+
+ expect(
+ responseController.stream,
+ emitsInOrder([
+ equals({
+ 'succeeded': true,
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'compiledProcedure': contains('return other;'),
+ })
+ ]));
+ }, skip: 'Evaluating expressions in SDK is not supported yet');
+
+ test('can load dependencies and compile expressions in a library',
+ () async {
+ requestController.add({
+ 'command': 'UpdateDeps',
+ 'inputs': inputs,
+ });
+
+ requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'formal',
+ 'line': 4,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {'formal': 'formal'},
+ 'libraryUri': config.testModule.libraryUri,
+ 'moduleName': config.mainModule.moduleName,
+ });
+
+ expect(
+ responseController.stream,
+ emitsInOrder([
+ equals({
+ 'succeeded': true,
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'compiledProcedure': contains('return formal;'),
+ })
+ ]));
+ });
+
+ test('can load dependencies and compile expressions in main', () async {
+ requestController.add({
+ 'command': 'UpdateDeps',
+ 'inputs': inputs,
+ });
+
+ requestController.add({
+ 'command': 'CompileExpression',
+ 'expression': 'count',
+ 'line': 7,
+ 'column': 1,
+ 'jsModules': {},
+ 'jsScope': {'count': 'count'},
+ 'libraryUri': config.mainModule.libraryUri,
+ 'moduleName': config.mainModule.moduleName,
+ });
+
+ expect(
+ responseController.stream,
+ emitsInOrder([
+ equals({
+ 'succeeded': true,
+ }),
+ equals({
+ 'succeeded': true,
+ 'errors': isEmpty,
+ 'warnings': isEmpty,
+ 'compiledProcedure': contains('return count;'),
+ })
+ ]));
+ });
+ }, skip: 'bazel kernel worker does not support full kernel generation yet');
+}
+
+/// Uses DDC to generate kernel from the test code
+/// in order to simulate webdev environment
+class DDCKernelGenerator {
+ final TestProjectConfiguration config;
+
+ DDCKernelGenerator(this.config);
+
+ Future<int> generate() async {
+ var dart = Platform.resolvedExecutable;
+ var dartdevc =
+ p.join(p.dirname(dart), 'snapshots', 'dartdevc.dart.snapshot');
+
+ Directory(config.outputPath)..createSync();
+
+ // generate test_library2.full.dill
+ var args = [
+ dartdevc,
+ config.testModule2.libraryUri,
+ '--no-summarize',
+ '-o',
+ config.testModule2.jsPath,
+ '--source-map',
+ '--experimental-emit-debug-metadata',
+ '--experimental-output-compiled-kernel',
+ '--dart-sdk-summary',
+ config.sdkSummaryPath,
+ '--multi-root',
+ config.root,
+ '--multi-root-scheme',
+ 'org-dartlang-app',
+ '--packages',
+ config.packagesPath,
+ ];
+
+ var exitCode = await runProcess(dart, args, config.root);
+ if (exitCode != 0) {
+ return exitCode;
+ }
+
+ // generate test_library.full.dill
+ args = [
+ dartdevc,
+ config.testModule.libraryUri,
+ '--no-summarize',
+ '--summary',
+ '${config.testModule2.fullDillPath}=${config.testModule2.moduleName}',
+ '-o',
+ config.testModule.jsPath,
+ '--source-map',
+ '--experimental-emit-debug-metadata',
+ '--experimental-output-compiled-kernel',
+ '--dart-sdk-summary',
+ config.sdkSummaryPath,
+ '--multi-root',
+ config.root,
+ '--multi-root-scheme',
+ 'org-dartlang-app',
+ '--packages',
+ config.packagesPath,
+ ];
+
+ exitCode = await runProcess(dart, args, config.root);
+ if (exitCode != 0) {
+ return exitCode;
+ }
+
+ // generate main.full.dill
+ args = [
+ dartdevc,
+ config.mainModule.libraryUri,
+ '--no-summarize',
+ '--summary',
+ '${config.testModule2.fullDillPath}=${config.testModule2.moduleName}',
+ '--summary',
+ '${config.testModule.fullDillPath}=${config.testModule.moduleName}',
+ '-o',
+ config.mainModule.jsPath,
+ '--source-map',
+ '--experimental-emit-debug-metadata',
+ '--experimental-output-compiled-kernel',
+ '--dart-sdk-summary',
+ config.sdkSummaryPath,
+ '--multi-root',
+ config.root,
+ '--multi-root-scheme',
+ 'org-dartlang-app',
+ '--packages',
+ config.packagesPath,
+ ];
+
+ return await runProcess(dart, args, config.root);
+ }
+}
+
+/// Uses bazel kernel worker to generate kernel from test code
+/// in order to simulate google3 environment
+/// TODO: split into 3 modules
+class BazelKernelWorkerGenerator {
+ TestProjectConfiguration config;
+
+ BazelKernelWorkerGenerator(this.config);
+
+ Future<void> generate() async {
+ var dart = Platform.resolvedExecutable;
+ var kernelWorker =
+ p.join(p.dirname(dart), 'snapshots', 'kernel_worker.dart.snapshot');
+
+ var args = [
+ kernelWorker,
+ '--target',
+ 'ddc',
+ '--output',
+ config.mainModule.fullDillPath,
+ '--dart-sdk-summary',
+ config.sdkSummaryPath,
+ '--exclude-non-sources',
+ '--source',
+ config.mainModule.libraryUri,
+ '--source',
+ config.testModule.libraryUri,
+ '--source',
+ config.testModule2.libraryUri,
+ '--multi-root',
+ config.root,
+ '--multi-root-scheme',
+ 'org-dartlang-app',
+ '--packages-file',
+ '.packages',
+ '--verbose'
+ ];
+
+ return await runProcess(dart, args, config.root);
+ }
+}
+
+Future<int> runProcess(
+ String command, List<String> args, String workingDirectory) async {
+ if (verbose) {
+ print('Running command in $workingDirectory:'
+ '\n\t $command ${args.join(' ')}, ');
+ }
+ var process =
+ await Process.start(command, args, workingDirectory: workingDirectory)
+ .then((Process process) {
+ process
+ ..stdout.transform(utf8.decoder).listen(stdout.write)
+ ..stderr.transform(utf8.decoder).listen(stderr.write);
+ return process;
+ });
+
+ return await process.exitCode;
+}
diff --git a/pkg/frontend_server/lib/frontend_server.dart b/pkg/frontend_server/lib/frontend_server.dart
index 35f5631..af48251 100644
--- a/pkg/frontend_server/lib/frontend_server.dart
+++ b/pkg/frontend_server/lib/frontend_server.dart
@@ -9,7 +9,8 @@
import 'dart:io' hide FileSystemEntity;
import 'package:args/args.dart';
-import 'package:dev_compiler/dev_compiler.dart' show DevCompilerTarget;
+import 'package:dev_compiler/dev_compiler.dart'
+ show DevCompilerTarget, ExpressionCompiler;
// front_end/src imports below that require lint `ignore_for_file`
// are a temporary state of things until frontend team builds better api
@@ -39,7 +40,6 @@
import 'src/javascript_bundle.dart';
import 'src/strong_components.dart';
-import 'src/expression_compiler.dart';
ArgParser argParser = ArgParser(allowTrailingOptions: true)
..addFlag('train',
@@ -968,7 +968,8 @@
var evaluator = new ExpressionCompiler(
_generator.generator, kernel2jsCompiler, component,
verbose: _compilerOptions.verbose,
- onDiagnostic: _compilerOptions.onDiagnostic);
+ onDiagnostic: _compilerOptions.onDiagnostic,
+ errors: errors);
var procedure = await evaluator.compileExpressionToJs(libraryUri, line,
column, jsModules, jsFrameValues, moduleName, expression);
diff --git a/pkg/frontend_server/pubspec.yaml b/pkg/frontend_server/pubspec.yaml
index 6f96f7e..7932dab 100644
--- a/pkg/frontend_server/pubspec.yaml
+++ b/pkg/frontend_server/pubspec.yaml
@@ -7,8 +7,6 @@
sdk: "^2.7.0"
dependencies:
- _fe_analyzer_shared:
- path: ../_fe_analyzer_shared
args: ^1.4.4
dev_compiler:
path: ../dev_compiler
@@ -23,6 +21,5 @@
path: ../vm
dev_dependencies:
- cli_util: any
mockito: any
test: any
diff --git a/tools/VERSION b/tools/VERSION
index b464eb3..fc575db 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 10
PATCH 0
-PRERELEASE 92
+PRERELEASE 93
PRERELEASE_PATCH 0
\ No newline at end of file