diff --git a/LanguageFeatures/Static-access-shorthand/non_ambiguity_A01_t01.dart b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A01_t01.dart new file mode 100644 index 0000000000..2ece784292 --- /dev/null +++ b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A01_t01.dart @@ -0,0 +1,36 @@ +// Copyright (c) 2025, 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. + +/// @assertion A postfix expression expression can follow a `?` in a conditional +/// expression, as in `{e1 ? . id : e2}`. This is not ambiguous with `e1?.id` +/// since we parse `?.` as a single token, and will keep doing so. It does mean +/// that `{e1?.id:e2}` and `{e1? .id:e2}` will now both be valid and have +/// different meanings, where the existing grammar didn’t allow the `?` token to +/// be followed by `.` anywhere. +/// +/// @description Checks that `{e1?.id:e2}` is parsed like a map literal. +/// @author sgrekhov22@gmail.com + +// SharedOptions=--enable-experiment=enum-shorthands + +import '../../Utils/expect.dart'; + +class C { + static C id = C(); +} + +extension on bool { + int get id => 42; +} + +main() { + bool e1 = 2 > 1; // true + var e2 = "value"; + Object o = C(); + if (o is C) { + o = {e1?.id: e2}; // ignore: invalid_null_aware_operator + Expect.isTrue(o is Map); + Expect.mapEquals({42: "value"}, o); + } +} diff --git a/LanguageFeatures/Static-access-shorthand/non_ambiguity_A01_t02.dart b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A01_t02.dart new file mode 100644 index 0000000000..1add0c9e20 --- /dev/null +++ b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A01_t02.dart @@ -0,0 +1,38 @@ +// Copyright (c) 2025, 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. + +/// @assertion A postfix expression expression can follow a `?` in a conditional +/// expression, as in `{e1 ? . id : e2}`. This is not ambiguous with `e1?.id` +/// since we parse `?.` as a single token, and will keep doing so. It does mean +/// that `{e1?.id:e2}` and `{e1? .id:e2}` will now both be valid and have +/// different meanings, where the existing grammar didn’t allow the `?` token to +/// be followed by `.` anywhere. +/// +/// @description Checks that `{e1? .id:e2}` is parsed like a set literal. +/// @author sgrekhov22@gmail.com + +// SharedOptions=--enable-experiment=enum-shorthands + +import '../../Utils/expect.dart'; + +class C { + int value; + C(this.value); + static C id = C(0); +} + +extension on bool { + int get id => 42; +} + +main() { + bool e1 = 2 > 1; // true + var e2 = "value"; + Object o = {C(1)}; + if (o is Set) { + o = {e1? .id: e2}; + Expect.isTrue(o is Set); // ignore: unnecessary_type_check + Expect.setEquals({C.id}, o as Set); + } +} diff --git a/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t01.dart b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t01.dart new file mode 100644 index 0000000000..16a3294d90 --- /dev/null +++ b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t01.dart @@ -0,0 +1,101 @@ +// Copyright (c) 2025, 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. + +/// @assertion A postfix expression expression can follow a `?` in a conditional +/// expression, as in `{e1 ? . id : e2}`. This is not ambiguous with `e1?.id` +/// since we parse `?.` as a single token, and will keep doing so. It does mean +/// that `{e1?.id:e2}` and `{e1? .id:e2}` will now both be valid and have +/// different meanings, where the existing grammar didn’t allow the `?` token to +/// be followed by `.` anywhere. +/// +/// @description Checks that for null-aware elements `? .id` is parsed as +/// `? C.id`. +/// @author sgrekhov22@gmail.com + +// SharedOptions=--enable-experiment=enum-shorthands,null-aware-elements + +import '../../Utils/expect.dart'; + +class C { + int value; + C(this.value); + C.id(this.value); + static C? one = C(1); + static C? get two => C(2); + static C? three() => C(3); + + @override + bool operator ==(Object other) { + if (other is C) { + return value == other.value; + } + return false; + } + + @override + int get hashCode => value.hashCode; +} + +mixin M on C { + static M? one = MC(1); + static M? get two => MC(2); + static M? three() => MC(3); +} + +class MC = C with M; + +enum E { + e1, e2, e3; + static E? one = E.e1; + static E? get two => E.e2; + static E? three() => E.e3; +} + +extension type ET(int value) { + ET.id(this.value); + static ET? one = ET(1); + static ET? get two => ET(2); + static ET? three() => ET(3); +} + +main() { + var l1 = [ + ? .id(0), + ? .new(0), + ? .one, + ? .two, + ? .three() + ]; + Expect.listEquals([C(0), C(0), C(1), C(2), C(3)], l1); + + var s = { + ? .one, + ? .two, + ? .three() + }; + Expect.setEquals({MC(1), MC(2), MC(3)}, s); + + var m1 = { + "key0": ? .e1, + "key1": ? .one, + "key2": ? .two, + "key3": ? .three() + }; + Expect.mapEquals({"key0": E.e1, "key1": E.e1, "key2": E.e2, "key3":E.e3}, m1); + + var m2 = { + ? .id(-1): "value0", + ? .new(0): "value1", + ? .one: "value2", + ? .two: "value3", + ? .three(): "value4" + }; + Expect.mapEquals({ + ET(-1): "value0", + ET(0): "value1", + ET(1): "value2", + ET(2): "value3", + ET(3): "value4" + }, m2); +} diff --git a/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t02.dart b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t02.dart new file mode 100644 index 0000000000..eb83aa23ac --- /dev/null +++ b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t02.dart @@ -0,0 +1,220 @@ +// Copyright (c) 2025, 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. + +/// @assertion A postfix expression expression can follow a `?` in a conditional +/// expression, as in `{e1 ? . id : e2}`. This is not ambiguous with `e1?.id` +/// since we parse `?.` as a single token, and will keep doing so. It does mean +/// that `{e1?.id:e2}` and `{e1? .id:e2}` will now both be valid and have +/// different meanings, where the existing grammar didn’t allow the `?` token to +/// be followed by `.` anywhere. +/// +/// @description Checks that `?.id` is parsed as `?. id` which is a compile-time +/// error. +/// @author sgrekhov22@gmail.com + +// SharedOptions=--enable-experiment=enum-shorthands,null-aware-elements + +class C { + int value; + C(this.value); + C.id(this.value); + static C? one = C(1); + static C? get two => C(2); + static C? three() => C(3); + + @override + bool operator ==(Object other) { + if (other is C) { + return value == other.value; + } + return false; + } + + @override + int get hashCode => value.hashCode; +} + +mixin M on C { + static M? one = MC(1); + static M? get two => MC(2); + static M? three() => MC(3); +} + +class MC = C with M; + +enum E { + e1, e2, e3; + static E? one = E.e1; + static E? get two => E.e2; + static E? three() => E.e3; +} + +extension type ET(int value) { + ET.id(this.value); + static ET? one = ET(1); + static ET? get two => ET(2); + static ET? three() => ET(3); +} + +void testConstructors() { + var l = [ + ?.id(0) +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + ]; + + var s = { + ?.new(0), +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + }; + + var m1 = { + "key": ?.id(0) +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + ?.new(0): "value1", +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + }; + + var m2 = { + ?.new(0): "value" +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + }; +} + +void testVariables() { + var l = [ + ?.one +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + ]; + + var s = { + ?.one +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + }; + + var m1 = { + "key": ?.one, +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + }; + + var m2 = { + ?.one: "value" +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + }; +} + +void testGetters() { + var l = [ + ?.two +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + ]; + + var s = { + ?.two +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + }; + + var m1 = { + "key": ?.two, +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + }; + + var m2 = { + ?.two: "value" +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + }; +} + +void testMethods() { + var l = [ + ?.three() +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + ]; + + var s = { + ?.three() +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + }; + + var m1 = { + "key": ?.three(), +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + }; + + var m2 = { + ?.three(): "value" +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + }; +} + +void testEnumValues() { + var l = [ + ?.e0 +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + ]; + + var s = { + ?.e0 +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + }; + + var m1 = { + "key": ?.e0, +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + }; + + var m2 = { + ?.e0: "value" +// ^^ +// [analyzer] unspecified +// [cfe] unspecified + }; +} + +main() { + testConstructors(); + testVariables(); + testGetters(); + testMetods(); + testEnumValues(); +} diff --git a/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t03.dart b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t03.dart new file mode 100644 index 0000000000..3135aa3b5e --- /dev/null +++ b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t03.dart @@ -0,0 +1,88 @@ +// Copyright (c) 2025, 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. + +/// @assertion A postfix expression expression can follow a `?` in a conditional +/// expression, as in `{e1 ? . id : e2}`. This is not ambiguous with `e1?.id` +/// since we parse `?.` as a single token, and will keep doing so. It does mean +/// that `{e1?.id:e2}` and `{e1? .id:e2}` will now both be valid and have +/// different meanings, where the existing grammar didn’t allow the `?` token to +/// be followed by `.` anywhere. +/// +/// @description Checks that spread collections `....id` is parsed as +/// `... .id` +/// @author sgrekhov22@gmail.com + +// SharedOptions=--enable-experiment=enum-shorthands + +import '../../Utils/expect.dart'; + +class C { + int value; + C(this.value); + static List one = [C(1)]; + static List get two => [C(2)]; + static List three() => [C(3)]; + + @override + bool operator ==(Object other) { + if (other is C) { + return value == other.value; + } + return false; + } + + @override + int get hashCode => value.hashCode; +} + +mixin M on C { + static Set one = {MC(1)}; + static Set get two => {MC(2)}; + static Set three() => {MC(3)}; +} + +class MC = C with M; + +enum E { + e1, e2, e3; + static Map one = {"key1": E.e1}; + static Map get two => {"key2": E.e2}; + static Map three() => {"key3": E.e3}; +} + +extension type ET(int value) { + static List one = [ET(1)]; + static List get two => [ET(2)]; + static List three() => [ET(3)]; +} + +main() { + var l1 = [ + ....one, + ....two, + ....three() + ]; + Expect.listEquals([C(1), C(2), C(3)] ,l1); + + var s = { + ....one, + ....two, + ....three() + }; + Expect.setEquals({MC(1), MC(2), MC(3)} ,s); + + var m = { + ....one, + ....two, + ....three() + }; + Expect.mapEquals({"key1": E.e1, "key2": E.e2, "key3":E.e3} ,m); + + var l2 = [ + ....one, + ....two, + ....three() + ]; + Expect.listEquals([ET(1), ET(2), ET(3)] ,l2); +} diff --git a/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t04.dart b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t04.dart new file mode 100644 index 0000000000..fe3ca8d1f6 --- /dev/null +++ b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t04.dart @@ -0,0 +1,88 @@ +// Copyright (c) 2025, 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. + +/// @assertion A postfix expression expression can follow a `?` in a conditional +/// expression, as in `{e1 ? . id : e2}`. This is not ambiguous with `e1?.id` +/// since we parse `?.` as a single token, and will keep doing so. It does mean +/// that `{e1?.id:e2}` and `{e1? .id:e2}` will now both be valid and have +/// different meanings, where the existing grammar didn’t allow the `?` token to +/// be followed by `.` anywhere. +/// +/// @description Checks that spread collections `... .id` is treated as +/// `... C.id` +/// @author sgrekhov22@gmail.com + +// SharedOptions=--enable-experiment=enum-shorthands + +import '../../Utils/expect.dart'; + +class C { + int value; + C(this.value); + static List one = [C(1)]; + static List get two => [C(2)]; + static List three() => [C(3)]; + + @override + bool operator ==(Object other) { + if (other is C) { + return value == other.value; + } + return false; + } + + @override + int get hashCode => value.hashCode; +} + +mixin M on C { + static Set one = {MC(1)}; + static Set get two => {MC(2)}; + static Set three() => {MC(3)}; +} + +class MC = C with M; + +enum E { + e1, e2, e3; + static Map one = {"key1": E.e1}; + static Map get two => {"key2": E.e2}; + static Map three() => {"key3": E.e3}; +} + +extension type ET(int value) { + static List one = [ET(1)]; + static List get two => [ET(2)]; + static List three() => [ET(3)]; +} + +main() { + var l1 = [ + ... .one, + ... .two, + ... .three() + ]; + Expect.listEquals([C(1), C(2), C(3)] ,l1); + + var s = { + ... .one, + ... .two, + ... .three() + }; + Expect.setEquals({MC(1), MC(2), MC(3)} ,s); + + var m = { + ... .one, + ... .two, + ... .three() + }; + Expect.mapEquals({"key1": E.e1, "key2": E.e2, "key3":E.e3} ,m); + + var l2 = [ + ... .one, + ... .two, + ... .three() + ]; + Expect.listEquals([ET(1), ET(2), ET(3)] ,l2); +} diff --git a/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t05.dart b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t05.dart new file mode 100644 index 0000000000..cb3d8559ce --- /dev/null +++ b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t05.dart @@ -0,0 +1,88 @@ +// Copyright (c) 2025, 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. + +/// @assertion A postfix expression expression can follow a `?` in a conditional +/// expression, as in `{e1 ? . id : e2}`. This is not ambiguous with `e1?.id` +/// since we parse `?.` as a single token, and will keep doing so. It does mean +/// that `{e1?.id:e2}` and `{e1? .id:e2}` will now both be valid and have +/// different meanings, where the existing grammar didn’t allow the `?` token to +/// be followed by `.` anywhere. +/// +/// @description Checks that spread collections `...? .id` is parsed as +/// `...? .id` +/// @author sgrekhov22@gmail.com + +// SharedOptions=--enable-experiment=enum-shorthands + +import '../../Utils/expect.dart'; + +class C { + int value; + C(this.value); + static List? one = [C(1)]; + static List? get two => [C(2)]; + static List? three() => null; + + @override + bool operator ==(Object other) { + if (other is C) { + return value == other.value; + } + return false; + } + + @override + int get hashCode => value.hashCode; +} + +mixin M on C { + static Set? one = {MC(1)}; + static Set? get two => null; + static Set? three() => {MC(3)}; +} + +class MC = C with M; + +enum E { + e1, e2, e3; + static Map? one = null; + static Map? get two => {"key2": E.e2}; + static Map? three() => {"key3": E.e3}; +} + +extension type ET(int value) { + static List? one = [ET(1)]; + static List? get two => [ET(2)]; + static List? three() => null; +} + +main() { + var l1 = [ + ...? .one, + ...? .two, + ...? .three() + ]; + Expect.listEquals([C(1), C(2)] ,l1); + + var s = { + ...? .one, + ...? .two, + ...? .three() + }; + Expect.setEquals({MC(1), MC(3)} ,s); + + var m = { + ...? .one, + ...? .two, + ...? .three() + }; + Expect.mapEquals({"key2": E.e2, "key3":E.e3} ,m); + + var l2 = [ + ...? .one, + ...? .two, + ...? .three() + ]; + Expect.listEquals([ET(1), ET(2)] ,l2); +} diff --git a/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t06.dart b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t06.dart new file mode 100644 index 0000000000..cecb4959c5 --- /dev/null +++ b/LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t06.dart @@ -0,0 +1,88 @@ +// Copyright (c) 2025, 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. + +/// @assertion A postfix expression expression can follow a `?` in a conditional +/// expression, as in `{e1 ? . id : e2}`. This is not ambiguous with `e1?.id` +/// since we parse `?.` as a single token, and will keep doing so. It does mean +/// that `{e1?.id:e2}` and `{e1? .id:e2}` will now both be valid and have +/// different meanings, where the existing grammar didn’t allow the `?` token to +/// be followed by `.` anywhere. +/// +/// @description Checks that spread collections `...?.id` is treated as +/// `...? C.id` +/// @author sgrekhov22@gmail.com + +// SharedOptions=--enable-experiment=enum-shorthands + +import '../../Utils/expect.dart'; + +class C { + int value; + C(this.value); + static List? one = [C(1)]; + static List? get two => [C(2)]; + static List? three() => null; + + @override + bool operator ==(Object other) { + if (other is C) { + return value == other.value; + } + return false; + } + + @override + int get hashCode => value.hashCode; +} + +mixin M on C { + static Set? one = {MC(1)}; + static Set? get two => null; + static Set? three() => {MC(3)}; +} + +class MC = C with M; + +enum E { + e1, e2, e3; + static Map? one = null; + static Map? get two => {"key2": E.e2}; + static Map? three() => {"key3": E.e3}; +} + +extension type ET(int value) { + static List? one = [ET(1)]; + static List? get two => [ET(2)]; + static List? three() => null; +} + +main() { + var l1 = [ + ...?.one, + ...?.two, + ...?.three() + ]; + Expect.listEquals([C(1), C(2)] ,l1); + + var s = { + ...?.one, + ...?.two, + ...?.three() + }; + Expect.setEquals({MC(1), MC(3)} ,s); + + var m = { + ...?.one, + ...?.two, + ...?.three() + }; + Expect.mapEquals({"key2": E.e2, "key3":E.e3} ,m); + + var l2 = [ + ...?.one, + ...?.two, + ...?.three() + ]; + Expect.listEquals([ET(1), ET(2)] ,l2); +}