[tests] Language tests for sealed classes.
Basic language tests that test usage in and out of library for sealed classes.
More tests will come later.
Change-Id: I298484d214a5fe7602d14ab1d7915c733ef00c34
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/265660
Reviewed-by: Bob Nystrom <rnystrom@google.com>
Reviewed-by: Leaf Petersen <leafp@google.com>
diff --git a/tests/language/sealed_class/sealed_class_as_mixin_error_test.dart b/tests/language/sealed_class/sealed_class_as_mixin_error_test.dart
new file mode 100644
index 0000000..db037d1
--- /dev/null
+++ b/tests/language/sealed_class/sealed_class_as_mixin_error_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2022, 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=sealed-class
+
+// Error when attempting to mix in a sealed class outside of library.
+
+import 'sealed_class_as_mixin_lib.dart';
+
+abstract class OutsideA with SealedClass {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+class OutsideB with SealedClass {
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+ @override
+ int foo = 2;
+
+ @override
+ int bar(int value) => value;
+}
+
+abstract class OutsideC = Object with SealedClass;
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
diff --git a/tests/language/sealed_class/sealed_class_as_mixin_lib.dart b/tests/language/sealed_class/sealed_class_as_mixin_lib.dart
new file mode 100644
index 0000000..f2f63a3
--- /dev/null
+++ b/tests/language/sealed_class/sealed_class_as_mixin_lib.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2022, 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=sealed-class
+
+sealed class SealedClass {
+ int nonAbstractFoo = 0;
+ abstract int foo;
+ int nonAbstractBar(int value) => value + 100;
+ int bar(int value);
+}
+
+abstract class A with SealedClass {}
+
+class AImpl extends A {
+ @override
+ int foo = 1;
+
+ @override
+ int bar(int value) => value + 1;
+}
+
+class B with SealedClass {
+ @override
+ int nonAbstractFoo = 100;
+
+ @override
+ int foo = 2;
+
+ @override
+ int bar(int value) => value;
+}
+
+abstract class C = Object with SealedClass;
+
+class CImpl extends C {
+ @override
+ int foo = 3;
+
+ @override
+ int bar(int value) => value - 1;
+}
diff --git a/tests/language/sealed_class/sealed_class_as_mixin_test.dart b/tests/language/sealed_class/sealed_class_as_mixin_test.dart
new file mode 100644
index 0000000..04b22ac
--- /dev/null
+++ b/tests/language/sealed_class/sealed_class_as_mixin_test.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2022, 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=sealed-class
+
+// Allow sealed classes to be mixed in by multiple classes in the same library.
+// Additionally, allow their subclasses/subtypes to be used freely.
+
+import "package:expect/expect.dart";
+import 'sealed_class_as_mixin_lib.dart';
+
+class AExtends extends A {
+ @override
+ int foo = 0;
+
+ @override
+ int bar(int value) => value;
+}
+
+class AImplements implements A {
+ @override
+ int nonAbstractFoo = 0;
+
+ @override
+ int foo = 0;
+
+ @override
+ int bar(int value) => value;
+
+ @override
+ int nonAbstractBar(int value) => value;
+}
+
+class CMixin with C {
+ @override
+ int foo = 0;
+
+ @override
+ int bar(int value) => value;
+}
+
+main() {
+ A a = AImpl();
+ Expect.equals(0, a.nonAbstractFoo);
+ Expect.equals(1, a.foo);
+ Expect.equals(3, a.bar(2));
+ Expect.equals(100, a.nonAbstractBar(0));
+
+ var b = B();
+ Expect.equals(100, b.nonAbstractFoo);
+ Expect.equals(2, b.foo);
+ Expect.equals(2, b.bar(2));
+ Expect.equals(100, b.nonAbstractBar(0));
+
+ C c = CImpl();
+ Expect.equals(0, c.nonAbstractFoo);
+ Expect.equals(3, c.foo);
+ Expect.equals(1, c.bar(2));
+ Expect.equals(100, c.nonAbstractBar(0));
+
+ var aExtends = AExtends();
+ Expect.equals(0, aExtends.nonAbstractFoo);
+ Expect.equals(0, aExtends.foo);
+ Expect.equals(0, aExtends.bar(0));
+ Expect.equals(100, aExtends.nonAbstractBar(0));
+
+ var aImplements = AImplements();
+ Expect.equals(0, aImplements.nonAbstractFoo);
+ Expect.equals(0, aImplements.foo);
+ Expect.equals(0, aImplements.bar(0));
+ Expect.equals(0, aImplements.nonAbstractBar(0));
+
+ var cMixin = CMixin();
+ Expect.equals(0, cMixin.nonAbstractFoo);
+ Expect.equals(0, cMixin.foo);
+ Expect.equals(0, cMixin.bar(0));
+ Expect.equals(100, cMixin.nonAbstractBar(0));
+}
diff --git a/tests/language/sealed_class/sealed_class_extend_error_test.dart b/tests/language/sealed_class/sealed_class_extend_error_test.dart
new file mode 100644
index 0000000..f69efd1
--- /dev/null
+++ b/tests/language/sealed_class/sealed_class_extend_error_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2022, 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=sealed-class
+
+// Error when attempting to extend a sealed class outside of its library.
+
+import 'sealed_class_extend_lib.dart';
+
+abstract class OutsideA extends SealedClass {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+class OutsideB extends SealedClass {
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+ @override
+ int foo = 2;
+
+ @override
+ int bar(int value) => value;
+}
diff --git a/tests/language/sealed_class/sealed_class_extend_lib.dart b/tests/language/sealed_class/sealed_class_extend_lib.dart
new file mode 100644
index 0000000..cc00100
--- /dev/null
+++ b/tests/language/sealed_class/sealed_class_extend_lib.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2022, 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=sealed-class
+
+sealed class SealedClass {
+ int nonAbstractFoo = 0;
+ abstract int foo;
+ int nonAbstractBar(int value) => value + 100;
+ int bar(int value);
+}
+
+abstract class A extends SealedClass {}
+
+class AImpl extends A {
+ @override
+ int foo = 1;
+
+ @override
+ int bar(int value) => value + 1;
+}
+
+class B extends SealedClass {
+ @override
+ int nonAbstractFoo = 100;
+
+ @override
+ int foo = 2;
+
+ @override
+ int bar(int value) => value;
+}
diff --git a/tests/language/sealed_class/sealed_class_extend_test.dart b/tests/language/sealed_class/sealed_class_extend_test.dart
new file mode 100644
index 0000000..587c379
--- /dev/null
+++ b/tests/language/sealed_class/sealed_class_extend_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2022, 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=sealed-class
+
+// Allow sealed classes to be extended by multiple classes in the same library.
+// Additionally, allow their subclasses/subtypes to be used freely.
+
+import "package:expect/expect.dart";
+import 'sealed_class_extend_lib.dart';
+
+class AExtends extends A {
+ @override
+ int foo = 0;
+
+ @override
+ int bar(int value) => value;
+}
+
+class AImplements implements A {
+ @override
+ int nonAbstractFoo = 0;
+
+ @override
+ int foo = 0;
+
+ @override
+ int bar(int value) => value;
+
+ @override
+ int nonAbstractBar(int value) => value;
+}
+
+main() {
+ A a = AImpl();
+ Expect.equals(0, a.nonAbstractFoo);
+ Expect.equals(1, a.foo);
+ Expect.equals(3, a.bar(2));
+ Expect.equals(100, a.nonAbstractBar(0));
+
+ var b = B();
+ Expect.equals(100, b.nonAbstractFoo);
+ Expect.equals(2, b.foo);
+ Expect.equals(2, b.bar(2));
+ Expect.equals(100, b.nonAbstractBar(0));
+
+ var aExtends = AExtends();
+ Expect.equals(0, aExtends.nonAbstractFoo);
+ Expect.equals(0, aExtends.foo);
+ Expect.equals(0, aExtends.bar(0));
+ Expect.equals(100, aExtends.nonAbstractBar(0));
+
+ var aImplements = AImplements();
+ Expect.equals(0, aImplements.nonAbstractFoo);
+ Expect.equals(0, aImplements.foo);
+ Expect.equals(0, aImplements.bar(0));
+ Expect.equals(0, aImplements.nonAbstractBar(0));
+}
diff --git a/tests/language/sealed_class/sealed_class_implement_error_test.dart b/tests/language/sealed_class/sealed_class_implement_error_test.dart
new file mode 100644
index 0000000..62c3c30
--- /dev/null
+++ b/tests/language/sealed_class/sealed_class_implement_error_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2022, 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=sealed-class
+
+// Error when attempting to implement a sealed class outside of its library.
+
+import "sealed_class_implement_lib.dart";
+
+abstract class OutsideA implements SealedClass {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+class OutsideB implements SealedClass {
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+ @override
+ int nonAbstractFoo = 2;
+
+ @override
+ int foo = 2;
+
+ @override
+ int nonAbstractBar(int value) => value;
+
+ @override
+ int bar(int value) => value;
+}
diff --git a/tests/language/sealed_class/sealed_class_implement_lib.dart b/tests/language/sealed_class/sealed_class_implement_lib.dart
new file mode 100644
index 0000000..b3d64c2
--- /dev/null
+++ b/tests/language/sealed_class/sealed_class_implement_lib.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2022, 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=sealed-class
+
+sealed class SealedClass {
+ int nonAbstractFoo = 0;
+ abstract int foo;
+ int nonAbstractBar(int value) => value + 100;
+ int bar(int value);
+}
+
+abstract class A implements SealedClass {}
+
+class AImpl implements A {
+ @override
+ int nonAbstractFoo = 0;
+
+ @override
+ int foo = 1;
+
+ @override
+ int nonAbstractBar(int value) => value + 100;
+
+ @override
+ int bar(int value) => value + 1;
+}
+
+class B implements SealedClass {
+ @override
+ int nonAbstractFoo = 100;
+
+ @override
+ int foo = 2;
+
+ @override
+ int nonAbstractBar(int value) => value + 100;
+
+ @override
+ int bar(int value) => value;
+}
diff --git a/tests/language/sealed_class/sealed_class_implement_test.dart b/tests/language/sealed_class/sealed_class_implement_test.dart
new file mode 100644
index 0000000..4aaeb12
--- /dev/null
+++ b/tests/language/sealed_class/sealed_class_implement_test.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2022, 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=sealed-class
+
+// Allow sealed classes to be implemented by multiple classes in the same
+// library.
+// Additionally, allow their subclasses/subtypes to be used freely.
+
+import "package:expect/expect.dart";
+import 'sealed_class_implement_lib.dart';
+
+class AExtends extends A {
+ @override
+ int nonAbstractFoo = 0;
+
+ @override
+ int foo = 0;
+
+ @override
+ int bar(int value) => value;
+
+ @override
+ int nonAbstractBar(int value) => value;
+}
+
+class AImplements implements A {
+ @override
+ int nonAbstractFoo = 0;
+
+ @override
+ int foo = 0;
+
+ @override
+ int bar(int value) => value;
+
+ @override
+ int nonAbstractBar(int value) => value;
+}
+
+main() {
+ A a = AImpl();
+ Expect.equals(0, a.nonAbstractFoo);
+ Expect.equals(1, a.foo);
+ Expect.equals(3, a.bar(2));
+ Expect.equals(100, a.nonAbstractBar(0));
+
+ var b = B();
+ Expect.equals(100, b.nonAbstractFoo);
+ Expect.equals(2, b.foo);
+ Expect.equals(2, b.bar(2));
+ Expect.equals(100, b.nonAbstractBar(0));
+
+ var aExtends = AExtends();
+ Expect.equals(0, aExtends.nonAbstractFoo);
+ Expect.equals(0, aExtends.foo);
+ Expect.equals(0, aExtends.bar(0));
+ Expect.equals(0, aExtends.nonAbstractBar(0));
+
+ var aImplements = AImplements();
+ Expect.equals(0, aImplements.nonAbstractFoo);
+ Expect.equals(0, aImplements.foo);
+ Expect.equals(0, aImplements.bar(0));
+ Expect.equals(0, aImplements.nonAbstractBar(0));
+}
diff --git a/tests/language/sealed_class/sealed_class_syntax_error_test.dart b/tests/language/sealed_class/sealed_class_syntax_error_test.dart
new file mode 100644
index 0000000..5584ba1
--- /dev/null
+++ b/tests/language/sealed_class/sealed_class_syntax_error_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2022, 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=sealed-class
+
+// Syntax errors such as using `sealed` keyword in a place other than a class or
+// mixin.
+
+abstract class SealedMembers {
+ sealed int foo;
+ // ^
+ // [analyzer] unspecified
+ // [cfe] unspecified
+
+ int bar(sealed int x);
+ // ^
+ // [analyzer] unspecified
+ // [cfe] unspecified
+
+ sealed void bar2();
+ // ^
+ // [analyzer] unspecified
+ // [cfe] unspecified
+}
+
+sealed abstract class SealedAndAbstractClass {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+
+abstract sealed class SealedAndAbstractClass2 {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+class SealedVariable {
+ int foo() {
+ sealed var x = 2;
+ // ^
+ // [analyzer] unspecified
+ // [cfe] unspecified
+ return x;
+ }
+}
\ No newline at end of file
diff --git a/tests/language/sealed_class/sealed_class_syntax_test.dart b/tests/language/sealed_class/sealed_class_syntax_test.dart
new file mode 100644
index 0000000..ceaacb4
--- /dev/null
+++ b/tests/language/sealed_class/sealed_class_syntax_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2022, 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=sealed-class
+
+// Tests we can still use `sealed` as an identifier.
+
+import "package:expect/expect.dart";
+
+class SealedField {
+ int sealed = 0;
+}
+
+class SealedMethod {
+ int sealed() => 1;
+ int foo(int sealed) => sealed;
+ int? foo1([int? sealed]) => sealed;
+ int? foo2({int? sealed}) => sealed;
+}
+
+class SealedVariable {
+ int foo() {
+ var sealed = 2;
+ return sealed;
+ }
+}
+
+main() {
+ var sealedField = SealedField();
+ var sealedMethod = SealedMethod();
+ var sealedVariable = SealedVariable();
+
+ Expect.equals(0, sealedField.sealed);
+
+ Expect.equals(1, sealedMethod.sealed());
+ Expect.equals(1, sealedMethod.foo(1));
+ Expect.equals(1, sealedMethod.foo1(1));
+ Expect.equals(1, sealedMethod.foo2(sealed: 1));
+
+ Expect.equals(2, sealedVariable.foo());
+}
diff --git a/tests/language/sealed_class/sealed_mixin_with_error_test.dart b/tests/language/sealed_class/sealed_mixin_with_error_test.dart
new file mode 100644
index 0000000..ea94933
--- /dev/null
+++ b/tests/language/sealed_class/sealed_mixin_with_error_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2022, 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=sealed-class
+
+// Error when attempting to mix in a sealed mixin outside of its library.
+
+import 'sealed_mixin_with_lib.dart';
+
+abstract class OutsideA with SealedMixin {}
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+
+class OutsideB with SealedMixin {
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
+ @override
+ int foo = 2;
+
+ @override
+ int bar(int value) => value;
+}
+
+abstract class OutsideC = Object with SealedMixin;
+// ^
+// [analyzer] unspecified
+// [cfe] unspecified
diff --git a/tests/language/sealed_class/sealed_mixin_with_lib.dart b/tests/language/sealed_class/sealed_mixin_with_lib.dart
new file mode 100644
index 0000000..959e887
--- /dev/null
+++ b/tests/language/sealed_class/sealed_mixin_with_lib.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2022, 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=sealed-class
+
+sealed mixin SealedMixin {
+ int nonAbstractFoo = 0;
+ abstract int foo;
+ int nonAbstractBar(int value) => value + 100;
+ int bar(int value);
+}
+
+abstract class A with SealedMixin {}
+
+class AImpl extends A {
+ @override
+ int foo = 1;
+
+ @override
+ int bar(int value) => value + 1;
+}
+
+class B with SealedMixin {
+ @override
+ int nonAbstractFoo = 100;
+
+ @override
+ int foo = 2;
+
+ @override
+ int bar(int value) => value;
+}
+
+abstract class C = Object with SealedMixin;
+
+class CImpl extends C {
+ @override
+ int foo = 3;
+
+ @override
+ int bar(int value) => value - 1;
+}
diff --git a/tests/language/sealed_class/sealed_mixin_with_test.dart b/tests/language/sealed_class/sealed_mixin_with_test.dart
new file mode 100644
index 0000000..e8ad0e0
--- /dev/null
+++ b/tests/language/sealed_class/sealed_mixin_with_test.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2022, 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=sealed-class
+
+// Allow sealed mixins to be mixed in by multiple classes in the same library.
+// Additionally, allow their subclasses/subtypes to be used freely.
+
+import "package:expect/expect.dart";
+import 'sealed_mixin_with_lib.dart';
+
+class AExtends extends A {
+ @override
+ int foo = 0;
+
+ @override
+ int bar(int value) => value;
+}
+
+class AImplements implements A {
+ @override
+ int nonAbstractFoo = 0;
+
+ @override
+ int foo = 0;
+
+ @override
+ int bar(int value) => value;
+
+ @override
+ int nonAbstractBar(int value) => value;
+}
+
+class CMixin with C {
+ @override
+ int foo = 0;
+
+ @override
+ int bar(int value) => value;
+}
+
+main() {
+ A a = AImpl();
+ Expect.equals(0, a.nonAbstractFoo);
+ Expect.equals(1, a.foo);
+ Expect.equals(3, a.bar(2));
+ Expect.equals(100, a.nonAbstractBar(0));
+
+ var b = B();
+ Expect.equals(100, b.nonAbstractFoo);
+ Expect.equals(2, b.foo);
+ Expect.equals(2, b.bar(2));
+ Expect.equals(100, b.nonAbstractBar(0));
+
+ C c = CImpl();
+ Expect.equals(0, c.nonAbstractFoo);
+ Expect.equals(3, c.foo);
+ Expect.equals(1, c.bar(2));
+ Expect.equals(100, c.nonAbstractBar(0));
+
+ var aExtends = AExtends();
+ Expect.equals(0, aExtends.nonAbstractFoo);
+ Expect.equals(0, aExtends.foo);
+ Expect.equals(0, aExtends.bar(0));
+ Expect.equals(100, aExtends.nonAbstractBar(0));
+
+ var aImplements = AImplements();
+ Expect.equals(0, aImplements.nonAbstractFoo);
+ Expect.equals(0, aImplements.foo);
+ Expect.equals(0, aImplements.bar(0));
+ Expect.equals(0, aImplements.nonAbstractBar(0));
+
+ var cMixin = CMixin();
+ Expect.equals(0, cMixin.nonAbstractFoo);
+ Expect.equals(0, cMixin.foo);
+ Expect.equals(0, cMixin.bar(0));
+ Expect.equals(100, cMixin.nonAbstractBar(0));
+}