Accept experimental flags in dart2js and enable set-literal tests, now supported
once we accept the flag.

Note: 3 tests are missing compile-time errors from the CFE. This is a known CFE
issue, we need to mark the tests as failng using the new workflow before we land
the CL.
Change-Id: I0eaf6c1d7e903e035c83d3338054a8f92d2d9296
Reviewed-on: https://dart-review.googlesource.com/c/88763
Commit-Queue: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 357d847..991fb58 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -43,6 +43,8 @@
   static const String experimentCallInstrumentation =
       '--experiment-call-instrumentation';
 
+  static const String enableLanguageExperiments = '--enable-experiment';
+
   static const String fastStartup = '--fast-startup';
   static const String fatalWarnings = '--fatal-warnings';
   static const String generateCodeWithCompileTimeErrors =
@@ -129,6 +131,10 @@
   static const String showPackageWarnings =
       '${Flags.showPackageWarnings}|${Flags.showPackageWarnings}=.*';
 
+  static const String enableLanguageExperiments =
+      '${Flags.enableLanguageExperiments}|'
+      '${Flags.enableLanguageExperiments}=.*';
+
   // Experimental options.
   static const String resolutionInput = '--resolution-input=.+';
   static const String bazelPaths = '--bazel-paths=.+';
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 30b30a9..4905ddb 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -381,6 +381,7 @@
     new OptionHandler(Flags.dumpInfo, passThrough),
     new OptionHandler('--disallow-unsafe-eval', ignoreOption),
     new OptionHandler(Option.showPackageWarnings, passThrough),
+    new OptionHandler(Option.enableLanguageExperiments, passThrough),
     new OptionHandler(Flags.useContentSecurityPolicy, passThrough),
     new OptionHandler(Flags.enableExperimentalMirrors, passThrough),
     new OptionHandler(Flags.enableAssertMessage, passThrough),
diff --git a/pkg/compiler/lib/src/kernel/loader.dart b/pkg/compiler/lib/src/kernel/loader.dart
index 4d14f55..19891b3 100644
--- a/pkg/compiler/lib/src/kernel/loader.dart
+++ b/pkg/compiler/lib/src/kernel/loader.dart
@@ -72,7 +72,8 @@
             new Dart2jsTarget(targetName, new TargetFlags()),
             _options.librariesSpecificationUri,
             _options.platformBinaries.resolve(platform),
-            _options.packageConfig);
+            _options.packageConfig,
+            experimentalFlags: _options.languageExperiments);
         component = await fe.compile(
             initializedCompilerState,
             false,
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index d3f68c6..89e4c55 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -70,6 +70,9 @@
   /// flags.
   Map<String, String> environment = const <String, String>{};
 
+  /// Flags enabling language experiments.
+  Map<fe.ExperimentalFlag, bool> languageExperiments = {};
+
   /// A possibly null state object for kernel compilation.
   fe.InitializedCompilerState kernelInitializedCompilerState;
 
@@ -313,6 +316,7 @@
       ..suppressHints = _hasOption(options, Flags.suppressHints)
       ..shownPackageWarnings =
           _extractOptionalCsvOption(options, Flags.showPackageWarnings)
+      ..languageExperiments = _extractExperiments(options)
       ..disableInlining = _hasOption(options, Flags.disableInlining)
       ..disableProgramSplit = _hasOption(options, Flags.disableProgramSplit)
       ..disableTypeInference = _hasOption(options, Flags.disableTypeInference)
@@ -509,4 +513,11 @@
   return null;
 }
 
+Map<fe.ExperimentalFlag, bool> _extractExperiments(List<String> options) {
+  List<String> experiments =
+      _extractOptionalCsvOption(options, Flags.enableLanguageExperiments);
+  return fe.parseExperimentalFlags(
+      experiments, (String error) => throw new ArgumentError(error));
+}
+
 const String _UNDETERMINED_BUILD_ID = "build number could not be determined";
diff --git a/pkg/front_end/lib/src/api_unstable/dart2js.dart b/pkg/front_end/lib/src/api_unstable/dart2js.dart
index 82225f3..188c88b 100644
--- a/pkg/front_end/lib/src/api_unstable/dart2js.dart
+++ b/pkg/front_end/lib/src/api_unstable/dart2js.dart
@@ -12,6 +12,8 @@
 
 import '../api_prototype/diagnostic_message.dart' show DiagnosticMessageHandler;
 
+import '../api_prototype/experimental_flags.dart' show ExperimentalFlag;
+
 import '../api_prototype/file_system.dart' show FileSystem;
 
 import '../base/processed_options.dart' show ProcessedOptions;
@@ -30,10 +32,13 @@
 
 import 'compiler_state.dart' show InitializedCompilerState;
 
-export '../api_prototype/compiler_options.dart' show CompilerOptions;
+export '../api_prototype/compiler_options.dart'
+    show CompilerOptions, parseExperimentalFlags;
 
 export '../api_prototype/diagnostic_message.dart' show DiagnosticMessage;
 
+export '../api_prototype/experimental_flags.dart' show ExperimentalFlag;
+
 export '../api_prototype/file_system.dart'
     show FileSystem, FileSystemEntity, FileSystemException;
 
@@ -98,11 +103,22 @@
     Target target,
     Uri librariesSpecificationUri,
     Uri sdkPlatformUri,
-    Uri packagesFileUri) {
+    Uri packagesFileUri,
+    {Map<ExperimentalFlag, bool> experimentalFlags}) {
+  bool mapEqual(Map<ExperimentalFlag, bool> a, Map<ExperimentalFlag, bool> b) {
+    if (a == null || b == null) return a == b;
+    if (a.length != b.length) return false;
+    for (var flag in a.keys) {
+      if (!b.containsKey(flag) || a[flag] != b[flag]) return false;
+    }
+    return true;
+  }
+
   if (oldState != null &&
       oldState.options.packagesFileUri == packagesFileUri &&
       oldState.options.librariesSpecificationUri == librariesSpecificationUri &&
-      oldState.options.linkedDependencies[0] == sdkPlatformUri) {
+      oldState.options.linkedDependencies[0] == sdkPlatformUri &&
+      mapEqual(oldState.options.experimentalFlags, experimentalFlags)) {
     return oldState;
   }
 
@@ -111,7 +127,8 @@
     ..legacyMode = target.legacyMode
     ..linkedDependencies = [sdkPlatformUri]
     ..librariesSpecificationUri = librariesSpecificationUri
-    ..packagesFileUri = packagesFileUri;
+    ..packagesFileUri = packagesFileUri
+    ..experimentalFlags = experimentalFlags;
 
   ProcessedOptions processedOpts = new ProcessedOptions(options: options);
 
diff --git a/tests/language_2/language_2_dart2js.status b/tests/language_2/language_2_dart2js.status
index c38a4b3..afc42ff 100644
--- a/tests/language_2/language_2_dart2js.status
+++ b/tests/language_2/language_2_dart2js.status
@@ -60,7 +60,6 @@
 partial_tearoff_instantiation_test/07: Pass # for the wrong reason.
 partial_tearoff_instantiation_test/08: Pass # for the wrong reason.
 private_method_tearoff_test: RuntimeError
-set_literals/*: Skip
 type_constants_test/none: RuntimeError # Issue 35052
 vm/*: SkipByDesign # Tests for the VM.