[cfe] Migrate experimental flag libraries

Change-Id: I621925a41de02b09071e9c2fbbb608961e9879b3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/196496
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/api_prototype/compiler_options.dart b/pkg/front_end/lib/src/api_prototype/compiler_options.dart
index a9154dd..23ba26d 100644
--- a/pkg/front_end/lib/src/api_prototype/compiler_options.dart
+++ b/pkg/front_end/lib/src/api_prototype/compiler_options.dart
@@ -270,18 +270,23 @@
   /// Verbosity level used for filtering emitted messages.
   Verbosity verbosity = Verbosity.all;
 
-  bool isExperimentEnabledByDefault(ExperimentalFlag flag) {
-    return flags.isExperimentEnabled(flag,
-        defaultExperimentFlagsForTesting: defaultExperimentFlagsForTesting);
-  }
-
-  /// Returns
+  /// Returns `true` if the experiment with the given [flag] is enabled, either
+  /// explicitly or implicitly.
+  ///
+  /// Note that libraries can still opt out of the experiment by having a lower
+  /// language version than required for the experiment.
   bool isExperimentEnabled(ExperimentalFlag flag) {
     return flags.isExperimentEnabled(flag,
         explicitExperimentalFlags: explicitExperimentalFlags,
         defaultExperimentFlagsForTesting: defaultExperimentFlagsForTesting);
   }
 
+  /// Returns `true` if the experiment with the given [flag] is enabled either
+  /// explicitly or implicitly for the library with the given [importUri].
+  ///
+  /// Note that the library can still opt out of the experiment by having a
+  /// lower language version than required for the experiment. See
+  /// [getExperimentEnabledVersionInLibrary].
   bool isExperimentEnabledInLibrary(ExperimentalFlag flag, Uri importUri) {
     return flags.isExperimentEnabledInLibrary(flag, importUri,
         defaultExperimentFlagsForTesting: defaultExperimentFlagsForTesting,
@@ -289,6 +294,11 @@
         allowedExperimentalFlags: allowedExperimentalFlagsForTesting);
   }
 
+  /// Returns the minimum language version needed for a library with the given
+  /// [importUri] to opt in to the experiment with the given [flag].
+  ///
+  /// Note that the experiment might not be enabled at all for the library, as
+  /// computed by [isExperimentEnabledInLibrary].
   Version getExperimentEnabledVersionInLibrary(
       ExperimentalFlag flag, Uri importUri) {
     return flags.getExperimentEnabledVersionInLibrary(
@@ -300,6 +310,8 @@
             experimentReleasedVersionForTesting);
   }
 
+  /// Return `true` if the experiment with the given [flag] is enabled for the
+  /// library with the given [importUri] and language [version].
   bool isExperimentEnabledInLibraryByVersion(
       ExperimentalFlag flag, Uri importUri, Version version) {
     return flags.isExperimentEnabledInLibraryByVersion(flag, importUri, version,
diff --git a/pkg/front_end/lib/src/api_prototype/experimental_flags.dart b/pkg/front_end/lib/src/api_prototype/experimental_flags.dart
index bd9a076..9220790 100644
--- a/pkg/front_end/lib/src/api_prototype/experimental_flags.dart
+++ b/pkg/front_end/lib/src/api_prototype/experimental_flags.dart
@@ -2,8 +2,6 @@
 // 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.
 
-// @dart = 2.9
-
 import 'package:kernel/kernel.dart' show Version;
 
 part 'experimental_flags_generated.dart';
@@ -33,7 +31,7 @@
 
   /// Return the set of enabled experiments for the package with the [name],
   /// e.g. "path", possibly `null`.
-  Set<ExperimentalFlag> forPackage(String name) {
+  Set<ExperimentalFlag>? forPackage(String name) {
     return packageExperiments[name];
   }
 
@@ -53,16 +51,16 @@
 /// If [flag] is marked as expired in [expiredExperimentalFlags], the value from
 /// [defaultExperimentalFlags] is always returned.
 bool isExperimentEnabled(ExperimentalFlag flag,
-    {Map<ExperimentalFlag, bool> explicitExperimentalFlags,
-    Map<ExperimentalFlag, bool> defaultExperimentFlagsForTesting}) {
+    {Map<ExperimentalFlag, bool>? explicitExperimentalFlags,
+    Map<ExperimentalFlag, bool>? defaultExperimentFlagsForTesting}) {
   assert(defaultExperimentalFlags.containsKey(flag),
       "No default value for $flag.");
   assert(expiredExperimentalFlags.containsKey(flag),
       "No expired value for $flag.");
-  if (expiredExperimentalFlags[flag]) {
-    return defaultExperimentalFlags[flag];
+  if (expiredExperimentalFlags[flag]!) {
+    return defaultExperimentalFlags[flag]!;
   }
-  bool enabled;
+  bool? enabled;
   if (explicitExperimentalFlags != null) {
     enabled = explicitExperimentalFlags[flag];
   }
@@ -70,7 +68,7 @@
     enabled ??= defaultExperimentFlagsForTesting[flag];
   }
   enabled ??= defaultExperimentalFlags[flag];
-  return enabled;
+  return enabled!;
 }
 
 /// Returns `true` if [flag] is enabled in the library with the [canonicalUri]
@@ -90,17 +88,17 @@
 /// defines the identity of a library, for instance `dart:core`, `package:foo`,
 /// or `file:///path/dir/file.dart`.
 bool isExperimentEnabledInLibrary(ExperimentalFlag flag, Uri canonicalUri,
-    {Map<ExperimentalFlag, bool> defaultExperimentFlagsForTesting,
-    Map<ExperimentalFlag, bool> explicitExperimentalFlags,
-    AllowedExperimentalFlags allowedExperimentalFlags}) {
+    {Map<ExperimentalFlag, bool>? defaultExperimentFlagsForTesting,
+    Map<ExperimentalFlag, bool>? explicitExperimentalFlags,
+    AllowedExperimentalFlags? allowedExperimentalFlags}) {
   assert(defaultExperimentalFlags.containsKey(flag),
       "No default value for $flag.");
   assert(expiredExperimentalFlags.containsKey(flag),
       "No expired value for $flag.");
-  if (expiredExperimentalFlags[flag]) {
-    return defaultExperimentalFlags[flag];
+  if (expiredExperimentalFlags[flag]!) {
+    return defaultExperimentalFlags[flag]!;
   }
-  bool enabled;
+  bool? enabled;
   if (explicitExperimentalFlags != null) {
     enabled = explicitExperimentalFlags[flag];
   }
@@ -108,9 +106,9 @@
     enabled ??= defaultExperimentFlagsForTesting[flag];
   }
   enabled ??= defaultExperimentalFlags[flag];
-  if (!enabled) {
+  if (!enabled!) {
     allowedExperimentalFlags ??= defaultAllowedExperimentalFlags;
-    Set<ExperimentalFlag> allowedFlags;
+    Set<ExperimentalFlag>? allowedFlags;
     if (canonicalUri.scheme == 'dart') {
       allowedFlags = allowedExperimentalFlags.forSdkLibrary(canonicalUri.path);
     } else if (canonicalUri.scheme == 'package') {
@@ -134,13 +132,13 @@
 /// [canonicalUri].
 Version getExperimentEnabledVersionInLibrary(ExperimentalFlag flag,
     Uri canonicalUri, Map<ExperimentalFlag, bool> explicitExperimentalFlags,
-    {AllowedExperimentalFlags allowedExperimentalFlags,
-    Map<ExperimentalFlag, bool> defaultExperimentFlagsForTesting,
-    Map<ExperimentalFlag, Version> experimentEnabledVersionForTesting,
-    Map<ExperimentalFlag, Version> experimentReleasedVersionForTesting}) {
+    {AllowedExperimentalFlags? allowedExperimentalFlags,
+    Map<ExperimentalFlag, bool>? defaultExperimentFlagsForTesting,
+    Map<ExperimentalFlag, Version>? experimentEnabledVersionForTesting,
+    Map<ExperimentalFlag, Version>? experimentReleasedVersionForTesting}) {
   allowedExperimentalFlags ??= defaultAllowedExperimentalFlags;
 
-  Set<ExperimentalFlag> allowedFlags;
+  Set<ExperimentalFlag>? allowedFlags;
   if (canonicalUri.scheme == 'dart') {
     allowedFlags = allowedExperimentalFlags.forSdkLibrary(canonicalUri.path);
   } else if (canonicalUri.scheme == 'package') {
@@ -153,8 +151,8 @@
     }
     allowedFlags = allowedExperimentalFlags.forPackage(packageName);
   }
-  Version version;
-  bool enabledByDefault;
+  Version? version;
+  bool? enabledByDefault;
   if (defaultExperimentFlagsForTesting != null) {
     enabledByDefault = defaultExperimentFlagsForTesting[flag];
   }
@@ -162,7 +160,7 @@
 
   bool enabledExplicitly = explicitExperimentalFlags[flag] ?? false;
 
-  if (!enabledByDefault ||
+  if (!enabledByDefault! ||
       enabledExplicitly ||
       (allowedFlags != null && allowedFlags.contains(flag))) {
     // If the feature is not enabled by default or is enabled by the allowed
@@ -180,25 +178,25 @@
     version ??= experimentEnabledVersion[flag];
   }
   assert(version != null, "No version for enabling $flag in $canonicalUri.");
-  return version;
+  return version!;
 }
 
 bool isExperimentEnabledInLibraryByVersion(
     ExperimentalFlag flag, Uri canonicalUri, Version version,
-    {Map<ExperimentalFlag, bool> defaultExperimentFlagsForTesting,
-    Map<ExperimentalFlag, bool> explicitExperimentalFlags,
-    AllowedExperimentalFlags allowedExperimentalFlags,
-    Map<ExperimentalFlag, Version> experimentEnabledVersionForTesting,
-    Map<ExperimentalFlag, Version> experimentReleasedVersionForTesting}) {
+    {Map<ExperimentalFlag, bool>? defaultExperimentFlagsForTesting,
+    required Map<ExperimentalFlag, bool> explicitExperimentalFlags,
+    AllowedExperimentalFlags? allowedExperimentalFlags,
+    Map<ExperimentalFlag, Version>? experimentEnabledVersionForTesting,
+    Map<ExperimentalFlag, Version>? experimentReleasedVersionForTesting}) {
   assert(defaultExperimentalFlags.containsKey(flag),
       "No default value for $flag.");
   assert(expiredExperimentalFlags.containsKey(flag),
       "No expired value for $flag.");
-  if (expiredExperimentalFlags[flag]) {
-    return defaultExperimentalFlags[flag];
+  if (expiredExperimentalFlags[flag]!) {
+    return defaultExperimentalFlags[flag]!;
   }
 
-  bool enabledByDefault;
+  bool? enabledByDefault;
   if (defaultExperimentFlagsForTesting != null) {
     enabledByDefault = defaultExperimentFlagsForTesting[flag];
   }
@@ -208,7 +206,7 @@
 
   allowedExperimentalFlags ??= defaultAllowedExperimentalFlags;
 
-  Set<ExperimentalFlag> allowedFlags;
+  Set<ExperimentalFlag>? allowedFlags;
   bool enabledByAllowed = false;
   if (canonicalUri.scheme == 'dart') {
     allowedFlags = allowedExperimentalFlags.forSdkLibrary(canonicalUri.path);
@@ -226,14 +224,14 @@
     enabledByAllowed = allowedFlags.contains(flag);
   }
 
-  if (enabledByDefault || enabledExplicitly || enabledByAllowed) {
+  if (enabledByDefault! || enabledExplicitly || enabledByAllowed) {
     // The feature is enabled depending on the library language version.
-    Version enabledVersion;
+    Version? enabledVersion;
     if (!enabledByDefault || enabledExplicitly || enabledByAllowed) {
       // If the feature is not enabled by default or is enabled by the allowed
       // list, use the experiment release version.
       if (experimentReleasedVersionForTesting != null) {
-        enabledVersion = experimentReleasedVersionForTesting[flag];
+        enabledVersion = experimentReleasedVersionForTesting[flag]!;
       }
       enabledVersion ??= experimentReleasedVersion[flag];
     } else {
@@ -244,7 +242,7 @@
       }
       enabledVersion ??= experimentEnabledVersion[flag];
     }
-    return version >= enabledVersion;
+    return version >= enabledVersion!;
   } else {
     // The feature is not enabled, regardless of library language version.
     return false;
diff --git a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
index af04e106..42d985f 100644
--- a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
+++ b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
@@ -2,8 +2,6 @@
 // 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.
 
-// @dart = 2.9
-
 // NOTE: THIS FILE IS GENERATED. DO NOT EDIT.
 //
 // Instead modify 'tools/experimental_features.yaml' and run
@@ -44,7 +42,7 @@
 const Version enableValueClassVersion = const Version(2, 14);
 const Version enableVarianceVersion = const Version(2, 14);
 
-ExperimentalFlag parseExperimentalFlag(String flag) {
+ExperimentalFlag? parseExperimentalFlag(String flag) {
   switch (flag) {
     case "alternative-invalidation-strategy":
       return ExperimentalFlag.alternativeInvalidationStrategy;
diff --git a/pkg/front_end/lib/src/base/processed_options.dart b/pkg/front_end/lib/src/base/processed_options.dart
index 04951b8..60c4162 100644
--- a/pkg/front_end/lib/src/base/processed_options.dart
+++ b/pkg/front_end/lib/src/base/processed_options.dart
@@ -362,11 +362,7 @@
   Target get target =>
       _target ??= _raw.target ?? new NoneTarget(new TargetFlags());
 
-  /// Returns `true` if the [flag] is enabled globally.
-  ///
-  /// This is `true` either if the [flag] is passed through an explicit
-  /// `--enable-experiment` option or if the [flag] is expired and on by
-  /// default.
+  /// Returns `true` if the [flag] is enabled globally by default.
   bool isExperimentEnabledByDefault(flags.ExperimentalFlag flag) {
     return flags.isExperimentEnabled(flag,
         defaultExperimentFlagsForTesting:
@@ -385,22 +381,29 @@
             _raw.defaultExperimentFlagsForTesting);
   }
 
-  /// Returns `true` if the [flag] is enabled in the library with the given
-  /// [importUri].
+  /// Returns `true` if the experiment with the given [flag] is enabled either
+  /// explicitly or implicitly for the library with the given [importUri].
   ///
-  /// This is `true` either if the [flag] is enabled globally as defined
-  /// by [isExperimentEnabledGlobally] or is explicitly enabled through
-  /// the 'allowed_experiments.json' file for this library.
+  /// Note that the library can still opt out of the experiment by having a
+  /// lower language version than required for the experiment. See
+  /// [getExperimentEnabledVersionInLibrary].
   bool isExperimentEnabledInLibrary(
       flags.ExperimentalFlag flag, Uri importUri) {
     return _raw.isExperimentEnabledInLibrary(flag, importUri);
   }
 
+  /// Returns the minimum language version needed for a library with the given
+  /// [importUri] to opt in to the experiment with the given [flag].
+  ///
+  /// Note that the experiment might not be enabled at all for the library, as
+  /// computed by [isExperimentEnabledInLibrary].
   Version getExperimentEnabledVersionInLibrary(
       flags.ExperimentalFlag flag, Uri importUri) {
     return _raw.getExperimentEnabledVersionInLibrary(flag, importUri);
   }
 
+  /// Return `true` if the experiment with the given [flag] is enabled for the
+  /// library with the given [importUri] and language [version].
   bool isExperimentEnabledInLibraryByVersion(
       flags.ExperimentalFlag flag, Uri importUri, Version version) {
     return _raw.isExperimentEnabledInLibraryByVersion(flag, importUri, version);
diff --git a/pkg/front_end/tool/_fasta/generate_experimental_flags.dart b/pkg/front_end/tool/_fasta/generate_experimental_flags.dart
index c3ec736..cd96105 100644
--- a/pkg/front_end/tool/_fasta/generate_experimental_flags.dart
+++ b/pkg/front_end/tool/_fasta/generate_experimental_flags.dart
@@ -97,8 +97,6 @@
 // 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.
 
-// @dart = 2.9
-
 // NOTE: THIS FILE IS GENERATED. DO NOT EDIT.
 //
 // Instead modify 'tools/experimental_features.yaml' and run
@@ -154,7 +152,7 @@
 
   sb.write('''
 
-ExperimentalFlag parseExperimentalFlag(String flag) {
+ExperimentalFlag? parseExperimentalFlag(String flag) {
   switch (flag) {
 ''');
   for (String key in keys) {