[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));
+}