Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Unified Diff: tests/language_strong/covariant_subtyping_test.dart

Issue 2954523002: fix #27259, implement covariance checking for strong mode and DDC (Closed)
Patch Set: merged and fix an analysis error Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/dev_compiler/test/codegen_expected/closure.js ('k') | tests/language_strong/type_hoisting_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tests/language_strong/covariant_subtyping_test.dart
diff --git a/tests/language_strong/covariant_subtyping_test.dart b/tests/language_strong/covariant_subtyping_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..d7ffbc5f49f3b86cad0d85314272526649bab438
--- /dev/null
+++ b/tests/language_strong/covariant_subtyping_test.dart
@@ -0,0 +1,225 @@
+// Copyright (c) 2017, 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.
+import 'package:expect/expect.dart';
+
+bool isTypeError(e) => e is TypeError;
+
+class Fields<T> {
+ T x;
+ T _y;
+ T _z;
+
+ m() {
+ _y = x;
+ }
+
+ n(Fields<T> c) {
+ c._z = x;
+ }
+}
+
+testField() {
+ Fields<Object> c = new Fields<int>();
+ Expect.throws(() {
+ c.x = 'hello';
+ }, isTypeError);
+
+ Fields<dynamic> d = new Fields<int>();
+ Expect.throws(() {
+ c.x = 'hello';
+ }, isTypeError);
+}
+
+testPrivateFields() {
+ Fields<Object> c = new Fields<int>()..x = 42;
+ c.m();
+ Expect.equals(c._y, 42);
+
+ Fields<Object> c2 = new Fields<String>()..x = 'hi';
+ c2.n(c2);
+ Expect.equals(c2._z, 'hi');
+ Expect.throws(() {
+ c.n(c2);
+ }, isTypeError);
+ Expect.equals(c2._z, 'hi');
+}
+
+class NumBounds<T extends num> {
+ bool m(T t) => t.isNegative;
+}
+
+class MethodTakesNum extends NumBounds<int> {
+ bool m(num obj) => obj.isNegative; // does not need check
+}
+
+class MethodTakesInt extends NumBounds<int> {
+ bool m(int obj) => obj.isNegative; // needs a check
+}
+
+testClassBounds() {
+ NumBounds<num> d = new MethodTakesNum();
+ Expect.equals(d.m(-1.1), true);
+ d = new MethodTakesInt();
+ Expect.throws(() {
+ d.m(-1.1);
+ }, isTypeError);
+}
+
+typedef void F<T>(T t);
+typedef G<T> = void Function<S extends T>(S s);
+
+class FnChecks<T> {
+ F<T> f;
+ G<T> g;
+ T _t;
+ T getT() => _t;
+ F<T> setterForT() {
+ return (T t) {
+ _t = t;
+ };
+ }
+}
+
+testReturnOfFunctionType() {
+ FnChecks<int> cInt = new FnChecks<int>();
+ FnChecks<Object> cObj = cInt;
+ Expect.throws(() => cObj.setterForT(), isTypeError);
+ Expect.throws(() => (cObj.setterForT() as F<Object>), isTypeError);
+ FnChecks<dynamic> cDyn = cInt;
+ cDyn.setterForT(); // allowed fuzzy arrow
+ Expect.throws(() => cDyn.setterForT()('hi'), isTypeError); // dcall throws
+ cInt.setterForT()(42);
+ Expect.equals(cObj.getT(), 42);
+}
+
+testFieldOfFunctionType() {
+ FnChecks<Object> c = new FnChecks<String>()..f = (String b) {};
+ Expect.throws(() {
+ F<Object> f = c.f;
+ }, isTypeError);
+ Expect.throws(() {
+ Object f = c.f;
+ }, isTypeError);
+ Expect.throws(() => c.f, isTypeError);
+ Expect.throws(() => c.f(42), isTypeError);
+ Expect.throws(() => c.f('hi'), isTypeError);
+ FnChecks<String> cStr = c;
+ cStr.f('hi');
+ FnChecks<dynamic> cDyn = c;
+ cDyn.f; // allowed fuzzy arrow
+ Expect.throws(() => cDyn.f(42), isTypeError); // dcall throws
+}
+
+testFieldOfGenericFunctionType() {
+ FnChecks<Object> c = new FnChecks<num>()
+ ..g = <S extends num>(S s) => s.isNegative;
+
+ Expect.throws(() {
+ G<Object> g = c.g;
+ }, isTypeError);
+ Expect.throws(() {
+ var g = c.g;
+ }, isTypeError);
+ Expect.throws(() {
+ c.g<String>('hi');
+ }, isTypeError);
+ Expect.throws(() {
+ c.g<int>(42);
+ }, isTypeError);
+ FnChecks<num> cNum = c;
+ cNum.g(42);
+}
+
+class Base {
+ int _t = 0;
+ add(int t) {
+ _t += t;
+ }
+}
+
+abstract class I<T> {
+ add(T t);
+}
+
+class ExtendsBase extends Base implements I<int> {}
+
+class MixinBase extends Object with Base implements I<int> {}
+
+class MixinBase2 = Object with Base implements I<int>;
+
+testMixinApplication() {
+ I<Object> i = new ExtendsBase();
+ I<Object> j = new MixinBase();
+ I<Object> k = new MixinBase2();
+ Expect.throws(() {
+ i.add('hi');
+ }, isTypeError);
+ Expect.throws(() {
+ j.add('hi');
+ }, isTypeError);
+ // TODO(jmesserly): this should also throw. It does not because DDC's
+ // technique for generating mixin aliases (mixin applications of the form
+ // `class X = Object with Y /* optional implements */;`) does not allow
+ // adding any methods in the class. The normal technique of generating
+ // a method that performs the check and then calls `super` will not work,
+ // because there is no superclass to call. We will need some sort of
+ // special case code to implement this, perhaps move the original
+ // method to a symbol, then generate a wrapper with the original method name,
+ // that checks and calls it.
+ k.add('hi');
+}
+
+abstract class GenericAdd<T> {
+ add<S extends T>(S t);
+}
+
+class GenericAdder implements GenericAdd<num> {
+ num _t = 0;
+ add<T extends num>(T t) {
+ _t = t;
+ }
+}
+
+testGenericMethodBounds() {
+ GenericAdd<Object> i = new GenericAdder();
+ // TODO(jmesserly): should generic method bounds use a different error type?
+ // This seems wrong. Also this Error type is not exposed from dart:core.
+ Expect.throws(() {
+ i.add('hi');
+ }, (e) => '${e.runtimeType}'.startsWith('StrongModeError'));
+ Expect.throws(() {
+ i.add<String>(null);
+ }, (e) => '${e.runtimeType}'.startsWith('StrongModeError'));
+ i.add(null);
+ i.add(42);
+}
+
+class ClassF<T> {
+ T x;
+ void call(T t) {
+ x = t;
+ }
+}
+
+testCallMethod() {
+ ClassF<int> cc = new ClassF<int>();
+ ClassF<Object> ca = cc; // An upcast, per covariance.
+ F<Object> f = ca;
+ Expect.equals(f.runtimeType.toString(), 'ClassF<int>');
+ Expect.throws(() {
+ f(new Object());
+ }, isTypeError);
+}
+
+main() {
+ testField();
+ testPrivateFields();
+ testClassBounds();
+ testReturnOfFunctionType();
+ testFieldOfFunctionType();
+ testFieldOfGenericFunctionType();
+ testMixinApplication();
+ testGenericMethodBounds();
+ testCallMethod();
+}
« no previous file with comments | « pkg/dev_compiler/test/codegen_expected/closure.js ('k') | tests/language_strong/type_hoisting_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698