dart-sdk/tools/experimental_features.yaml
Paul Berry 2b8411f626 Enable language feature inference-update-2.
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>
2023-07-28 23:56:52 +00:00

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