Skip to content

Commit

Permalink
#2976. Add semantics tests (#2998)
Browse files Browse the repository at this point in the history
Add semantics tests
  • Loading branch information
sgrekhov authored Nov 28, 2024
1 parent 4c0cf74 commit 67eddf2
Show file tree
Hide file tree
Showing 9 changed files with 594 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ main() {
E e2 = .staticMethod();
Expect.equals("v2", e2.value);

E e3 = E.values[1];
E e3 = .values[1];
Expect.equals(E.v2, e3);
}
29 changes: 29 additions & 0 deletions LanguageFeatures/Static-access-shorthand/grammar_A03_t01.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) 2024, 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 We also add `.` to the tokens that an expression statement cannot
/// start with.
///
/// @description Checks that numerical literal like `.123` is still not an error
/// @author [email protected]
// SharedOptions=--enable-experiment=enum-shorthands

main() {
.123;

(.123);

var v1 = .123 + 1;

if (.123 > 0) {}

const half = .5;

final zero = 0 - .0;

.314e+1;

var pi = .214e+1 + 1;
}
97 changes: 97 additions & 0 deletions LanguageFeatures/Static-access-shorthand/semantics_A01_t01.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (c) 2024, 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 Dart semantics, static and dynamic, do not follow the grammar
/// precisely. For example, a static member invocation expression of the form
/// `C.id<T1>(e2)` is treated as an atomic entity for type inference (and
/// runtime semantics). It’s not a combination of doing a `C.id` tear-off, then
/// a `<T1>` instantiation and then an `(e2)` invocation. The context type of
/// that entire expression is used throughout the inference, where
/// `(e1.id<T1>)(e2)` has `(e1.id<T1>)` in a position where it has no context
/// type.
///
/// Because of that, the specification of the static and runtime semantics of
/// the new constructs needs to address all the forms `.id`, `.id<typeArgs>`,
/// `.id(args)`, `.id<typeArgs>(args)`, `.new` or `.new(args)`.
/// ...
/// The general rule is that any of the expression forms above, starting with
/// `.id`, are treated exactly as if they were prefixed by a fresh identifier
/// `X` which denotes an accessible type alias for the greatest closure of the
/// context type scheme of the following primary and selector chain.
///
/// @description Checks that the processing of the context type for shorthand
/// of the forms `.id`, `.id(args)` and `.id<typeArgs>(args)` includes a type
/// alias expansion.
/// @author [email protected]
// SharedOptions=--enable-experiment=enum-shorthands

import '../../Utils/expect.dart';

class C<T> {
T t;
C(this.t);

static C<int> get id1 => C(1);
static C<X> id2<X>(X x) => C<X>(x);
}

typedef CAlias<T> = C<T>;
typedef CInt = C<int>;

mixin M<T> on C<T> {
static M<int> get id1 => MC(1);
static M<X> id2<X>(X x) => MC<X>(x);
}

class MC<T> = C<T> with M<T>;

typedef MAlias<T> = M<T>;
typedef MInt = M<int>;

enum E<T> {
e1(1), e2("2");
final T t;
const E(this.t);

static E<int> get id1 => E.e1;
static E<String> id2() => E.e2;
}

typedef EAlias<T> = E<T>;
typedef EInt = E<int>;

extension type ET<T>(T t) {
static ET<int> get id1 => ET(1);
static ET<X> id2<X>(X x) => ET<X>(x);
}

typedef ETAlias<T> = ET<T>;
typedef ETInt = ET<int>;

main() {
CAlias<int> c1 = .id1;
Expect.equals(1, c1.t);

CInt c2 = .id2<int>(2);
Expect.equals(2, c2.t);

MAlias<int> m1 = .id1;
Expect.equals(1, m1.t);

MInt m2 = .id2<int>(2);
Expect.equals(2, m2.t);

EInt e1 = .id1;
Expect.equals(1, e1.t);

EAlias<String> e2 = .id2();
Expect.equals("2", e2.t);

ETAlias<int> et1 = .id1;
Expect.equals(1, et1.t);

ETInt et2 = .id2<int>(2);
Expect.equals(2, et2.t);
}
57 changes: 57 additions & 0 deletions LanguageFeatures/Static-access-shorthand/semantics_A01_t02.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) 2024, 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 Dart semantics, static and dynamic, do not follow the grammar
/// precisely. For example, a static member invocation expression of the form
/// `C.id<T1>(e2)` is treated as an atomic entity for type inference (and
/// runtime semantics). It’s not a combination of doing a `C.id` tear-off, then
/// a `<T1>` instantiation and then an `(e2)` invocation. The context type of
/// that entire expression is used throughout the inference, where
/// `(e1.id<T1>)(e2)` has `(e1.id<T1>)` in a position where it has no context
/// type.
///
/// Because of that, the specification of the static and runtime semantics of
/// the new constructs needs to address all the forms `.id`, `.id<typeArgs>`,
/// `.id(args)`, `.id<typeArgs>(args)`, `.new` or `.new(args)`.
/// ...
/// The general rule is that any of the expression forms above, starting with
/// `.id`, are treated exactly as if they were prefixed by a fresh identifier
/// `X` which denotes an accessible type alias for the greatest closure of the
/// context type scheme of the following primary and selector chain.
///
/// @description Checks that the processing of the context type for shorthand
/// of the forms `.id`, `.id(args)` and `.id<typeArgs>(args)` includes a type
/// alias expansion. Test unprefixed import.
/// @author [email protected]
// SharedOptions=--enable-experiment=enum-shorthands

import '../../Utils/expect.dart';
import 'shorthand_lib.dart';

main() {
CAlias<int> c1 = .id1;
Expect.equals(1, c1.t);

CInt c2 = .id2<int>(2);
Expect.equals(2, c2.t);

MAlias<int> m1 = .id1;
Expect.equals(1, m1.t);

MInt m2 = .id2<int>(2);
Expect.equals(2, m2.t);

EInt e1 = .id1;
Expect.equals(1, e1.t);

EAlias<String> e2 = .id2();
Expect.equals("2", e2.t);

ETAlias<int> et1 = .id1;
Expect.equals(1, et1.t);

ETInt et2 = .id2<int>(2);
Expect.equals(2, et2.t);
}
57 changes: 57 additions & 0 deletions LanguageFeatures/Static-access-shorthand/semantics_A01_t03.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) 2024, 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 Dart semantics, static and dynamic, do not follow the grammar
/// precisely. For example, a static member invocation expression of the form
/// `C.id<T1>(e2)` is treated as an atomic entity for type inference (and
/// runtime semantics). It’s not a combination of doing a `C.id` tear-off, then
/// a `<T1>` instantiation and then an `(e2)` invocation. The context type of
/// that entire expression is used throughout the inference, where
/// `(e1.id<T1>)(e2)` has `(e1.id<T1>)` in a position where it has no context
/// type.
///
/// Because of that, the specification of the static and runtime semantics of
/// the new constructs needs to address all the forms `.id`, `.id<typeArgs>`,
/// `.id(args)`, `.id<typeArgs>(args)`, `.new` or `.new(args)`.
/// ...
/// The general rule is that any of the expression forms above, starting with
/// `.id`, are treated exactly as if they were prefixed by a fresh identifier
/// `X` which denotes an accessible type alias for the greatest closure of the
/// context type scheme of the following primary and selector chain.
///
/// @description Checks that the processing of the context type for shorthand
/// of the forms `.id`, `.id(args)` and `.id<typeArgs>(args)` includes a type
/// alias expansion. Test prefixed import.
/// @author [email protected]
// SharedOptions=--enable-experiment=enum-shorthands

import '../../Utils/expect.dart';
import 'shorthand_lib.dart' as p;

main() {
p.CAlias<int> c1 = .id1;
Expect.equals(1, c1.t);

p.CInt c2 = .id2<int>(2);
Expect.equals(2, c2.t);

p.MAlias<int> m1 = .id1;
Expect.equals(1, m1.t);

p.MInt m2 = .id2<int>(2);
Expect.equals(2, m2.t);

p.EInt e1 = .id1;
Expect.equals(1, e1.t);

p.EAlias<String> e2 = .id2();
Expect.equals("2", e2.t);

p.ETAlias<int> et1 = .id1;
Expect.equals(1, et1.t);

p.ETInt et2 = .id2<int>(2);
Expect.equals(2, et2.t);
}
113 changes: 113 additions & 0 deletions LanguageFeatures/Static-access-shorthand/semantics_A01_t04.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright (c) 2024, 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 Dart semantics, static and dynamic, do not follow the grammar
/// precisely. For example, a static member invocation expression of the form
/// `C.id<T1>(e2)` is treated as an atomic entity for type inference (and
/// runtime semantics). It’s not a combination of doing a `C.id` tear-off, then
/// a `<T1>` instantiation and then an `(e2)` invocation. The context type of
/// that entire expression is used throughout the inference, where
/// `(e1.id<T1>)(e2)` has `(e1.id<T1>)` in a position where it has no context
/// type.
///
/// Because of that, the specification of the static and runtime semantics of
/// the new constructs needs to address all the forms `.id`, `.id<typeArgs>`,
/// `.id(args)`, `.id<typeArgs>(args)`, `.new` or `.new(args)`.
/// ...
/// The general rule is that any of the expression forms above, starting with
/// `.id`, are treated exactly as if they were prefixed by a fresh identifier
/// `X` which denotes an accessible type alias for the greatest closure of the
/// context type scheme of the following primary and selector chain.
///
/// @description Checks that the processing of the context type for shorthand
/// of the form `.id<typeArgs>` includes a type alias expansion.
/// @author [email protected]
// SharedOptions=--enable-experiment=enum-shorthands

import '../../Utils/expect.dart';

class C {
static X id<X>(X x) => x;
}
typedef CAlias = C;

mixin M {
static X id<X>(X x) => x;
}
typedef MAlias = M;
class MA = Object with M;

enum E {
e0;
static X id<X>(X x) => x;
}
typedef EAlias = E;

extension type ET(int _) implements Object {
static X id<X>(X x) => x;
}
typedef ETAlias = ET;

main() {
Object o = C();
if (o is C) {
o = .id<int>;
if (o is Function) {
Expect.equals(42, o(42));
}
}
o = C();
if (o is CAlias) {
o = .id<int>;
if (o is Function) {
Expect.equals(42, o(42));
}
}

o = MA();
if (o is M) {
o = .id<int>;
if (o is Function) {
Expect.equals(42, o(42));
}
}
o = MA();
if (o is MAlias) {
o = .id<int>;
if (o is Function) {
Expect.equals(42, o(42));
}
}

o = E.e0;
if (o is E) {
o = .id<int>;
if (o is Function) {
Expect.equals(42, o(42));
}
}
o = E.e0;
if (o is EAlias) {
o = .id<int>;
if (o is Function) {
Expect.equals(42, o(42));
}
}

o = ET(0);
if (o is ET) {
o = .id<int>;
if (o is Function) {
Expect.equals(42, o(42));
}
}
o = ET(1);
if (o is EAlias) {
o = .id<int>;
if (o is Function) {
Expect.equals(42, o(42));
}
}
}
Loading

0 comments on commit 67eddf2

Please sign in to comment.