Version 2.16.0-160.0.dev
Merge commit '0a8298d14c96cfd82cd391dc68a10ad77e5ff352' into 'dev'
diff --git a/tests/language/enum/enhanced_enums_basic_test.dart b/tests/language/enum/enhanced_enums_basic_test.dart
new file mode 100644
index 0000000..ee3a0e0
--- /dev/null
+++ b/tests/language/enum/enhanced_enums_basic_test.dart
@@ -0,0 +1,370 @@
+// Copyright (c) 2021, 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.
+
+// SharedOptions=--enable-experiment=enhanced-enums
+
+// Test new enhanced enum syntax.
+
+import 'package:expect/expect.dart';
+
+void main() {
+ Expect.equals(3, EnumPlain.values.length);
+ Expect.identical(EnumPlain.v1, EnumPlain.values[0]);
+ Expect.identical(EnumPlain.v2, EnumPlain.values[1]);
+ Expect.identical(EnumPlain.v3, EnumPlain.values[2]);
+
+ Expect.equals(3, EnumPlainTrailingComma.values.length);
+ Expect.identical(EnumPlainTrailingComma.v1, EnumPlainTrailingComma.values[0]);
+ Expect.identical(EnumPlainTrailingComma.v2, EnumPlainTrailingComma.values[1]);
+ Expect.identical(EnumPlainTrailingComma.v3, EnumPlainTrailingComma.values[2]);
+
+ Expect.equals(3, EnumPlainNoSemicolon.values.length);
+ Expect.identical(EnumPlainNoSemicolon.v1, EnumPlainNoSemicolon.values[0]);
+ Expect.identical(EnumPlainNoSemicolon.v2, EnumPlainNoSemicolon.values[1]);
+ Expect.identical(EnumPlainNoSemicolon.v3, EnumPlainNoSemicolon.values[2]);
+ Expect.type<EnumNoSemicolon<num>>(EnumNoSemicolon.v1);
+
+ Expect.equals(3, EnumPlainSemicolon.values.length);
+ Expect.identical(EnumPlainSemicolon.v1, EnumPlainSemicolon.values[0]);
+ Expect.identical(EnumPlainSemicolon.v2, EnumPlainSemicolon.values[1]);
+ Expect.identical(EnumPlainSemicolon.v3, EnumPlainSemicolon.values[2]);
+
+ Expect.equals(3, EnumPlainTrailingCommaSemicolon.values.length);
+ Expect.identical(EnumPlainTrailingCommaSemicolon.v1,
+ EnumPlainTrailingCommaSemicolon.values[0]);
+ Expect.identical(EnumPlainTrailingCommaSemicolon.v2,
+ EnumPlainTrailingCommaSemicolon.values[1]);
+ Expect.identical(EnumPlainTrailingCommaSemicolon.v3,
+ EnumPlainTrailingCommaSemicolon.values[2]);
+
+ Expect.equals(6, EnumAll.values.length);
+ Expect.identical(EnumAll.v1, EnumAll.values[0]);
+ Expect.identical(EnumAll.v2, EnumAll.values[1]);
+ Expect.identical(EnumAll.v3, EnumAll.values[2]);
+ Expect.identical(EnumAll.v4, EnumAll.values[3]);
+ Expect.identical(EnumAll.v5, EnumAll.values[4]);
+ Expect.identical(EnumAll.v6, EnumAll.values[5]);
+
+ Expect.equals("unnamed", EnumAll.v1.constructor);
+ Expect.equals("unnamed", EnumAll.v2.constructor);
+ Expect.equals("unnamed", EnumAll.v3.constructor);
+ Expect.equals("named", EnumAll.v4.constructor);
+ Expect.equals("renamed", EnumAll.v5.constructor);
+ Expect.equals("unnamed", EnumAll.v6.constructor);
+
+ Expect.type<EnumAll<num, num>>(EnumAll.v1);
+ Expect.type<EnumAll<num, int>>(EnumAll.v2);
+ Expect.type<EnumAll<int, int>>(EnumAll.v3);
+ Expect.type<EnumAll<int, int>>(EnumAll.v4);
+ Expect.type<EnumAll<int, int>>(EnumAll.v5);
+ Expect.type<EnumAll<num, num>>(EnumAll.v6);
+
+ // Access static members.
+ Expect.identical(EnumAll.v3, EnumAll.sConst);
+ Expect.identical(EnumAll.v3, EnumAll.sFinal);
+
+ Expect.throws(() => EnumAll.sLateFinal);
+ EnumAll.sLateFinal = EnumAll.v1;
+ Expect.identical(EnumAll.v1, EnumAll.sLateFinal);
+ Expect.throws(() => EnumAll.sLateFinal = EnumAll.v1);
+
+ Expect.identical(EnumAll.v3, EnumAll.sFinalInit);
+
+ Expect.throws(() => EnumAll.sLate);
+ EnumAll.sLate = EnumAll.v1;
+ Expect.identical(EnumAll.v1, EnumAll.sLate);
+ EnumAll.sLate = EnumAll.v3;
+ Expect.identical(EnumAll.v3, EnumAll.sLate);
+ Expect.identical(EnumAll.v3, EnumAll.sLateVarInit);
+ Expect.isNull(EnumAll.sVar);
+ Expect.identical(EnumAll.v3, EnumAll.sVarInit);
+
+ Expect.identical(EnumAll.v3, EnumAll.staticGetSet);
+ EnumAll.staticGetSet = EnumAll.v5;
+ Expect.equals(42, EnumAll.staticMethod());
+
+ Expect.identical(EnumAll.v2, EnumAll<num, num>.factory(2));
+ Expect.identical(EnumAll.v2, EnumAll<num, num>.refactory(2));
+
+ // Access static members through typedef.
+ Expect.identical(EnumAll.v3, TypeDefAll.sConst);
+ Expect.identical(EnumAll.v3, TypeDefAll.sFinal);
+ Expect.identical(EnumAll.v1, TypedefAll.sLateFinal);
+ Expect.identical(EnumAll.v3, TypedefAll.sFinalInit);
+
+ Expect.identical(EnumAll.v3, TypeDefAll.staticGetSet);
+ TypeDefAll.staticGetSet = EnumAll.v5;
+ Expect.equals(42, TypeDefAll.staticMethod());
+
+ Expect.identical(EnumAll.v2, TypeDefAll.factory(2));
+ Expect.identical(EnumAll.v2, TypeDefAll.refactory(2));
+
+ // Access instance members.
+ Expect.equals(0, EnumAll.v1.instanceGetSet);
+ EnumAll.v1.instanceGetSet = 0.5;
+ Expect.equals(0, EnumAll.v1.instanceMethod());
+ Expect.identical(EnumAll.v1, EnumAll.v3 ^ EnumAll.v2);
+
+ Expect.equals("EnumAll.v1:EnumMixin<num>:ObjectMixin:this",
+ EnumAll.v1.thisAndSuper());
+
+ // Which can reference type parameters.
+ Expect.isTrue(EnumAll.v2.test(2)); // does `is T` with `T` being `int`.
+ Expect.isFalse(EnumAll.v2.test(2.5));
+
+ // Including `call`.
+ Expect.equals(42, EnumAll.v1<int>(42));
+ Expect.equals(42, EnumAll.v1(42));
+ // Also as tear-off.
+ Function eaf1 = EnumAll.v1;
+ Expect.type<T Function<T>(T)>(eaf1);
+ Function eaf2 = EnumAll.v1<String>;
+ Expect.type<String Function(String)>(eaf2);
+
+ // Instance members shadow extensions.
+ Expect.equals("not extension", EnumAll.v1.notExtension);
+ // But you can call extension members if there is no conflict.
+ Expect.equals("extension", EnumAll.v1.extension);
+
+ // The `index` and `toString` implementations are inherited from
+ // the `Enum` implementing superclass.
+ Expect.equals(3.5, StringIndexEnum.v1.index);
+ Expect.equals(3.5, StringIndexEnum.v2.index);
+ Expect.equals(0, StringIndexEnum.v1.realIndex);
+ Expect.equals(1, StringIndexEnum.v2.realIndex);
+ Expect.equals("FakeString", StringIndexEnum.v1.toString());
+ Expect.equals("FakeString", StringIndexEnum.v2.toString());
+ Expect.equals("StringIndexEnum.v1", StringIndexEnum.v1.realToString());
+ Expect.equals("StringIndexEnum.v2", StringIndexEnum.v2.realToString());
+
+ // Enum elements are always distinct, even if their state doesn't differ.
+ Expect.distinct(Canonical.v1, Canonical.v2, "Canonical - type only");
+ Expect.distinct(Canonical.v2, Canonical.v3, "Canonical - no difference");
+
+ // A `values` static constant is added only if *not* causing a conflict.
+ Expect.equals("StaticDeclaration", DeclaresValuesStatic.values);
+ Expect.equals("Declaration", DeclaresValues.v1.values);
+ Expect.equals("Mixin", InheritsValues.v1.values);
+ Expect.equals("NSM", ImplementsValues.v1.values);
+}
+
+// Original syntax still works, without semicolon after values.
+enum EnumPlain { v1, v2, v3 }
+
+// Also with trailing comma.
+enum EnumPlainTrailingComma {
+ v1,
+ v2,
+ v3,
+}
+
+// Also if using type parameters, mixins or interfaces.
+// It only matters whether there is something after the values.
+enum EnumNoSemicolon<T extends num> with ObjectMixin implements Interface {
+ v1, v2, v3
+}
+
+
+// Allows semicolon after values, even when not needed.
+// Without trailing comma.
+enum EnumPlainSemicolon { v1, v2, v3; }
+
+// With trailing comma.
+enum EnumPlainTrailingCommaSemicolon {
+ v1,
+ v2,
+ v3,
+ ;
+}
+
+// Full syntax, with every possible option.
+@EnumAll.v1
+@EnumAll.sConst
+enum EnumAll<S extends num, T extends num>
+ with GenericEnumMixin<T>, ObjectMixin
+ implements Interface, GenericInterface<S> {
+ @v1
+ @v2
+ v1,
+ @EnumAll.v2
+ v2(y: 2),
+ @sConst
+ v3<int, int>(y: 2),
+ v4.named(1, y: 2),
+ v5<int, int>.renamed(1, y: 2),
+ v6.new(),
+ ;
+
+ /// Static members.
+ ///
+ /// Any kind of static variable.
+ static const sConst = v3;
+ static final sFinal = v3;
+ static late final EnumAll sLateFinal;
+ static late final sLateFinalInit = v3;
+ static late EnumAll sLateVar;
+ static late var sLateVarInit = v3;
+ static EnumAll? sVar;
+ static EnumAll sVarInit = v3;
+ /// Static getters, setters and methods
+ static EnumAll<int, int> get staticGetSet => v3;
+ static set staticGetSet(EnumAll<int, int> _) {}
+ static int staticMethod() => 42;
+
+ // Constructors.
+ // Generative, non-redirecting, unnamed.
+ const EnumAll({T? y})
+ : constructor = "unnamed", this.x = 0 as S, y = y ?? (0 as T);
+ // Generative, non-redirecting, named.
+ const EnumAll.named(this.x, {T? y, String? constructor})
+ : constructor = constructor ?? "named", y = y ?? (0 as T);
+ // Generative, redirecting.
+ const EnumAll.renamed(S x, {T? y})
+ : this.named(x, y: y, constructor: "renamed");
+ // Factory, non-redirecting.
+ factory EnumAll.factory(int index) => values[index] as EnumAll<S, T>;
+ // Factory, redirecting (only to other factory constructor).
+ factory EnumAll.refactory(int index) = EnumAll<S, T>.factory;
+
+ // Cannot have factory constructors redirecting to generative constructors.
+ // (Nothing can refer to generative constructors except redirecting generative
+ // constructors and the implicit element creation expressions.)
+ // Cannot have const factory constructor, because they *must* redirect to
+ // generative constructors.
+ // Cannot have `super`-constuctor invocations in initializer lists.
+
+ // Instance members.
+
+ // Instance variables must be final and non-late because of const constructor.
+ final String constructor;
+ final S x;
+ final num y;
+
+ // Getters, setters, methods and operators.
+ S get instanceGetSet => x;
+ set instanceGetSet(S _) {}
+ S instanceMethod() => x;
+ EnumAll<num, num> operator ^(EnumAll<num, num> other) {
+ var newIndex = index ^ other.index;
+ if (newIndex > 4) newIndex = 4;
+ return values[newIndex]; // Can refer to `values`.
+ }
+
+ // Can have non-primitive equality and hashCode.
+ int get hashCode => index;
+ bool operator==(covariant EnumAll other) => index == other.index;
+
+ // Can access `this` and `super` in an instance method.
+ String thisAndSuper() => "${super.toString()}:${this.toString()}";
+
+ // Can be callable.
+ T call<T>(T value) => value;
+
+ // Instance members shadow extensions.
+ String get notExtension => "not extension";
+
+ String toString() => "this";
+}
+
+extension EnumAllExtension on EnumAll {
+ String get notExtension => Expect.fail("Unreachable");
+ String get extension => "extension":
+}
+
+typedef TypeDefAll = EnumAll<num, num>;
+
+// Can have no unnamed constructor.
+enum EnumNoUnnamedConstructor {
+ v1.named(1),
+ v2.named(2);
+
+ final int x;
+ EnumNoUnnamedConstructor.named(this.x);
+}
+
+// Can have an unnamed factory constructor.
+enum EnumFactoryUnnamedConstructor {
+ v1.named(1),
+ v2.named(2);
+
+ final int x;
+ factory EnumFactoryUnnamedConstructor() => v1;
+ EnumFactoryUnnamedConstructor.named(this.x);
+}
+
+// Elements which do not differ in public state are still different.
+// Ditto if only differing in type arguments.
+enum Canonical<T> {
+ v1<int>(1),
+ v2<num>(1),
+ v3<num>(1);
+ final T value;
+ Canonical(this.value);
+}
+
+// Both `toString` and `index` are inherited from superclass.
+enum StringIndexEnum {
+ v1, v2;
+ num get index => 3.5;
+ int get realIndex => super.index;
+ String toString() => "FakeString";
+ String realToString() => super.toString();
+}
+
+enum DeclaresValuesStatic {
+ v1;
+ static String get values => "StaticDeclaration";
+}
+
+enum DeclaresValues {
+ v1;
+ String get values => "Declaration";
+}
+
+enum InheritsValues with ValuesMixin {
+ v1;
+}
+
+enum ImplementsValues implements ValuesInterface {
+ v1;
+ dynamic noSuchMethod(i) => "NSM";
+}
+
+// --------------------------------------------------------------------
+// Helper declarations
+
+mixin ObjectMixin on Object {
+ String toString() => "${super.toString()}:ObjectMixin";
+}
+
+mixin EnumMixin on Enum {
+ String toString() => "${super.toString()}:EnumMixin";
+}
+
+mixin GenericObjectMixin<T> on Object {
+ bool test(Object o) => o is T;
+ String toString() => "${super.toString()}:ObjectMixin<$T>";
+}
+
+mixin GenericEnumMixin<T> on Enum {
+ bool test(Object o) => o is T;
+ String toString() => "${super.toString()}:EnumMixin<$T>";
+}
+
+abstract class Interface {
+
+}
+
+abstract class GenericInterface<T> {
+ // Implemented by mixins.
+ bool test(Object o);
+}
+
+abstract class ValuesInterface {
+ String get values;
+}
+
+mixin ValuesMixin {
+ String get values => "Mixin";
+}
diff --git a/tools/VERSION b/tools/VERSION
index 6c960b2..65a1042 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 16
PATCH 0
-PRERELEASE 159
+PRERELEASE 160
PRERELEASE_PATCH 0
\ No newline at end of file