[ddc] Use LibraryBundleCompiler in expression eval

When the canary and ddc modules flags are passed together use the
expression compiler worker uses the LibraryBundleCompiler to compile
the expression to be evaluated. This ensures the compiler JavaScript
matches the expected format and representation of the compiled library.

Change-Id: I4667522a6640707265a3f38770a17fd696c840f4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/479400
Reviewed-by: Mark Zhou <markzipan@google.com>
Commit-Queue: Nicholas Shahan <nshahan@google.com>
This commit is contained in:
Nicholas Shahan
2026-02-10 16:58:36 -08:00
committed by Commit Queue
parent eee4dfa5e7
commit e7d8b99bb6
2 changed files with 160 additions and 38 deletions
@@ -25,6 +25,7 @@ import '../compiler/js_names.dart';
import '../compiler/module_builder.dart' show ModuleFormat, parseModuleFormat;
import 'asset_file_system.dart';
import 'compiler.dart' show ProgramCompiler;
import 'compiler_new.dart' show LibraryBundleCompiler;
import 'expression_compiler.dart' show ExpressionCompiler;
import 'target.dart' show DevCompilerTarget;
@@ -497,22 +498,40 @@ class ExpressionCompilerWorker {
var coreTypes = incrementalCompilerResult.coreTypes;
var hierarchy = incrementalCompilerResult.classHierarchy;
var kernel2jsCompiler = ProgramCompiler(
finalComponent,
hierarchy,
Options(
sourceMap: true,
summarizeApi: false,
moduleName: moduleName,
canaryFeatures: _canaryFeatures,
enableAsserts: _enableAsserts,
),
_moduleCache.componentForLibrary,
_moduleCache.moduleNameForComponent,
coreTypes: coreTypes,
ticker: _processedOptions.ticker,
var options = Options(
sourceMap: true,
summarizeApi: false,
moduleName: moduleName,
moduleFormats: [_moduleFormat],
canaryFeatures: _canaryFeatures,
enableAsserts: _enableAsserts,
);
if (isSdk && options.emitLibraryBundle) {
errors.add(
'Expression evaluation in the context of an SDK library '
'is not currently supported in this environment.',
);
return null;
}
var kernel2jsCompiler = options.emitLibraryBundle
? LibraryBundleCompiler(
finalComponent,
hierarchy,
options,
_moduleCache.componentForLibrary,
_moduleCache.moduleNameForComponent,
coreTypes: coreTypes,
ticker: _processedOptions.ticker,
)
: ProgramCompiler(
finalComponent,
hierarchy,
options,
_moduleCache.componentForLibrary,
_moduleCache.moduleNameForComponent,
coreTypes: coreTypes,
ticker: _processedOptions.ticker,
);
assert(
originalComponent.libraries.toSet().length ==
originalComponent.libraries.length,
@@ -538,9 +557,7 @@ class ExpressionCompilerWorker {
expressionCompiler = ExpressionCompiler(
_compilerOptions,
_moduleFormat == ModuleFormat.ddc && _canaryFeatures
? ModuleFormat.ddcLibraryBundle
: _moduleFormat,
options.emitLibraryBundle ? ModuleFormat.ddcLibraryBundle : _moduleFormat,
errors,
incrementalCompiler,
kernel2jsCompiler,
@@ -125,16 +125,30 @@ void runExpressionCompilationTests(ExpressionCompilerWorkerTestDriver driver) {
driver.responseController.stream,
emitsInOrder([
equals({'succeeded': true}),
equals({
'succeeded': true,
'errors': isEmpty,
'warnings': isEmpty,
'infos': isEmpty,
'compiledProcedure': stringContainsInOrder([
'developer',
'postEvent',
]),
}),
// TODO(nshahan): https://github.com/dart-lang/sdk/issues/62643
if (driver.setup.canaryFeatures &&
driver.setup.moduleFormat == ModuleFormat.ddc)
equals({
'succeeded': false,
'errors': [
'Expression evaluation in the context of an SDK library '
'is not currently supported in this environment.',
],
'warnings': [],
'infos': [],
'compiledProcedure': null,
})
else
equals({
'succeeded': true,
'errors': isEmpty,
'warnings': isEmpty,
'infos': isEmpty,
'compiledProcedure': stringContainsInOrder([
'developer',
'postEvent',
]),
}),
]),
);
});
@@ -161,16 +175,30 @@ void runExpressionCompilationTests(ExpressionCompilerWorkerTestDriver driver) {
driver.responseController.stream,
emitsInOrder([
equals({'succeeded': true}),
equals({
'succeeded': true,
'errors': isEmpty,
'warnings': isEmpty,
'infos': isEmpty,
'compiledProcedure': stringContainsInOrder([
'developer',
'postEvent',
]),
}),
// TODO(nshahan): https://github.com/dart-lang/sdk/issues/62643
if (driver.setup.canaryFeatures &&
driver.setup.moduleFormat == ModuleFormat.ddc)
equals({
'succeeded': false,
'errors': [
'Expression evaluation in the context of an SDK library '
'is not currently supported in this environment.',
],
'warnings': [],
'infos': [],
'compiledProcedure': null,
})
else
equals({
'succeeded': true,
'errors': isEmpty,
'warnings': isEmpty,
'infos': isEmpty,
'compiledProcedure': stringContainsInOrder([
'developer',
'postEvent',
]),
}),
]),
);
});
@@ -366,6 +394,48 @@ void runExpressionCompilationTests(ExpressionCompilerWorkerTestDriver driver) {
},
);
test(
'compile expressions include correct import format for module system',
() {
driver.requestController.add({
'command': 'UpdateDeps',
'inputs': driver.inputs,
});
driver.requestController.add({
'command': 'CompileExpression',
'expression': '5 is int && 5.isOdd',
'line': 5,
'column': 1,
'jsModules': {},
'jsScope': {'formal': 'formal'},
'libraryUri': driver.config.getModule('testModule').libraryUris.first,
'moduleName': driver.config.getModule('testModule').moduleName,
});
expect(
driver.responseController.stream,
emitsInOrder([
equals({'succeeded': true}),
equals({
'succeeded': true,
'errors': isEmpty,
'warnings': isEmpty,
'infos': isEmpty,
'compiledProcedure': driver.setup.emitLibraryBundle
? StringContainsUnordered([
'"dart:core"',
'"dart:_runtime"',
'"dart:_rti"',
'"dartx"',
])
: contains('\'dart_sdk\''),
}),
]),
);
},
);
test('can compile expressions in main', () {
driver.requestController.add({
'command': 'UpdateDeps',
@@ -1685,3 +1755,38 @@ Future<int> runProcess(
return await process.exitCode;
}
/// A matcher that checks if a string contains all of the expected substrings in
/// any order.
class StringContainsUnordered extends Matcher {
final List<String> _expected;
StringContainsUnordered(this._expected);
@override
bool matches(item, Map matchState) {
if (item is! String) return false;
for (var expected in _expected) {
if (!item.contains(expected)) return false;
}
return true;
}
@override
Description describe(Description description) =>
description.add('contains all of ').addDescriptionOf(_expected);
@override
Description describeMismatch(
item,
Description mismatchDescription,
Map matchState,
bool verbose,
) {
if (item is! String) {
return mismatchDescription.add('is not a string');
}
var missing = _expected.where((e) => !item.contains(e)).toList();
return mismatchDescription.add('is missing ').addDescriptionOf(missing);
}
}