Reland: [cfe] Embed and use allowed experiments in CFE

This CL embeds the sdk_nnbd/lib/_internal/allowed_experiments.json
into the CFE and uses this to allow experiments enabled on a
per library basis. The file is embedded through generated code to
avoid reliance on access to the file itself.

A presubmit check is also added to ensure that the json file and
the generated code are in sync.

This work is in preparation for https://github.com/dart-lang/sdk/issues/41538

This was reverted in https://dart-review.googlesource.com/c/sdk/+/149620
because flutter wasn't prepared for auto-enabling nnbd in dart:* libraries.
This has now been fixed in https://github.com/flutter/engine/pull/18714

Closes #42162

Change-Id: I686ed6feaef8ee066b426068fe2a0f5080bf1713
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/149588
Reviewed-by: Jens Johansen <jensj@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Johnni Winther 2020-06-03 08:15:49 +00:00 committed by commit-bot@chromium.org
parent 5c0c41cc68
commit 23d70f6f23
27 changed files with 402 additions and 179 deletions

View file

@ -27,7 +27,7 @@ class AllowedExperiments {
/// are enabled for all files of this package.
final Map<String, List<String>> packageExperiments;
const AllowedExperiments({
AllowedExperiments({
@required this.sdkDefaultExperiments,
@required this.sdkLibraryExperiments,
@required this.packageExperiments,

View file

@ -16,6 +16,7 @@ import '../base/nnbd_mode.dart';
import 'experimental_flags.dart'
show
AllowedExperimentalFlags,
defaultExperimentalFlags,
ExperimentalFlag,
expiredExperimentalFlags,
@ -129,6 +130,8 @@ class CompilerOptions {
/// Features not mentioned in the map will have their default value.
Map<ExperimentalFlag, bool> experimentalFlags = <ExperimentalFlag, bool>{};
AllowedExperimentalFlags allowedExperimentalFlags;
/// Environment map used when evaluating `bool.fromEnvironment`,
/// `int.fromEnvironment` and `String.fromEnvironment` during constant
/// evaluation. If the map is `null`, all environment constants will be left

View file

@ -1,86 +1,117 @@
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS 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.
// NOTE: THIS FILE IS GENERATED. DO NOT EDIT.
//
// Instead modify 'tools/experimental_features.yaml' and run
// 'dart pkg/front_end/tool/fasta.dart generate-experimental-flags' to update.
import 'package:_fe_analyzer_shared/src/sdk/allowed_experiments.dart';
import 'package:kernel/kernel.dart' show Version;
enum ExperimentalFlag {
constantUpdate2018,
controlFlowCollections,
extensionMethods,
nonNullable,
nonfunctionTypeAliases,
setLiterals,
spreadCollections,
tripleShift,
variance,
}
part 'experimental_flags_generated.dart';
const Version enableConstantUpdate2018Version = const Version(2, 4);
const Version enableControlFlowCollectionsVersion = const Version(2, 2);
const Version enableExtensionMethodsVersion = const Version(2, 6);
const Version enableNonNullableVersion = const Version(2, 9);
const Version enableNonfunctionTypeAliasesVersion = const Version(2, 9);
const Version enableSetLiteralsVersion = const Version(2, 2);
const Version enableSpreadCollectionsVersion = const Version(2, 2);
const Version enableTripleShiftVersion = const Version(2, 9);
const Version enableVarianceVersion = const Version(2, 9);
/// The set of experiments enabled for SDK and packages.
///
/// This are derived from an `allowed_experiments.json` file whose default is
/// located in `sdk_nnbd/lib/_internal/allowed_experiments.json`.
class AllowedExperimentalFlags {
/// The set of experiments that are enabled for all SDK libraries other than
/// for those which are specified in [sdkLibraryExperiments].
final Set<ExperimentalFlag> sdkDefaultExperiments;
ExperimentalFlag parseExperimentalFlag(String flag) {
switch (flag) {
case "constant-update-2018":
return ExperimentalFlag.constantUpdate2018;
case "control-flow-collections":
return ExperimentalFlag.controlFlowCollections;
case "extension-methods":
return ExperimentalFlag.extensionMethods;
case "non-nullable":
return ExperimentalFlag.nonNullable;
case "nonfunction-type-aliases":
return ExperimentalFlag.nonfunctionTypeAliases;
case "set-literals":
return ExperimentalFlag.setLiterals;
case "spread-collections":
return ExperimentalFlag.spreadCollections;
case "triple-shift":
return ExperimentalFlag.tripleShift;
case "variance":
return ExperimentalFlag.variance;
/// Mapping from individual SDK libraries, e.g. 'core', to the set of
/// experiments that are enabled for this library.
final Map<String, Set<ExperimentalFlag>> sdkLibraryExperiments;
/// Mapping from package names, e.g. 'path', to the set of experiments that
/// are enabled for all files of this package.
final Map<String, Set<ExperimentalFlag>> packageExperiments;
const AllowedExperimentalFlags({
this.sdkDefaultExperiments: const {},
this.sdkLibraryExperiments: const {},
this.packageExperiments: const {},
});
/// Return the set of enabled experiments for the package with the [name],
/// e.g. "path", possibly `null`.
Set<ExperimentalFlag> forPackage(String name) {
return packageExperiments[name];
}
/// Return the set of enabled experiments for the library with the [name],
/// e.g. "core".
Set<ExperimentalFlag> forSdkLibrary(String name) {
return sdkLibraryExperiments[name] ?? sdkDefaultExperiments;
}
return null;
}
const Map<ExperimentalFlag, bool> defaultExperimentalFlags = {
ExperimentalFlag.constantUpdate2018: true,
ExperimentalFlag.controlFlowCollections: true,
ExperimentalFlag.extensionMethods: true,
ExperimentalFlag.nonNullable: false,
ExperimentalFlag.nonfunctionTypeAliases: false,
ExperimentalFlag.setLiterals: true,
ExperimentalFlag.spreadCollections: true,
ExperimentalFlag.tripleShift: false,
ExperimentalFlag.variance: false,
};
/// Returns `true` if [flag] is enabled using global [experimentalFlags].
///
/// If [experimentalFlags] is `null` or doesn't contain [flag], the default
/// value from [defaultExperimentalFlags] is returned.
///
/// If [flag] is marked as expired in [expiredExperimentalFlags], the value from
/// [defaultExperimentalFlags] is always returned.
bool isExperimentEnabled(ExperimentalFlag flag,
{Map<ExperimentalFlag, bool> experimentalFlags}) {
assert(defaultExperimentalFlags.containsKey(flag),
"No default value for $flag.");
assert(expiredExperimentalFlags.containsKey(flag),
"No expired value for $flag.");
if (expiredExperimentalFlags[flag]) {
return defaultExperimentalFlags[flag];
}
bool enabled;
if (experimentalFlags != null) {
enabled = experimentalFlags[flag];
}
enabled ??= defaultExperimentalFlags[flag];
return enabled;
}
const Map<ExperimentalFlag, bool> expiredExperimentalFlags = {
ExperimentalFlag.constantUpdate2018: true,
ExperimentalFlag.controlFlowCollections: true,
ExperimentalFlag.extensionMethods: false,
ExperimentalFlag.nonNullable: false,
ExperimentalFlag.nonfunctionTypeAliases: false,
ExperimentalFlag.setLiterals: true,
ExperimentalFlag.spreadCollections: true,
ExperimentalFlag.tripleShift: false,
ExperimentalFlag.variance: false,
};
const AllowedExperiments allowedExperiments =
const AllowedExperiments(sdkDefaultExperiments: [
"non-nullable",
], sdkLibraryExperiments: {}, packageExperiments: {});
/// Returns `true` if [flag] is enabled in the library with the [canonicalUri]
/// either globally using [experimentalFlags] or per library using
/// [allowedExperimentalFlags].
///
/// If [experimentalFlags] is `null` or doesn't contain [flag], the default
/// value from [defaultExperimentalFlags] used as the global flag state.
///
/// If [allowedExperimentalFlags] is `null` [defaultAllowedExperimentalFlags] is
/// used for the per library flag state.
///
/// If [flag] is marked as expired in [expiredExperimentalFlags], the value from
/// [defaultExperimentalFlags] is always returned.
///
/// The canonical uri, also known as the import uri, is the absolute uri that
/// 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> experimentalFlags,
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];
}
bool enabled;
if (experimentalFlags != null) {
enabled = experimentalFlags[flag];
}
enabled ??= defaultExperimentalFlags[flag];
if (!enabled) {
allowedExperimentalFlags ??= defaultAllowedExperimentalFlags;
Set<ExperimentalFlag> allowedFlags;
if (canonicalUri.scheme == 'dart') {
allowedFlags = allowedExperimentalFlags.forSdkLibrary(canonicalUri.path);
} else if (canonicalUri.scheme == 'package') {
int index = canonicalUri.path.indexOf('/');
if (index >= 0) {
String packageName = canonicalUri.path.substring(0, index);
allowedFlags = allowedExperimentalFlags.forPackage(packageName);
}
}
if (allowedFlags != null) {
enabled = allowedFlags.contains(flag);
}
}
return enabled;
}

View file

@ -0,0 +1,85 @@
// 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.
// NOTE: THIS FILE IS GENERATED. DO NOT EDIT.
//
// Instead modify 'tools/experimental_features.yaml' and run
// 'dart pkg/front_end/tool/fasta.dart generate-experimental-flags' to update.
part of 'experimental_flags.dart';
enum ExperimentalFlag {
constantUpdate2018,
controlFlowCollections,
extensionMethods,
nonNullable,
nonfunctionTypeAliases,
setLiterals,
spreadCollections,
tripleShift,
variance,
}
const Version enableConstantUpdate2018Version = const Version(2, 4);
const Version enableControlFlowCollectionsVersion = const Version(2, 2);
const Version enableExtensionMethodsVersion = const Version(2, 6);
const Version enableNonNullableVersion = const Version(2, 9);
const Version enableNonfunctionTypeAliasesVersion = const Version(2, 9);
const Version enableSetLiteralsVersion = const Version(2, 2);
const Version enableSpreadCollectionsVersion = const Version(2, 2);
const Version enableTripleShiftVersion = const Version(2, 9);
const Version enableVarianceVersion = const Version(2, 9);
ExperimentalFlag parseExperimentalFlag(String flag) {
switch (flag) {
case "constant-update-2018":
return ExperimentalFlag.constantUpdate2018;
case "control-flow-collections":
return ExperimentalFlag.controlFlowCollections;
case "extension-methods":
return ExperimentalFlag.extensionMethods;
case "non-nullable":
return ExperimentalFlag.nonNullable;
case "nonfunction-type-aliases":
return ExperimentalFlag.nonfunctionTypeAliases;
case "set-literals":
return ExperimentalFlag.setLiterals;
case "spread-collections":
return ExperimentalFlag.spreadCollections;
case "triple-shift":
return ExperimentalFlag.tripleShift;
case "variance":
return ExperimentalFlag.variance;
}
return null;
}
const Map<ExperimentalFlag, bool> defaultExperimentalFlags = {
ExperimentalFlag.constantUpdate2018: true,
ExperimentalFlag.controlFlowCollections: true,
ExperimentalFlag.extensionMethods: true,
ExperimentalFlag.nonNullable: false,
ExperimentalFlag.nonfunctionTypeAliases: false,
ExperimentalFlag.setLiterals: true,
ExperimentalFlag.spreadCollections: true,
ExperimentalFlag.tripleShift: false,
ExperimentalFlag.variance: false,
};
const Map<ExperimentalFlag, bool> expiredExperimentalFlags = {
ExperimentalFlag.constantUpdate2018: true,
ExperimentalFlag.controlFlowCollections: true,
ExperimentalFlag.extensionMethods: false,
ExperimentalFlag.nonNullable: false,
ExperimentalFlag.nonfunctionTypeAliases: false,
ExperimentalFlag.setLiterals: true,
ExperimentalFlag.spreadCollections: true,
ExperimentalFlag.tripleShift: false,
ExperimentalFlag.variance: false,
};
const AllowedExperimentalFlags defaultAllowedExperimentalFlags =
const AllowedExperimentalFlags(sdkDefaultExperiments: {
ExperimentalFlag.nonNullable,
}, sdkLibraryExperiments: {}, packageExperiments: {});

View file

@ -22,8 +22,7 @@ import 'package:package_config/package_config.dart';
import '../api_prototype/compiler_options.dart'
show CompilerOptions, DiagnosticMessage;
import '../api_prototype/experimental_flags.dart'
show defaultExperimentalFlags, ExperimentalFlag, expiredExperimentalFlags;
import '../api_prototype/experimental_flags.dart' as flags;
import '../api_prototype/file_system.dart'
show FileSystem, FileSystemEntity, FileSystemException;
@ -325,15 +324,27 @@ class ProcessedOptions {
Target get target =>
_target ??= _raw.target ?? new NoneTarget(new TargetFlags());
bool isExperimentEnabled(ExperimentalFlag flag) {
assert(defaultExperimentalFlags.containsKey(flag),
"No default value for $flag.");
assert(expiredExperimentalFlags.containsKey(flag),
"No expired value for $flag.");
if (expiredExperimentalFlags[flag]) {
return defaultExperimentalFlags[flag];
}
return _raw.experimentalFlags[flag] ?? defaultExperimentalFlags[flag];
/// 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.
bool isExperimentEnabledGlobally(flags.ExperimentalFlag flag) {
return flags.isExperimentEnabled(flag,
experimentalFlags: _raw.experimentalFlags);
}
/// Returns `true` if the [flag] is enabled in 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.
bool isExperimentEnabledInLibrary(
flags.ExperimentalFlag flag, Uri importUri) {
return flags.isExperimentEnabledInLibrary(flag, importUri,
experimentalFlags: _raw.experimentalFlags,
allowedExperimentalFlags: _raw.allowedExperimentalFlags);
}
/// Get an outline component that summarizes the SDK, if any.

View file

@ -5518,7 +5518,7 @@ class BodyBuilder extends ScopeListener<JumpTarget>
TypeVariableBuilder variable = typeVariables[index];
variable.bound = bound?.builder;
if (variance != null) {
if (!libraryBuilder.loader.target.enableVariance) {
if (!libraryBuilder.enableVarianceInLibrary) {
reportVarianceModifierNotEnabled(variance);
}
variable.variance = Variance.fromString(variance.lexeme);

View file

@ -6,6 +6,7 @@ library fasta.kernel_target;
import 'dart:async' show Future;
import 'package:front_end/src/api_prototype/experimental_flags.dart';
import 'package:kernel/ast.dart'
show
Arguments,
@ -251,9 +252,8 @@ class KernelTarget extends TargetImplementation {
if (dillTarget.isLoaded) {
LibraryBuilder builder = dillTarget.loader.builders[uri];
if (builder != null) {
if (enableNonNullable &&
(loader.nnbdMode == NnbdMode.Strong ||
loader.nnbdMode == NnbdMode.Agnostic)) {
if (loader.nnbdMode == NnbdMode.Strong ||
loader.nnbdMode == NnbdMode.Agnostic) {
if (!builder.isNonNullableByDefault) {
loader.addProblem(messageStrongModeNNBDButOptOut, -1, 1, fileUri);
}
@ -400,7 +400,7 @@ class KernelTarget extends TargetImplementation {
nameRoot: nameRoot, libraries: libraries, uriToSource: uriToSource));
NonNullableByDefaultCompiledMode compiledMode = null;
if (enableNonNullable) {
if (isExperimentEnabledGlobally(ExperimentalFlag.nonNullable)) {
switch (loader.nnbdMode) {
case NnbdMode.Weak:
compiledMode = NonNullableByDefaultCompiledMode.Weak;
@ -1099,7 +1099,8 @@ class KernelTarget extends TargetImplementation {
// because the SDK might be agnostic and therefore needs to be weakened
// for legacy mode.
assert(
enableNonNullable || loader.nnbdMode == NnbdMode.Weak,
isExperimentEnabledGlobally(ExperimentalFlag.nonNullable) ||
loader.nnbdMode == NnbdMode.Weak,
"Non-weak nnbd mode found without experiment enabled: "
"${loader.nnbdMode}.");
switch (loader.nnbdMode) {
@ -1122,7 +1123,8 @@ class KernelTarget extends TargetImplementation {
new KernelConstantErrorReporter(loader),
evaluationMode,
desugarSets: !backendTarget.supportsSetLiterals,
enableTripleShift: enableTripleShift,
enableTripleShift:
isExperimentEnabledGlobally(ExperimentalFlag.tripleShift),
errorOnUnevaluatedConstant: errorOnUnevaluatedConstant);
ticker.logMs("Evaluated constants");

View file

@ -1636,10 +1636,10 @@ class OutlineBuilder extends StackListenerImpl {
return;
}
if (type is FunctionTypeBuilder &&
!libraryBuilder.loader.target.enableNonfunctionTypeAliases) {
!libraryBuilder.enableNonfunctionTypeAliasesInLibrary) {
if (type.nullabilityBuilder.build(libraryBuilder) ==
Nullability.nullable &&
libraryBuilder.loader.target.enableNonNullable) {
libraryBuilder.enableNonNullableInLibrary) {
// The error is reported when the non-nullable experiment is enabled.
// Otherwise, the attempt to use a nullable type will be reported
// elsewhere.
@ -1653,7 +1653,7 @@ class OutlineBuilder extends StackListenerImpl {
// of a generic function).
aliasedType = type;
}
} else if (libraryBuilder.loader.target.enableNonfunctionTypeAliases) {
} else if (libraryBuilder.enableNonfunctionTypeAliasesInLibrary) {
if (type is TypeBuilder) {
aliasedType = type;
} else {
@ -1797,7 +1797,7 @@ class OutlineBuilder extends StackListenerImpl {
if (typeParameters != null) {
typeParameters[index].bound = bound;
if (variance != null) {
if (!libraryBuilder.loader.target.enableVariance) {
if (!libraryBuilder.enableVarianceInLibrary) {
reportVarianceModifierNotEnabled(variance);
}
typeParameters[index].variance = Variance.fromString(variance.lexeme);

View file

@ -73,6 +73,7 @@ import 'package:kernel/type_algebra.dart' show substitute;
import 'package:kernel/type_environment.dart'
show SubtypeCheckMode, TypeEnvironment;
import '../../api_prototype/experimental_flags.dart';
import '../../base/nnbd_mode.dart';
import '../builder/builder.dart';
@ -166,9 +167,6 @@ import 'source_extension_builder.dart' show SourceExtensionBuilder;
import 'source_loader.dart' show SourceLoader;
import '../../api_prototype/experimental_flags.dart'
show enableNonNullableVersion;
class SourceLibraryBuilder extends LibraryBuilderImpl {
static const String MALFORMED_URI_SCHEME = "org-dartlang-malformed-uri";
@ -319,9 +317,36 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
updateLibraryNNBDSettings();
}
bool _enableVarianceInLibrary;
bool _enableNonfunctionTypeAliasesInLibrary;
bool _enableNonNullableInLibrary;
bool _enableTripleShiftInLibrary;
bool _enableExtensionMethodsInLibrary;
bool get enableVarianceInLibrary => _enableVarianceInLibrary ??= loader.target
.isExperimentEnabledInLibrary(ExperimentalFlag.variance, importUri);
bool get enableNonfunctionTypeAliasesInLibrary =>
_enableNonfunctionTypeAliasesInLibrary ??= loader.target
.isExperimentEnabledInLibrary(
ExperimentalFlag.nonfunctionTypeAliases, importUri);
bool get enableNonNullableInLibrary => _enableNonNullableInLibrary ??= loader
.target
.isExperimentEnabledInLibrary(ExperimentalFlag.nonNullable, importUri);
bool get enableTripleShiftInLibrary => _enableTripleShiftInLibrary ??= loader
.target
.isExperimentEnabledInLibrary(ExperimentalFlag.tripleShift, importUri);
bool get enableExtensionMethodsInLibrary =>
_enableExtensionMethodsInLibrary ??= loader.target
.isExperimentEnabledInLibrary(
ExperimentalFlag.extensionMethods, importUri);
void updateLibraryNNBDSettings() {
library.isNonNullableByDefault = isNonNullableByDefault;
if (loader.target.enableNonNullable) {
if (enableNonNullableInLibrary) {
switch (loader.nnbdMode) {
case NnbdMode.Weak:
library.nonNullableByDefaultCompiledMode =
@ -382,7 +407,7 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
@override
bool get isNonNullableByDefault =>
loader.target.enableNonNullable &&
enableNonNullableInLibrary &&
languageVersion.version >= enableNonNullableVersion &&
!isOptOutTest(library.importUri);
@ -449,7 +474,7 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
new LanguageVersion(version, fileUri, offset, length, explicit);
library.setLanguageVersion(version);
if (loader.target.enableNonNullable &&
if (enableNonNullableInLibrary &&
(loader.nnbdMode == NnbdMode.Strong ||
loader.nnbdMode == NnbdMode.Agnostic)) {
// In strong and agnostic mode, the language version is not allowed to
@ -3031,7 +3056,7 @@ class SourceLibraryBuilder extends LibraryBuilderImpl {
isNonNullableByDefault),
fieldBuilder.charOffset,
fieldBuilder.name.length,
fileUri);
fieldBuilder.fileUri);
}
}
}

View file

@ -256,16 +256,16 @@ class SourceLoader extends Loader {
ScannerResult result = scan(bytes,
includeComments: includeComments,
configuration: new ScannerConfiguration(
enableTripleShift: target.enableTripleShift,
enableExtensionMethods: target.enableExtensionMethods,
enableTripleShift: library.enableTripleShiftInLibrary,
enableExtensionMethods: library.enableExtensionMethodsInLibrary,
enableNonNullable: library.isNonNullableByDefault),
languageVersionChanged:
(Scanner scanner, LanguageVersionToken version) {
library.setLanguageVersion(new Version(version.major, version.minor),
offset: version.offset, length: version.length, explicit: true);
scanner.configuration = new ScannerConfiguration(
enableTripleShift: target.enableTripleShift,
enableExtensionMethods: target.enableExtensionMethods,
enableTripleShift: library.enableTripleShiftInLibrary,
enableExtensionMethods: library.enableExtensionMethodsInLibrary,
enableNonNullable: library.isNonNullableByDefault);
});
Token token = result.tokens;

View file

@ -68,7 +68,7 @@ abstract class StackListenerImpl extends StackListener {
void reportMissingNonNullableSupport(Token token) {
assert(!libraryBuilder.isNonNullableByDefault);
assert(token != null);
if (libraryBuilder.loader.target.enableNonNullable) {
if (libraryBuilder.enableNonNullableInLibrary) {
if (libraryBuilder.languageVersion.isExplicit) {
addProblem(messageNonNullableOptOut, token.charOffset, token.charCount,
context: <LocatedMessage>[

View file

@ -48,28 +48,23 @@ abstract class TargetImplementation extends Target {
MemberBuilder cachedDuplicatedFieldInitializerError;
MemberBuilder cachedNativeAnnotation;
bool enableExtensionMethods;
bool enableNonNullable;
bool enableTripleShift;
bool enableVariance;
bool enableNonfunctionTypeAliases;
final ProcessedOptions _options;
TargetImplementation(Ticker ticker, this.uriTranslator, this.backendTarget)
: assert(ticker != null),
assert(uriTranslator != null),
assert(backendTarget != null),
enableExtensionMethods = CompilerContext.current.options
.isExperimentEnabled(ExperimentalFlag.extensionMethods),
enableNonNullable = CompilerContext.current.options
.isExperimentEnabled(ExperimentalFlag.nonNullable),
enableTripleShift = CompilerContext.current.options
.isExperimentEnabled(ExperimentalFlag.tripleShift),
enableVariance = CompilerContext.current.options
.isExperimentEnabled(ExperimentalFlag.variance),
enableNonfunctionTypeAliases = CompilerContext.current.options
.isExperimentEnabled(ExperimentalFlag.nonfunctionTypeAliases),
_options = CompilerContext.current.options,
super(ticker);
bool isExperimentEnabledInLibrary(ExperimentalFlag flag, Uri importUri) {
return _options.isExperimentEnabledInLibrary(flag, importUri);
}
bool isExperimentEnabledGlobally(ExperimentalFlag flag) {
return _options.isExperimentEnabledGlobally(flag);
}
/// Creates a [LibraryBuilder] corresponding to [uri], if one doesn't exist
/// already.
///

View file

@ -11,7 +11,8 @@ import 'package:kernel/ast.dart';
import 'package:kernel/target/targets.dart';
import '../api_prototype/compiler_options.dart'
show CompilerOptions, DiagnosticMessage;
import '../api_prototype/experimental_flags.dart' show ExperimentalFlag;
import '../api_prototype/experimental_flags.dart'
show AllowedExperimentalFlags, ExperimentalFlag;
import '../api_prototype/terminal_color_support.dart'
show printDiagnosticMessage;
import '../base/common.dart';
@ -43,6 +44,7 @@ class TestConfig {
final String marker;
final String name;
final Map<ExperimentalFlag, bool> experimentalFlags;
final AllowedExperimentalFlags allowedExperimentalFlags;
final Uri librariesSpecificationUri;
// TODO(johnniwinther): Tailor support to redefine selected platform
// classes/members only.
@ -52,6 +54,7 @@ class TestConfig {
const TestConfig(this.marker, this.name,
{this.experimentalFlags = const {},
this.allowedExperimentalFlags,
this.librariesSpecificationUri,
this.compileSdk: false,
this.targetFlags: const TargetFlags(),
@ -298,6 +301,7 @@ Future<TestResult<T>> runTestForConfig<T>(
options.debugDump = printCode;
options.target = new NoneTarget(config.targetFlags);
options.experimentalFlags.addAll(config.experimentalFlags);
options.allowedExperimentalFlags = config.allowedExperimentalFlags;
options.nnbdMode = config.nnbdMode;
if (config.librariesSpecificationUri != null) {
Set<Uri> testFiles =

View file

@ -5,6 +5,7 @@
import 'dart:io' show Directory, Platform;
import 'package:_fe_analyzer_shared/src/testing/id.dart';
import 'package:_fe_analyzer_shared/src/testing/id_testing.dart';
import 'package:front_end/src/api_prototype/experimental_flags.dart';
import 'package:front_end/src/fasta/builder/class_builder.dart';
import 'package:front_end/src/fasta/builder/extension_builder.dart';
@ -28,7 +29,8 @@ main(List<String> args) async {
onFailure: onFailure,
runTest: runTestFor(const ExtensionsDataComputer(), [
new TestConfig(cfeMarker, 'cfe',
librariesSpecificationUri: createUriForFileName('libraries.json'))
librariesSpecificationUri: createUriForFileName('libraries.json'),
allowedExperimentalFlags: const AllowedExperimentalFlags())
]));
}

View file

@ -14,6 +14,7 @@ import 'package:_fe_analyzer_shared/src/util/colors.dart' as colors;
import "package:front_end/src/api_prototype/compiler_options.dart"
show CompilerOptions, DiagnosticMessage;
import 'package:front_end/src/api_prototype/experimental_flags.dart';
import "package:front_end/src/api_prototype/memory_file_system.dart"
show MemoryFileSystem;
@ -409,7 +410,8 @@ Future<Context> createContext(
printDiagnosticMessage(message, print);
errors.add(message);
}
..environmentDefines = const {};
..environmentDefines = const {}
..allowedExperimentalFlags = const AllowedExperimentalFlags();
final ProcessedOptions options =
new ProcessedOptions(options: optionBuilder, inputs: [entryPoint]);

View file

@ -23,7 +23,7 @@ import 'package:front_end/src/api_prototype/compiler_options.dart'
show CompilerOptions, DiagnosticMessage;
import 'package:front_end/src/api_prototype/experimental_flags.dart'
show ExperimentalFlag, defaultExperimentalFlags;
show ExperimentalFlag, defaultExperimentalFlags, isExperimentEnabled;
import 'package:front_end/src/api_prototype/standard_file_system.dart'
show StandardFileSystem;
@ -618,7 +618,8 @@ class Outline extends Step<TestDescription, ComponentResult, FastaContext> {
Map<ExperimentalFlag, bool> experimentalFlags =
testOptions.computeExperimentalFlags(context.experimentalFlags);
NnbdMode nnbdMode = context.weak ||
!experimentalFlags[ExperimentalFlag.nonNullable]
!isExperimentEnabled(ExperimentalFlag.nonNullable,
experimentalFlags: experimentalFlags)
? NnbdMode.Weak
: (testOptions.nnbdAgnosticMode ? NnbdMode.Agnostic : NnbdMode.Strong);
List<Uri> inputs = <Uri>[description.uri];

View file

@ -28,11 +28,13 @@ main(List<String> args) async {
runTest: runTestFor(const PatchingDataComputer(), [
new TestConfigWithLanguageVersion(
cfeMarker, 'cfe with libraries specification',
librariesSpecificationUri: createUriForFileName('libraries.json')),
librariesSpecificationUri: createUriForFileName('libraries.json'),
allowedExperimentalFlags: const AllowedExperimentalFlags()),
new TestConfigWithLanguageVersion(cfeWithNnbdMarker,
'cfe with libraries specification and non-nullable',
librariesSpecificationUri: createUriForFileName('libraries.json'),
experimentalFlags: {ExperimentalFlag.nonNullable: true})
experimentalFlags: {ExperimentalFlag.nonNullable: true},
allowedExperimentalFlags: const AllowedExperimentalFlags())
]),
skipMap: {
cfeMarker: [
@ -47,10 +49,12 @@ main(List<String> args) async {
class TestConfigWithLanguageVersion extends TestConfig {
TestConfigWithLanguageVersion(String marker, String name,
{Uri librariesSpecificationUri,
Map<ExperimentalFlag, bool> experimentalFlags = const {}})
Map<ExperimentalFlag, bool> experimentalFlags = const {},
AllowedExperimentalFlags allowedExperimentalFlags})
: super(marker, name,
librariesSpecificationUri: librariesSpecificationUri,
experimentalFlags: experimentalFlags);
experimentalFlags: experimentalFlags,
allowedExperimentalFlags: allowedExperimentalFlags);
@override
void customizeCompilerOptions(CompilerOptions options, TestData testData) {

View file

@ -181,6 +181,7 @@ epoch
err
everytime
evicting
exceed
excess
exe
execute

View file

@ -3,7 +3,8 @@
"libraries": {
"test": {
"patches": [
"patch_lib.dart"
"patch_lib.dart",
"patch_lib2.dart"
],
"uri": "origin_lib.dart"
}

View file

@ -7,6 +7,13 @@ static method main() → dynamic
;
library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:32:14: Error: Field 'staticField' should be initialized because its type 'int' doesn't allow null.
// static int staticField;
// ^^^^^^^^^^^
//
import self as self2;
import "dart:_internal" as _in;
import "dart:core" as core;
@ -15,13 +22,14 @@ import "dart:_internal";
@_in::patch
class Class1 extends core::Object {
field core::int field /* from org-dartlang-testcase:///patch_lib.dart */;
field core::int field /* from org-dartlang-testcase:///patch_lib2.dart */;
static field core::int staticField /* from org-dartlang-testcase:///patch_lib2.dart */;
synthetic constructor •() → self2::Class1
;
}
@_in::patch
class Class2 extends core::Object {
field core::int field /* from org-dartlang-testcase:///patch_lib.dart */;
field core::int field /* from org-dartlang-testcase:///patch_lib2.dart */;
constructor constructor2(core::int field) → self2::Class2
;
constructor constructor1() → self2::Class2

View file

@ -13,11 +13,15 @@ library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib.dart:10:7: Error: Field 'field' should be initialized because its type 'int' doesn't allow null.
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:32:14: Error: Field 'staticField' should be initialized because its type 'int' doesn't allow null.
// static int staticField;
// ^^^^^^^^^^^
//
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:30:7: Error: Field 'field' should be initialized because its type 'int' doesn't allow null.
// int field;
// ^^^^^
//
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib.dart:15:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
// int field;
// ^^^^^
//
@ -29,14 +33,15 @@ import "dart:_internal";
@#C1
class Class1 extends core::Object {
field core::int field = null /* from org-dartlang-testcase:///patch_lib.dart */;
field core::int field = null /* from org-dartlang-testcase:///patch_lib2.dart */;
static field core::int staticField = null /* from org-dartlang-testcase:///patch_lib2.dart */;
synthetic constructor •() → test::Class1
: super core::Object::•()
;
}
@#C1
class Class2 extends core::Object {
field core::int field /* from org-dartlang-testcase:///patch_lib.dart */;
field core::int field /* from org-dartlang-testcase:///patch_lib2.dart */;
constructor constructor2(core::int field) → test::Class2
: test::Class2::field = field, super core::Object::•()
;

View file

@ -13,11 +13,15 @@ library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib.dart:10:7: Error: Field 'field' should be initialized because its type 'int' doesn't allow null.
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:32:14: Error: Field 'staticField' should be initialized because its type 'int' doesn't allow null.
// static int staticField;
// ^^^^^^^^^^^
//
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:30:7: Error: Field 'field' should be initialized because its type 'int' doesn't allow null.
// int field;
// ^^^^^
//
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib.dart:15:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
// int field;
// ^^^^^
//
@ -29,14 +33,15 @@ import "dart:_internal";
@#C1
class Class1 extends core::Object {
field core::int field = null /* from org-dartlang-testcase:///patch_lib.dart */;
field core::int field = null /* from org-dartlang-testcase:///patch_lib2.dart */;
static field core::int staticField = null /* from org-dartlang-testcase:///patch_lib2.dart */;
synthetic constructor •() → test::Class1
: super core::Object::•()
;
}
@#C1
class Class2 extends core::Object {
field core::int field /* from org-dartlang-testcase:///patch_lib.dart */;
field core::int field /* from org-dartlang-testcase:///patch_lib2.dart */;
constructor constructor2(core::int field) → test::Class2
: test::Class2::field = field, super core::Object::•()
;

View file

@ -13,11 +13,15 @@ library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib.dart:10:7: Error: Field 'field' should be initialized because its type 'int' doesn't allow null.
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:32:14: Error: Field 'staticField' should be initialized because its type 'int' doesn't allow null.
// static int staticField;
// ^^^^^^^^^^^
//
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:30:7: Error: Field 'field' should be initialized because its type 'int' doesn't allow null.
// int field;
// ^^^^^
//
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib.dart:15:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
// int field;
// ^^^^^
//
@ -29,14 +33,15 @@ import "dart:_internal";
@#C1
class Class1 extends core::Object {
field core::int field = null /* from org-dartlang-testcase:///patch_lib.dart */;
field core::int field = null /* from org-dartlang-testcase:///patch_lib2.dart */;
static field core::int staticField = null /* from org-dartlang-testcase:///patch_lib2.dart */;
synthetic constructor •() → test::Class1
: super core::Object::•()
;
}
@#C1
class Class2 extends core::Object {
field core::int field /* from org-dartlang-testcase:///patch_lib.dart */;
field core::int field /* from org-dartlang-testcase:///patch_lib2.dart */;
constructor constructor2(core::int field) → test::Class2
: test::Class2::field = field, super core::Object::•()
;

View file

@ -13,11 +13,15 @@ library /*isNonNullableByDefault*/;
//
// Problems in library:
//
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib.dart:10:7: Error: Field 'field' should be initialized because its type 'int' doesn't allow null.
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:32:14: Error: Field 'staticField' should be initialized because its type 'int' doesn't allow null.
// static int staticField;
// ^^^^^^^^^^^
//
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:30:7: Error: Field 'field' should be initialized because its type 'int' doesn't allow null.
// int field;
// ^^^^^
//
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib.dart:15:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
// int field;
// ^^^^^
//
@ -29,14 +33,15 @@ import "dart:_internal";
@#C1
class Class1 extends core::Object {
field core::int field = null /* from org-dartlang-testcase:///patch_lib.dart */;
field core::int field = null /* from org-dartlang-testcase:///patch_lib2.dart */;
static field core::int staticField = null /* from org-dartlang-testcase:///patch_lib2.dart */;
synthetic constructor •() → test::Class1
: super core::Object::•()
;
}
@#C1
class Class2 extends core::Object {
field core::int field /* from org-dartlang-testcase:///patch_lib.dart */;
field core::int field /* from org-dartlang-testcase:///patch_lib2.dart */;
constructor constructor2(core::int field) → test::Class2
: test::Class2::field = field, super core::Object::•()
;

View file

@ -4,15 +4,3 @@
// ignore: import_internal_library
import 'dart:_internal';
@patch
class Class1 {
int field;
}
@patch
class Class2 {
int field;
Class2.constructor2(this.field);
}

View file

@ -0,0 +1,40 @@
// 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.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
// Comment to make offset in patch_lib2.dart exceed the range of patch_lib.dart.
@patch
class Class1 {
int field;
static int staticField;
}
@patch
class Class2 {
int field;
Class2.constructor2(this.field);
}

View file

@ -22,7 +22,7 @@ main(List<String> arguments) {
Uri computeCfeGeneratedFile() {
return Platform.script
.resolve("../../lib/src/api_prototype/experimental_flags.dart");
.resolve("../../lib/src/api_prototype/experimental_flags_generated.dart");
}
Uri computeKernelGeneratedFile() {
@ -91,7 +91,7 @@ String generateCfeFile() {
StringBuffer sb = new StringBuffer();
sb.write('''
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS 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.
@ -100,8 +100,7 @@ String generateCfeFile() {
// Instead modify 'tools/experimental_features.yaml' and run
// 'dart pkg/front_end/tool/fasta.dart generate-experimental-flags' to update.
import 'package:_fe_analyzer_shared/src/sdk/allowed_experiments.dart';
import 'package:kernel/kernel.dart' show Version;
part of 'experimental_flags.dart';
''');
Map<dynamic, dynamic> features = yaml['features'];
@ -182,32 +181,33 @@ const Map<ExperimentalFlag, bool> expiredExperimentalFlags = {
new File.fromUri(allowListFile).readAsStringSync());
sb.write('''
const AllowedExperiments allowedExperiments = const AllowedExperiments(
const AllowedExperimentalFlags defaultAllowedExperimentalFlags =
const AllowedExperimentalFlags(
''');
sb.writeln('sdkDefaultExperiments: [');
sb.writeln('sdkDefaultExperiments: {');
for (String sdkDefaultExperiment
in allowedExperiments.sdkDefaultExperiments) {
sb.writeln('"$sdkDefaultExperiment",');
sb.writeln('ExperimentalFlag.${keyToIdentifier(sdkDefaultExperiment)},');
}
sb.writeln('],');
sb.writeln('},');
sb.writeln('sdkLibraryExperiments: {');
allowedExperiments.sdkLibraryExperiments
.forEach((String library, List<String> experiments) {
sb.writeln('"$library": [');
sb.writeln('"$library": {');
for (String experiment in experiments) {
sb.writeln('"$experiment",');
sb.writeln('ExperimentalFlag.${keyToIdentifier(experiment)},');
}
sb.writeln('],');
sb.writeln('},');
});
sb.writeln('},');
sb.writeln('packageExperiments: {');
allowedExperiments.packageExperiments
.forEach((String package, List<String> experiments) {
sb.writeln('"$package": [');
sb.writeln('"$package": {');
for (String experiment in experiments) {
sb.writeln('"$experiment",');
sb.writeln('ExperimentalFlag.${keyToIdentifier(experiment)},');
}
sb.writeln('],');
sb.writeln('},');
});
sb.writeln('});');