From 39a2e69ea458b368a73e5885598c2cd76b7481f2 Mon Sep 17 00:00:00 2001 From: Leaf Petersen Date: Sat, 3 Apr 2021 01:31:42 +0000 Subject: [PATCH] Enable non-function type aliases by default in 2.13. TEST=language/nonfunction-type-aliases Change-Id: Ifff4e838fbfc4f71e2d990e1f1f8a67b987adf91 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/192948 Commit-Queue: Leaf Petersen Reviewed-by: Erik Ernst --- CHANGELOG.md | 42 +++++++++++++++++ .../lib/src/dart/analysis/experiments.g.dart | 4 +- .../experimental_flags_generated.dart | 2 +- runtime/vm/experimental_features.cc | 9 ++-- runtime/vm/experimental_features.h | 1 + .../generic/function_typedef2_test.dart | 4 ++ .../generic/function_typedef3_test.dart | 47 +++++++++++++++++++ tools/experimental_features.yaml | 13 +++-- 8 files changed, 112 insertions(+), 10 deletions(-) create mode 100644 tests/language/generic/function_typedef3_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 4028c90daed..51cf0650e1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,48 @@ ### Language +* **Type aliases** [Non-function type aliases][]: Type aliases (names for + types introduced via the `typedef` keyword) were previously restricted + to only introduce names for function types. In this release, we + remove this restriction and allow type aliases to name any kind of type. + + ```dart + import 'dart:convert'; + + typedef JsonMap = Map; + + JsonMap parseJsonMap(String input) => json.decode(input) as JsonMap; + ``` + + In addition to being usable as type annotations, type aliases that name + class types can now also be used anywhere that the underlying class could be + used, allowing type aliases to be used to safely rename existing classes. + + ```dart + class NewClassName { + NewClassName.create(T x); + static NewClassName mkOne(T x) => NewClassName.create(x); + } + @Deprecated("Use NewClassName instead") + typedef OldClassName = NewClassName; + + class LegacyClass extends OldClassName { + LegacyClass() : super.create(3); + } + OldClassName legacyCode() { + var one = OldClassName.create(1); + var two = OldClassName.mkOne(2); + return LegacyClass(); + } + ``` + + The new type alias feature is only available as part of the 2.13 [language + version](https://dart.dev/guides/language/evolution). To use this feature, + you must set the lower bound on the sdk constraint for your package to 2.13 + or greater. + + [Non-function type aliases]: https://github.com/dart-lang/language/blob/master/accepted/2.13/nonfunction-type-aliases/feature-specification.md + ### Core libraries #### `dart:collection` diff --git a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart index 5d7c6ecb1c5..74cac9dc59d 100644 --- a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart +++ b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart @@ -152,7 +152,7 @@ class ExperimentalFeatures { isExpired: IsExpired.nonfunction_type_aliases, documentation: 'Type aliases define a , not just a ', experimentalReleaseVersion: null, - releaseVersion: null, + releaseVersion: Version.parse('2.13.0'), ); static final set_literals = ExperimentalFeature( @@ -231,7 +231,7 @@ class IsEnabledByDefault { static const bool non_nullable = true; /// Default state of the experiment "nonfunction-type-aliases" - static const bool nonfunction_type_aliases = false; + static const bool nonfunction_type_aliases = true; /// Default state of the experiment "set-literals" static const bool set_literals = true; 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 e7d11dc5fed..f774c070194 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 @@ -87,7 +87,7 @@ const Map defaultExperimentalFlags = { ExperimentalFlag.extensionTypes: false, ExperimentalFlag.genericMetadata: false, ExperimentalFlag.nonNullable: true, - ExperimentalFlag.nonfunctionTypeAliases: false, + ExperimentalFlag.nonfunctionTypeAliases: true, ExperimentalFlag.setLiterals: true, ExperimentalFlag.spreadCollections: true, ExperimentalFlag.tripleShift: false, diff --git a/runtime/vm/experimental_features.cc b/runtime/vm/experimental_features.cc index e341195996c..57eb3099ce0 100644 --- a/runtime/vm/experimental_features.cc +++ b/runtime/vm/experimental_features.cc @@ -18,7 +18,7 @@ namespace dart { bool GetExperimentalFeatureDefault(ExperimentalFeature feature) { constexpr bool kFeatureValues[] = { - 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)]; @@ -26,9 +26,10 @@ bool GetExperimentalFeatureDefault(ExperimentalFeature feature) { const char* GetExperimentalFeatureName(ExperimentalFeature feature) { constexpr const char* kFeatureNames[] = { - "non-nullable", "extension-methods", - "constant-update-2018", "control-flow-collections", - "set-literals", "spread-collections", + "nonfunction-type-aliases", "non-nullable", + "extension-methods", "constant-update-2018", + "control-flow-collections", "set-literals", + "spread-collections", }; 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 8efd29ec704..d6816b3e59c 100644 --- a/runtime/vm/experimental_features.h +++ b/runtime/vm/experimental_features.h @@ -14,6 +14,7 @@ namespace dart { enum class ExperimentalFeature { + nonfunction_type_aliases, non_nullable, extension_methods, constant_update_2018, diff --git a/tests/language/generic/function_typedef2_test.dart b/tests/language/generic/function_typedef2_test.dart index 6d9c0ffd505..22fd24864e3 100644 --- a/tests/language/generic/function_typedef2_test.dart +++ b/tests/language/generic/function_typedef2_test.dart @@ -3,6 +3,10 @@ // BSD-style license that can be found in the LICENSE file. // Dart test for a function type test that cannot be eliminated at compile time. +// This test validates the static errors for typedefs in language versions +// prior to the release of nonfunction type aliases (Dart 2.13). +// @dart=2.12 + import "package:expect/expect.dart"; class A {} diff --git a/tests/language/generic/function_typedef3_test.dart b/tests/language/generic/function_typedef3_test.dart new file mode 100644 index 00000000000..47c3838e190 --- /dev/null +++ b/tests/language/generic/function_typedef3_test.dart @@ -0,0 +1,47 @@ +// Copyright (c) 2017, 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. +// Dart test for a function type test that cannot be eliminated at compile time. + +// This test validates the static errors for typedefs as per the code in +// function_typedef2_test.dart in language versions after the release of +// nonfunction type aliases (Dart 2.13). + +import "package:expect/expect.dart"; + +class A {} + +typedef int F(); + +typedef G = F; + +typedef H = int; + +typedef I = A; + +typedef J = List; + +typedef K = Function(Function(A)); +// ^^^^^^ +// [analyzer] COMPILE_TIME_ERROR.WRONG_NUMBER_OF_TYPE_ARGUMENTS +// [cfe] Can't use type arguments with type variable 'A'. +typedef L = Function({x}); +// ^ +// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_CLASS +// [cfe] Type 'x' not found. +// ^ +// [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER +// [cfe] Expected an identifier, but got '}'. + +typedef M = Function({int}); + // ^ + // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER + // [cfe] Expected an identifier, but got '}'. + +foo({bool int = false}) {} +main() { + bool b = true; + Expect.isFalse(b is L); + Expect.isFalse(b is M); + Expect.isTrue(foo is M); +} diff --git a/tools/experimental_features.yaml b/tools/experimental_features.yaml index f3375ea1155..336213dd412 100644 --- a/tools/experimental_features.yaml +++ b/tools/experimental_features.yaml @@ -119,9 +119,6 @@ features: variance: help: "Sound variance" - nonfunction-type-aliases: - help: "Type aliases define a , not just a " - alternative-invalidation-strategy: help: "Alternative invalidation strategy for incremental compilation" category: "CFE" @@ -143,6 +140,16 @@ features: # on the command line, and will eventually be removed. # + nonfunction-type-aliases: + help: "Type aliases define a , not just a " + enabledIn: '2.13.0' + validation: | + typedef S = String; + void main() { + S s = 'feature enabled'; + print(s); + } + non-nullable: help: "Non Nullable by default" experimentalReleaseVersion: '2.10.0'