Turn on the experimental feature `inference-update-1`.
Fixes https://github.com/dart-lang/language/issues/731.
Change-Id: I5fee1470efe7b891b79dcfecd33bc3670590efb3
Tested: trybots, and global presubmit in the internal mono repo
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/243530
Reviewed-by: Bob Nystrom <rnystrom@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
Reviewed-by: Liam Appelbe <liama@google.com>
Reviewed-by: Michael Thomsen <mit@google.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ab41e51..46f2467 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,52 @@
## 2.18.0
+### Language
+
+The following features are new in the Dart 2.18 [language version][]. To use
+them, you must set the lower bound on the SDK constraint for your package to
+2.18 or greater (`sdk: '>=2.18.0 <3.0.0'`).
+
+[language version]: https://dart.dev/guides/language/evolution
+
+- **[Enhanced type inference for generic invocations with function
+ literals][]**: Invocations of generic methods/constructors that supply
+ function literal arguments now have improved type inference. This primarily
+ affects the `Iterable.fold` method. For example, in previous versions of
+ Dart, the compiler would fail to infer an appropriate type for the parameter
+ `a`:
+
+ ```dart
+ void main() {
+ List<int> ints = [1, 2, 3];
+ var maximum = ints.fold(0, (a, b) => a < b ? b : a);
+ }
+ ```
+
+ With this improvement, `a` receives its type from the initial value, `0`.
+
+ On rare occasions, the wrong type will be inferred, leading to a compile-time
+ error, for example in this code, type inference will infer that `a` has a
+ type of `Null`:
+
+ ```dart
+ void main() {
+ List<int> ints = [1, 2, 3];
+ var maximumOrNull = ints.fold(null,
+ (a, b) => a == null || a < b ? b : a);
+ }
+ ```
+
+ This can be worked around by supplying the appropriate type as an explicit
+ type argument to `fold`:
+
+ ```dart
+ void main() {
+ List<int> ints = [1, 2, 3];
+ var maximumOrNull = ints.fold<int?>(null,
+ (a, b) => a == null || a < b ? b : a);
+ }
+ ```
+
### Core libraries
#### `dart:html`
diff --git a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
index 0ddc93b..de04c11 100644
--- a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
@@ -197,7 +197,7 @@
documentation:
'Horizontal type inference for function expressions passed to generic invocations.',
experimentalReleaseVersion: null,
- releaseVersion: null,
+ releaseVersion: Version.parse('2.18.0'),
);
static final inference_update_2 = ExperimentalFeature(
@@ -350,7 +350,7 @@
static const bool generic_metadata = true;
/// Default state of the experiment "inference-update-1"
- static const bool inference_update_1 = false;
+ static const bool inference_update_1 = true;
/// Default state of the experiment "inference-update-2"
static const bool inference_update_2 = 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 3bfd9d3..bc70279 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
@@ -125,7 +125,7 @@
static const ExperimentalFlag inferenceUpdate1 = const ExperimentalFlag(
name: 'inference-update-1',
- isEnabledByDefault: false,
+ isEnabledByDefault: true,
isExpired: false,
enabledVersion: const Version(2, 18),
experimentEnabledVersion: const Version(2, 18),
diff --git a/runtime/vm/experimental_features.cc b/runtime/vm/experimental_features.cc
index 6ac7812..c776db0f 100644
--- a/runtime/vm/experimental_features.cc
+++ b/runtime/vm/experimental_features.cc
@@ -18,19 +18,8 @@
bool GetExperimentalFeatureDefault(ExperimentalFeature feature) {
constexpr bool kFeatureValues[] = {
- true,
- true,
- true,
- true,
- true,
- true,
- true,
- true,
- true,
- true,
- true,
- true,
- true,
+ true, true, true, true, true, true, true,
+ true, true, true, true, true, true, true,
};
ASSERT(static_cast<size_t>(feature) < ARRAY_SIZE(kFeatureValues));
return kFeatureValues[static_cast<int>(feature)];
@@ -38,19 +27,20 @@
const char* GetExperimentalFeatureName(ExperimentalFeature feature) {
constexpr const char* kFeatureNames[] = {
- "nonfunction-type-aliases",
- "non-nullable",
- "extension-methods",
- "constant-update-2018",
- "control-flow-collections",
- "generic-metadata",
- "set-literals",
- "spread-collections",
- "triple-shift",
- "constructor-tearoffs",
- "enhanced-enums",
- "named-arguments-anywhere",
- "super-parameters",
+ "nonfunction-type-aliases",
+ "non-nullable",
+ "extension-methods",
+ "constant-update-2018",
+ "control-flow-collections",
+ "generic-metadata",
+ "set-literals",
+ "spread-collections",
+ "triple-shift",
+ "constructor-tearoffs",
+ "enhanced-enums",
+ "named-arguments-anywhere",
+ "super-parameters",
+ "inference-update-1",
};
ASSERT(static_cast<size_t>(feature) < ARRAY_SIZE(kFeatureNames));
return kFeatureNames[static_cast<int>(feature)];
diff --git a/runtime/vm/experimental_features.h b/runtime/vm/experimental_features.h
index c32ef01..be9be59 100644
--- a/runtime/vm/experimental_features.h
+++ b/runtime/vm/experimental_features.h
@@ -27,6 +27,7 @@
enhanced_enums,
named_arguments_anywhere,
super_parameters,
+ inference_update_1,
};
bool GetExperimentalFeatureDefault(ExperimentalFeature feature);
diff --git a/tests/corelib/iterable_empty_test.dart b/tests/corelib/iterable_empty_test.dart
index 7d26088..84749ce 100644
--- a/tests/corelib/iterable_empty_test.dart
+++ b/tests/corelib/iterable_empty_test.dart
@@ -18,7 +18,7 @@
Expect.throwsRangeError(() => it.elementAt(0), name);
Expect.throwsStateError(() => it.reduce((a, b) => a), name);
Expect.throwsStateError(() => it.singleWhere((_) => true), name);
- Expect.equals(42, it.fold(42, (a, b) => "not 42"), name);
+ Expect.equals(42, it.fold<dynamic>(42, (a, b) => "not 42"), name);
Expect.equals(42, it.firstWhere((v) => true, orElse: () => 42), name);
Expect.equals(42, it.lastWhere((v) => true, orElse: () => 42), name);
Expect.equals("", it.join("separator"), name);
diff --git a/tools/experimental_features.yaml b/tools/experimental_features.yaml
index cea81af..dec610c 100644
--- a/tools/experimental_features.yaml
+++ b/tools/experimental_features.yaml
@@ -125,9 +125,6 @@
macros:
help: "Static meta-programming"
- inference-update-1:
- help: "Horizontal type inference for function expressions passed to generic invocations."
-
inference-update-2:
help: "Type promotion for fields"
@@ -264,3 +261,20 @@
void main(){
print(C('feature enabled').foo);
}
+
+ inference-update-1:
+ help: "Horizontal type inference for function expressions passed to generic invocations."
+ enabledIn: '2.18.0'
+ 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]);
+ }