mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 16:41:07 +00:00
![Paul Berry](/assets/img/avatar_default.png)
This language feature allows type promotion to apply to private final fields, e.g.: class C { final int? _x; C(this._x); } f(C c) { if (c._x != null) { print(c._x.abs()); // (1) } } Previously the line marked (1) would have needed to be written `print(c._x!.abs());`. Note that to ensure soundness, there are certain restrictions: - Public fields don't undergo promotion (because a public field might be overridden by a class in some other library). - Non-final fields don't undergo promotion (because a non-final field might be modified as a side effect of code executed between the type test and the field's usage). - Fields that are forwarded to `noSuchMethod` in the same library don't undergo promotion (because there's no guarantee that `noSuchMethod` will return the same value on every invocation). For example: class C { final int? _x; C(this._x); } class D implements C { @override noSuchMethod(...) => ...; } f(C c) { if (c._x != null) { print(c._x.abs()); // ERROR: `c._x` might dispatch to // `D.noSuchMethod`, in which case there's // no guarantee that it will return a // non-null value the second time it's // invoked. } } - If two classes define fields or getters of the same name, and promotion is not permitted for one of them, then it isn't permitted for the other. This is because there might be a class in some other library that's a subclass of both classes, causing a reference to one field or getter to dispatch to the other. For example: class C { final int? _x; C(this._x); } class D { int? get _x => ...; } f(C c) { if (c._x != null) { print(c._x.abs()); // ERROR: `c._x` might dispatch to `D._x` // (e.g. because some library might declare // `class E extends D implements C`), in // which case there's no guarantee that it // will return a non-null value the second // time it's invoked. } } Change-Id: Ib9183581aa0194377e38ab70d37c3e9f0bb57a75 Bug: https://github.com/dart-lang/language/issues/2020 Tested: TAP global presubmit Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/314600 Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Nate Bosch <nbosch@google.com> Commit-Queue: Paul Berry <paulberry@google.com>
349 lines
10 KiB
YAML
349 lines
10 KiB
YAML
# Copyright (c) 2019, 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.
|
|
|
|
# Experimental features are described in docs/process/experimental-flags.md
|
|
#
|
|
# Despite the name, they are not limited to experiments, and are often
|
|
# used to enable new features or enhancements that are being
|
|
# developed and are not yet shipped. Experimental feature flags are expected
|
|
# to be relatively short-lived. Some features behind experiment flags
|
|
# may get cancelled and never ship.
|
|
#
|
|
# ### Code Generation
|
|
#
|
|
# When you change this file, run the following to update analyzer, kernel, and
|
|
# vm:
|
|
#
|
|
# analyzer:
|
|
# dart pkg/analyzer/tool/experiments/generate.dart
|
|
#
|
|
# Also, pkg/analyzer/lib/src/dart/analysis/driver.dart will need a bump in
|
|
# DATA_VERSION if making changes that change the "index" of any previous flags,
|
|
# e.g. if adding a new flag that doesn't happen to be lexicographically last.
|
|
#
|
|
# kernel:
|
|
# dart pkg/front_end/tool/fasta.dart generate-experimental-flags
|
|
#
|
|
# vm:
|
|
# dart tools/generate_experimental_flags.dart
|
|
#
|
|
# ### Overview
|
|
#
|
|
# This document consists mostly of a map called "features".
|
|
# Each entry in this map corresponds to an experiment,
|
|
# and contains the following parts:
|
|
#
|
|
# 1. help: (required text)
|
|
# A human readable description of the experiment.
|
|
#
|
|
# 2. enabledIn: (optional #.#)
|
|
# The Dart SDK version (<major>.<minor>) in which the experiment is shipping.
|
|
#
|
|
# If this field is specified, then the experiment is enabled regardless of
|
|
# the actual version of the SDK. If this field is omitted, then the
|
|
# experiment is disabled by default, but may be enabled by specifying the
|
|
# flag on the command line. (e.g. --enable-experiment=non-nullable)
|
|
#
|
|
# A version less than this version may be specified in a .packages file
|
|
# or in a library language version override (e.g. // @dart = 2.1)
|
|
# to disable this feature. For more on library language version override, see
|
|
# https://github.com/dart-lang/language/blob/master/accepted/future-releases/language-versioning/language-versioning.md
|
|
#
|
|
# 3. expired: (optional boolean)
|
|
# If true, then the experiment can no longer be enabled by specifying the
|
|
# flag on the command line, and the corresponding entry is slated for
|
|
# eventual removal from this file. If this field is omitted, then 'expired'
|
|
# is considered to be false.
|
|
#
|
|
# 4. validation: (optional string)
|
|
# If provided this should be a program that prints "feature enabled" on
|
|
# stdout if the feature is enabled, and throws or fails to compile otherwise.
|
|
# The intended use for this is to be able to run generic tests for each
|
|
# experiment.
|
|
#
|
|
# Using the above fields, experiments pass through several states:
|
|
#
|
|
# Disabled:
|
|
# When an experiment is first added to this file, the 'enabledIn' and
|
|
# 'expired' fields are omitted and the experiment is disabled by default,
|
|
# but may be enabled by specifying the flag on the command line.
|
|
# The implementation teams begin building support for the feature,
|
|
# guarded by the flag. Users can enable the flag and begin to try out
|
|
# the feature as it is being developed.
|
|
#
|
|
# Experimental release:
|
|
# When an experiment is released, then the 'experimentalReleaseVersion' field
|
|
# is added indicating which version of the SDK contains this new language
|
|
# feature for libraries and packages in mentioned in
|
|
# `sdk/lib/_internal/allowed_experiments.json`. For other libraries and
|
|
# packages, passing the experiment flag is still required to turn on the
|
|
# experiment.
|
|
#
|
|
# Shipped:
|
|
# When an experiment is shipped, then the 'enabledIn' field is added
|
|
# indicating which version of the SDK contains this new language feature.
|
|
# At this point, specifying the flag on the command line has no effect because
|
|
# the experiment is enabled by default and cannot be disabled.
|
|
#
|
|
# Retired or Rejected:
|
|
# At some point, the 'expired' field is added to the experiment indicating
|
|
# that the flag is to be retired if the experiment has shipped or that the
|
|
# entire experiment was rejected if the experiment has not shipped. It also
|
|
# indicates that the corresponding entry is slated for eventual removal
|
|
# from this file. Users specifying this flag on the command line should receive
|
|
# a warning that the experiment has been retired or rejected, but the tool
|
|
# should continue to run.
|
|
#
|
|
# In addition, there is also a value called "current-version"
|
|
# specifying the version of Dart that is currently being developed.
|
|
# Dart source files that don't specify their own version will be
|
|
# presumed to be in this version. Experiment flags will not affect
|
|
# files that specify an earlier version.
|
|
#
|
|
# Furthermore, most of the above was designed with language features
|
|
# (spanning both CFE and Analyzer) in mind, but didn't take into account
|
|
# features in individual products (e.g. in CFE that has no influence on
|
|
# Analyzer). As a stepping-stone to allow for this usage as well, a "category"
|
|
# is also available. If no "category" is specified it's assumed to be the
|
|
# default 'language' "category" with code generated for both CFE and Analyzer,
|
|
# while other categories can be tailored more specifically.
|
|
|
|
current-version: '3.2.0'
|
|
|
|
features:
|
|
variance:
|
|
help: "Sound variance"
|
|
|
|
const-functions:
|
|
help: "Allow more of the Dart language to be executed in const expressions."
|
|
|
|
macros:
|
|
help: "Static meta-programming"
|
|
|
|
inline-class:
|
|
help: "Extension Types"
|
|
|
|
native-assets:
|
|
help: "Compile and bundle native assets."
|
|
|
|
# Experiment flag only used for testing.
|
|
test-experiment:
|
|
help: >-
|
|
Has no effect. Can be used for testing the --enable-experiment
|
|
command line functionality.
|
|
|
|
#
|
|
# Flags below this line are shipped, or scheduled to ship in the next
|
|
# stable release. They should be sorted descending by release.
|
|
#
|
|
# Shipped flags should be marked retired the following stable release.
|
|
#
|
|
|
|
inference-update-2:
|
|
enabledIn: '3.2.0'
|
|
validation: |
|
|
class C {
|
|
final String? _x;
|
|
C(this._x);
|
|
}
|
|
String f(C c) => c._x == null ? 'no' : c._x;
|
|
main() {
|
|
print(f(C('feature enabled')));
|
|
}
|
|
help: "Type promotion for fields"
|
|
|
|
sealed-class:
|
|
help: "Sealed class"
|
|
enabledIn: '3.0.0'
|
|
validation: |
|
|
sealed class A {}
|
|
void main() {
|
|
print('feature enabled');
|
|
}
|
|
|
|
class-modifiers:
|
|
help: "Class modifiers"
|
|
enabledIn: '3.0.0'
|
|
validation: |
|
|
interface class A {}
|
|
void main() {
|
|
print('feature enabled');
|
|
}
|
|
|
|
records:
|
|
help: "Records"
|
|
enabledIn: '3.0.0'
|
|
validation: |
|
|
final x = ('feature', a: 'enabled');
|
|
void main() {
|
|
print('${x.$1} ${x.a}');
|
|
}
|
|
|
|
patterns:
|
|
help: "Patterns"
|
|
enabledIn: '3.0.0'
|
|
validation: |
|
|
void main() {
|
|
final [a, b] = ['feature', 'enabled'];
|
|
print('$a $b');
|
|
}
|
|
|
|
unnamed-libraries:
|
|
help: "Unnamed libraries"
|
|
enabledIn: '2.19.0'
|
|
expired: true
|
|
validation: |
|
|
library;
|
|
void main() => print('feature enabled');
|
|
|
|
alternative-invalidation-strategy:
|
|
help: "Alternative invalidation strategy for incremental compilation."
|
|
category: "CFE"
|
|
enabledIn: '2.18.0'
|
|
expired: true
|
|
|
|
inference-update-1:
|
|
help: "Horizontal type inference for function expressions passed to generic invocations."
|
|
enabledIn: '2.18.0'
|
|
expired: true
|
|
validation: |
|
|
void test(List<int> list) {
|
|
var a = list.fold(0, (x, y) => x + y);
|
|
f(a);
|
|
}
|
|
void f<T>(T t) {
|
|
if (T == int) {
|
|
print('feature enabled');
|
|
}
|
|
}
|
|
void main() {
|
|
test([1, 2, 3]);
|
|
}
|
|
|
|
enhanced-enums:
|
|
help: "Enhanced Enums"
|
|
enabledIn: '2.17.0'
|
|
validation: |
|
|
enum T {
|
|
t();
|
|
void test() {
|
|
print('feature enabled');
|
|
}
|
|
}
|
|
void main() {
|
|
T.t.test();
|
|
}
|
|
expired: true
|
|
|
|
named-arguments-anywhere:
|
|
help: "Named Arguments Anywhere"
|
|
enabledIn: '2.17.0'
|
|
validation: |
|
|
void test(String msg, {bool enabled = false}) {
|
|
if (enabled) {
|
|
print(msg);
|
|
}
|
|
}
|
|
void main() {
|
|
test(enabled : true, 'feature enabled');
|
|
}
|
|
expired: true
|
|
|
|
super-parameters:
|
|
help: "Super-Initializer Parameters"
|
|
enabledIn: '2.17.0'
|
|
validation: |
|
|
class B {
|
|
final String foo;
|
|
B(this.foo);
|
|
}
|
|
class C extends B {
|
|
C(super.foo);
|
|
}
|
|
void main(){
|
|
print(C('feature enabled').foo);
|
|
}
|
|
expired: true
|
|
|
|
constructor-tearoffs:
|
|
help: "Allow constructor tear-offs and explicit generic instantiations."
|
|
enabledIn: '2.15.0'
|
|
validation: |
|
|
class A {
|
|
A() {
|
|
print('feature enabled');
|
|
}
|
|
}
|
|
void main() {
|
|
var c = A.new;
|
|
c();
|
|
}
|
|
expired: true
|
|
|
|
generic-metadata:
|
|
help: >-
|
|
Allow annotations to accept type arguments;
|
|
also allow generic function types as type arguments.
|
|
enabledIn: '2.14.0'
|
|
expired: true
|
|
|
|
triple-shift:
|
|
help: "Triple-shift operator"
|
|
enabledIn: '2.14.0'
|
|
validation: |
|
|
class A {
|
|
operator>>>(int k) => 42;
|
|
}
|
|
void main() {
|
|
if ((A() >>> 1) == 42) print('feature enabled');
|
|
}
|
|
expired: true
|
|
|
|
nonfunction-type-aliases:
|
|
help: "Type aliases define a <type>, not just a <functionType>"
|
|
enabledIn: '2.13.0'
|
|
validation: |
|
|
typedef S = String;
|
|
void main() {
|
|
S s = 'feature enabled';
|
|
print(s);
|
|
}
|
|
expired: true
|
|
|
|
non-nullable:
|
|
help: "Non Nullable by default"
|
|
experimentalReleaseVersion: '2.10.0'
|
|
enabledIn: '2.12.0'
|
|
validation: |
|
|
void main() {
|
|
int? a = null;
|
|
print('feature enabled');
|
|
}
|
|
expired: true
|
|
|
|
extension-methods:
|
|
help: "Extension Methods"
|
|
enabledIn: '2.6.0'
|
|
expired: true
|
|
|
|
constant-update-2018:
|
|
help: "Enhanced constant expressions"
|
|
enabledIn: '2.0.0'
|
|
expired: true
|
|
|
|
control-flow-collections:
|
|
help: "Control Flow Collections"
|
|
enabledIn: '2.0.0'
|
|
expired: true
|
|
|
|
set-literals:
|
|
help: "Set Literals"
|
|
enabledIn: '2.0.0'
|
|
expired: true
|
|
|
|
spread-collections:
|
|
help: "Spread Collections"
|
|
enabledIn: '2.0.0'
|
|
expired: true
|