Reland "[ddc] Add web library environment variables"

This is a reland of fb36bba5f2 with
a fix to the ordering to ensure all the expectations run.

Original change's description:
> [ddc] Add web library environment variables
>
> Ensure frontend server builds for the `DevCompilerTarget` add the
> environment variables needed for `bool.fromEnvironment()` calls for
> conditional imports.
>
> Change-Id: Ifd372c1cf385fc843534d85af1ac9ae75a6285b8
> Fixes: https://github.com/dart-lang/sdk/issues/47207
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/213802
> Commit-Queue: Nicholas Shahan <nshahan@google.com>
> Reviewed-by: Johnni Winther <johnniwinther@google.com>

Change-Id: Id88aeaf0ddc783936d413c06099df031bc7cb0a7
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/214224
Reviewed-by: Anna Gringauze <annagrin@google.com>
Commit-Queue: Nicholas Shahan <nshahan@google.com>
This commit is contained in:
Nicholas Shahan 2021-09-22 23:47:40 +00:00 committed by commit-bot@chromium.org
parent 68aac9d9ec
commit 6c4593929f
6 changed files with 187 additions and 31 deletions

View file

@ -23,34 +23,6 @@ import 'module_builder.dart';
/// This file should only implement functionality that does not depend on
/// Analyzer/Kernel imports.
/// Variables that indicate which libraries are available in dev compiler.
// TODO(jmesserly): provide an option to compile without dart:html & friends?
Map<String, String> sdkLibraryVariables = {
'dart.isVM': 'false',
'dart.library.async': 'true',
'dart.library.core': 'true',
'dart.library.collection': 'true',
'dart.library.convert': 'true',
// TODO(jmesserly): this is not really supported in dart4web other than
// `debugger()`
'dart.library.developer': 'true',
'dart.library.io': 'false',
'dart.library.isolate': 'false',
'dart.library.js': 'true',
'dart.library.js_util': 'true',
'dart.library.math': 'true',
'dart.library.mirrors': 'false',
'dart.library.typed_data': 'true',
'dart.library.indexed_db': 'true',
'dart.library.html': 'true',
'dart.library.html_common': 'true',
'dart.library.svg': 'true',
'dart.library.ui': 'false',
'dart.library.web_audio': 'true',
'dart.library.web_gl': 'true',
'dart.library.web_sql': 'true',
};
/// Compiler options for the `dartdevc` backend.
class SharedCompilerOptions {
/// Whether to emit the source mapping file.

View file

@ -819,7 +819,8 @@ Map<String, String> parseAndRemoveDeclaredVariables(List<String> args) {
}
// Add platform defined variables
declaredVariables.addAll(sdkLibraryVariables);
// TODO(47243) Remove when all code paths read these from the `Target`.
declaredVariables.addAll(sdkLibraryEnvironmentDefines);
return declaredVariables;
}

View file

@ -12,6 +12,8 @@ import 'dart:isolate';
import 'package:args/args.dart';
import 'package:build_integration/file_system/multi_root.dart';
import 'package:dev_compiler/dev_compiler.dart';
import 'package:dev_compiler/src/kernel/target.dart'
show sdkLibraryEnvironmentDefines;
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;
@ -206,7 +208,7 @@ class ExpressionCompilerWorker {
@required Uri sdkSummary,
@required FileSystem fileSystem,
Uri packagesFile,
Map<String, String> environmentDefines = const {},
Map<String, String> environmentDefines,
Map<ExperimentalFlag, bool> explicitExperimentalFlags = const {},
Uri sdkRoot,
bool trackWidgetCreation = false,
@ -228,7 +230,11 @@ class ExpressionCompilerWorker {
TargetFlags(trackWidgetCreation: trackWidgetCreation))
..fileSystem = fileSystem
..omitPlatform = true
..environmentDefines = environmentDefines
..environmentDefines = {
if (environmentDefines != null) ...environmentDefines,
// TODO(47243) Remove when all code paths read these from the `Target`.
...sdkLibraryEnvironmentDefines
}
..explicitExperimentalFlags = explicitExperimentalFlags
..onDiagnostic = _onDiagnosticHandler(errors, warnings, infos)
..nnbdMode = soundNullSafety ? NnbdMode.Strong : NnbdMode.Weak

View file

@ -19,6 +19,35 @@ import 'package:kernel/transformations/track_widget_constructor_locations.dart';
import 'constants.dart' show DevCompilerConstantsBackend;
import 'kernel_helpers.dart';
/// Boolean environment variables that indicate which libraries are available in
/// dev compiler.
// TODO(jmesserly): provide an option to compile without dart:html & friends?
const sdkLibraryEnvironmentDefines = {
'dart.isVM': 'false',
'dart.library.async': 'true',
'dart.library.core': 'true',
'dart.library.collection': 'true',
'dart.library.convert': 'true',
// TODO(jmesserly): this is not really supported in dart4web other than
// `debugger()`
'dart.library.developer': 'true',
'dart.library.io': 'false',
'dart.library.isolate': 'false',
'dart.library.js': 'true',
'dart.library.js_util': 'true',
'dart.library.math': 'true',
'dart.library.mirrors': 'false',
'dart.library.typed_data': 'true',
'dart.library.indexed_db': 'true',
'dart.library.html': 'true',
'dart.library.html_common': 'true',
'dart.library.svg': 'true',
'dart.library.ui': 'false',
'dart.library.web_audio': 'true',
'dart.library.web_gl': 'true',
'dart.library.web_sql': 'true',
};
/// A kernel [Target] to configure the Dart Front End for dartdevc.
class DevCompilerTarget extends Target {
DevCompilerTarget(this.flags);
@ -30,6 +59,10 @@ class DevCompilerTarget extends Target {
Map<String, Class>? _nativeClasses;
@override
Map<String, String> updateEnvironmentDefines(Map<String, String> map) =>
map..addAll(sdkLibraryEnvironmentDefines);
@override
bool get enableSuperMixins => true;

View file

@ -175,6 +175,40 @@ void runExpressionCompilationTests(TestDriver driver) {
]));
});
test('compile expressions include "dart.library..." environment defines.',
() async {
driver.requestController.add({
'command': 'UpdateDeps',
'inputs': driver.inputs,
});
driver.requestController.add({
'command': 'CompileExpression',
'expression': 'const bool.fromEnvironment("dart.library.html")',
'line': 5,
'column': 1,
'jsModules': {},
'jsScope': {'formal': 'formal'},
'libraryUri': driver.config.testModule.libraryUri,
'moduleName': driver.config.testModule.moduleName,
});
expect(
driver.responseController.stream,
emitsInOrder([
equals({
'succeeded': true,
}),
equals({
'succeeded': true,
'errors': isEmpty,
'warnings': isEmpty,
'infos': isEmpty,
'compiledProcedure': contains('true'),
})
]));
});
test('can compile expressions in main', () async {
driver.requestController.add({
'command': 'UpdateDeps',

View file

@ -2327,6 +2327,116 @@ class BarState extends State<FizzWidget> {
expect(count, 3);
});
test('compiled Javascript includes web library environment defines',
() async {
var file = File('${tempDir.path}/foo.dart')..createSync();
file.writeAsStringSync(
"main() {print(const bool.fromEnvironment('dart.library.html'));}\n");
var package_config =
File('${tempDir.path}/.dart_tool/package_config.json')
..createSync(recursive: true)
..writeAsStringSync('''
{
"configVersion": 2,
"packages": [
{
"name": "hello",
"rootUri": "../",
"packageUri": "./"
}
]
}
''');
var library = 'package:hello/foo.dart';
var module = 'packages/hello/foo.dart';
var dillFile = File('${tempDir.path}/foo.dart.dill');
var sourceFile = File('${dillFile.path}.sources');
var manifestFile = File('${dillFile.path}.json');
var sourceMapsFile = File('${dillFile.path}.map');
expect(dillFile.existsSync(), false);
final List<String> args = <String>[
'--sdk-root=${sdkRoot.toFilePath()}',
'--incremental',
'--platform=${ddcPlatformKernel.path}',
'--output-dill=${dillFile.path}',
'--target=dartdevc',
'--packages=${package_config.path}',
];
final StreamController<List<int>> streamController =
StreamController<List<int>>();
final StreamController<List<int>> stdoutStreamController =
StreamController<List<int>>();
final IOSink ioSink = IOSink(stdoutStreamController.sink);
StreamController<Result> receivedResults = StreamController<Result>();
final outputParser = OutputParser(receivedResults);
stdoutStreamController.stream
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen(outputParser.listener);
Future<int> result =
starter(args, input: streamController.stream, output: ioSink);
streamController.add('compile $library\n'.codeUnits);
int count = 0;
receivedResults.stream.listen((Result compiledResult) {
CompilationResult result =
CompilationResult.parse(compiledResult.status);
if (count == 0) {
// Request to 'compile', which results in full JavaScript.
expect(result.errorsCount, equals(0));
expect(sourceFile.existsSync(), equals(true));
expect(manifestFile.existsSync(), equals(true));
expect(sourceMapsFile.existsSync(), equals(true));
expect(result.filename, dillFile.path);
var compiledOutput = sourceFile.readAsStringSync();
// The constant environment variable should be inlined as a boolean
// literal.
expect(compiledOutput, contains('print(true);'));
streamController.add('accept\n'.codeUnits);
// 'compile-expression-to-js <boundarykey>
// libraryUri
// line
// column
// jsModules (one k-v pair per line)
// ...
// <boundarykey>
// jsFrameValues (one k-v pair per line)
// ...
// <boundarykey>
// moduleName
// expression
outputParser.expectSources = false;
streamController.add('compile-expression-to-js abc\n'
'$library\n2\n1\nabc\nabc\n$module\n'
'const bool.fromEnvironment("dart.library.html")\n'
.codeUnits);
count += 1;
} else {
expect(count, 1);
// Second request is to 'compile-expression-to-js' that should
// result in a literal `true` .
expect(result.errorsCount, 0);
var resultFile = File(result.filename);
// The constant environment variable should be inlined as a boolean
// literal.
expect(resultFile.readAsStringSync(), contains('return true;'));
outputParser.expectSources = false;
count += 1;
streamController.add('quit\n'.codeUnits);
}
});
expect(await result, 0);
expect(count, 2);
});
test('mixed compile expression commands with web target', () async {
var file = File('${tempDir.path}/foo.dart')..createSync();
file.writeAsStringSync("main() {\n\n}\n");