From 0a92b0c3aa2e32924a04c7a12a544f98b611fea4 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Tue, 24 May 2022 13:54:23 +0000 Subject: [PATCH] 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 Commit-Queue: Paul Berry Reviewed-by: Liam Appelbe Reviewed-by: Michael Thomsen --- CHANGELOG.md | 47 +++++++++++++++++++ .../lib/src/dart/analysis/experiments.g.dart | 4 +- .../experimental_flags_generated.dart | 2 +- runtime/vm/experimental_features.cc | 42 +++++++---------- runtime/vm/experimental_features.h | 1 + tests/corelib/iterable_empty_test.dart | 2 +- tools/experimental_features.yaml | 20 ++++++-- 7 files changed, 85 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab41e51c3e40..46f2467778ec 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 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 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 ints = [1, 2, 3]; + var maximumOrNull = ints.fold(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 0ddc93bf87d5..de04c117c849 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 @@ class ExperimentalFeatures { 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 @@ class IsEnabledByDefault { 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 3bfd9d365e16..bc702790ac10 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 @@ class ExperimentalFlag { 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 6ac781245e09..c776db0f1674 100644 --- a/runtime/vm/experimental_features.cc +++ b/runtime/vm/experimental_features.cc @@ -18,19 +18,8 @@ namespace dart { 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(feature) < ARRAY_SIZE(kFeatureValues)); return kFeatureValues[static_cast(feature)]; @@ -38,19 +27,20 @@ bool GetExperimentalFeatureDefault(ExperimentalFeature feature) { 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(feature) < ARRAY_SIZE(kFeatureNames)); return kFeatureNames[static_cast(feature)]; diff --git a/runtime/vm/experimental_features.h b/runtime/vm/experimental_features.h index c32ef01dedab..be9be593cf15 100644 --- a/runtime/vm/experimental_features.h +++ b/runtime/vm/experimental_features.h @@ -27,6 +27,7 @@ enum class ExperimentalFeature { 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 7d260883fdbd..84749ce35367 100644 --- a/tests/corelib/iterable_empty_test.dart +++ b/tests/corelib/iterable_empty_test.dart @@ -18,7 +18,7 @@ main() { 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(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 cea81af3fd63..dec610cf0b3d 100644 --- a/tools/experimental_features.yaml +++ b/tools/experimental_features.yaml @@ -125,9 +125,6 @@ features: 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 @@ features: 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 list) { + var a = list.fold(0, (x, y) => x + y); + f(a); + } + void f(T t) { + if (T == int) { + print('feature enabled'); + } + } + void main() { + test([1, 2, 3]); + }