Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2976. Add non-ambiguity tests #3034

Merged
merged 2 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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 [email protected]

// 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);
}
}
Original file line number Diff line number Diff line change
@@ -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 [email protected]

// 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>{C(1)};
if (o is Set<C>) {
o = {e1? .id: e2};
Expect.isTrue(o is Set); // ignore: unnecessary_type_check
Expect.setEquals({C.id}, o as Set);
}
}
101 changes: 101 additions & 0 deletions LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t01.dart
Original file line number Diff line number Diff line change
@@ -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 [email protected]

// 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 = <C>[
? .id(0),
? .new(0),
? .one,
? .two,
? .three()
];
Expect.listEquals([C(0), C(0), C(1), C(2), C(3)], l1);

var s = <M>{
? .one,
? .two,
? .three()
};
Expect.setEquals({MC(1), MC(2), MC(3)}, s);

var m1 = <String, E>{
"key0": ? .e1,
"key1": ? .one,
"key2": ? .two,
"key3": ? .three()
};
eernstg marked this conversation as resolved.
Show resolved Hide resolved
Expect.mapEquals({"key0": E.e1, "key1": E.e1, "key2": E.e2, "key3":E.e3}, m1);

var m2 = <ET, String> {
? .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);
}
220 changes: 220 additions & 0 deletions LanguageFeatures/Static-access-shorthand/non_ambiguity_A02_t02.dart
Original file line number Diff line number Diff line change
@@ -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 [email protected]

// 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 = <C>[
?.id(0)
// ^^
// [analyzer] unspecified
// [cfe] unspecified
];

var s = <C>{
?.new(0),
// ^^
// [analyzer] unspecified
// [cfe] unspecified
};

var m1 = <String, ET> {
"key": ?.id(0)
// ^^
// [analyzer] unspecified
// [cfe] unspecified
?.new(0): "value1",
// ^^
// [analyzer] unspecified
// [cfe] unspecified
};

var m2 = <ET, String> {
?.new(0): "value"
// ^^
// [analyzer] unspecified
// [cfe] unspecified
};
}

void testVariables() {
var l = <C>[
?.one
// ^^
// [analyzer] unspecified
// [cfe] unspecified
];

var s = <M>{
?.one
// ^^
// [analyzer] unspecified
// [cfe] unspecified
};

var m1 = <String, E>{
"key": ?.one,
// ^^
// [analyzer] unspecified
// [cfe] unspecified
};

var m2 = <ET, String> {
?.one: "value"
// ^^
// [analyzer] unspecified
// [cfe] unspecified
};
}

void testGetters() {
var l = <C>[
?.two
// ^^
// [analyzer] unspecified
// [cfe] unspecified
];

var s = <M>{
?.two
// ^^
// [analyzer] unspecified
// [cfe] unspecified
};

var m1 = <String, E>{
"key": ?.two,
// ^^
// [analyzer] unspecified
// [cfe] unspecified
};

var m2 = <ET, String> {
?.two: "value"
// ^^
// [analyzer] unspecified
// [cfe] unspecified
};
eernstg marked this conversation as resolved.
Show resolved Hide resolved
}

void testMethods() {
var l = <C>[
?.three()
// ^^
// [analyzer] unspecified
// [cfe] unspecified
];

var s = <M>{
?.three()
// ^^
// [analyzer] unspecified
// [cfe] unspecified
};

var m1 = <String, E>{
"key": ?.three(),
// ^^
// [analyzer] unspecified
// [cfe] unspecified
};

var m2 = <ET, String> {
?.three(): "value"
// ^^
// [analyzer] unspecified
// [cfe] unspecified
};
}

void testEnumValues() {
var l = <E>[
?.e0
// ^^
// [analyzer] unspecified
// [cfe] unspecified
];

var s = <E>{
?.e0
// ^^
// [analyzer] unspecified
// [cfe] unspecified
};

var m1 = <String, E>{
"key": ?.e0,
// ^^
// [analyzer] unspecified
// [cfe] unspecified
};

var m2 = <E, String> {
?.e0: "value"
// ^^
// [analyzer] unspecified
// [cfe] unspecified
};
}

main() {
testConstructors();
testVariables();
testGetters();
testMetods();
testEnumValues();
}
eernstg marked this conversation as resolved.
Show resolved Hide resolved
Loading
Loading