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

Side by Side Diff: tests/language_strong/covariant_subtyping_test.dart

Issue 2954523002: fix #27259, implement covariance checking for strong mode and DDC (Closed)
Patch Set: format 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4 import 'package:expect/expect.dart';
5
6 bool isTypeError(e) => e is TypeError;
7
8 class Fields<T> {
9 T x;
10 T _y;
11 T _z;
12
13 m() {
14 _y = x;
15 }
16
17 n(Fields<T> c) {
18 c._z = x;
19 }
20 }
21
22 testField() {
23 Fields<Object> c = new Fields<int>();
24 Expect.throws(() {
25 c.x = 'hello';
26 }, isTypeError);
27
28 Fields<dynamic> d = new Fields<int>();
29 Expect.throws(() {
30 c.x = 'hello';
31 }, isTypeError);
32 }
33
34 testPrivateFields() {
35 Fields<Object> c = new Fields<int>()..x = 42;
36 c.m();
37 Expect.equals(c._y, 42);
38
39 Fields<Object> c2 = new Fields<String>()..x = 'hi';
40 c2.n(c2);
41 Expect.equals(c2._z, 'hi');
42 Expect.throws(() {
43 c.n(c2);
44 }, isTypeError);
45 Expect.equals(c2._z, 'hi');
46 }
47
48 class NumBounds<T extends num> {
49 bool m(T t) => t.isNegative;
50 }
51
52 class MethodTakesNum extends NumBounds<int> {
53 bool m(num obj) => obj.isNegative; // does not need check
54 }
55
56 class MethodTakesInt extends NumBounds<int> {
57 bool m(int obj) => obj.isNegative; // needs a check
58 }
59
60 testClassBounds() {
61 NumBounds<num> d = new MethodTakesNum();
62 Expect.equals(d.m(-1.1), true);
63 d = new MethodTakesInt();
64 Expect.throws(() {
65 d.m(-1.1);
66 }, isTypeError);
67 }
68
69 typedef void F<T>(T t);
70 typedef G<T> = void Function<S extends T>(S s);
71
72 class FnChecks<T> {
73 F<T> f;
74 G<T> g;
75 T _t;
76 T getT() => _t;
77 F<T> setterForT() {
78 return (T t) {
79 _t = t;
80 };
81 }
82 }
83
84 testReturnOfFunctionType() {
85 FnChecks<int> cInt = new FnChecks<int>();
86 FnChecks<Object> cObj = cInt;
87 Expect.throws(() => cObj.setterForT(), isTypeError);
88 Expect.throws(() => (cObj.setterForT() as F<Object>), isTypeError);
89 FnChecks<dynamic> cDyn = cInt;
90 cDyn.setterForT(); // allowed fuzzy arrow
91 Expect.throws(() => cDyn.setterForT()('hi'), isTypeError); // dcall throws
92 cInt.setterForT()(42);
93 Expect.equals(cObj.getT(), 42);
94 }
95
96 testFieldOfFunctionType() {
97 FnChecks<Object> c = new FnChecks<String>()..f = (String b) {};
98 Expect.throws(() {
99 F<Object> f = c.f;
100 }, isTypeError);
101 Expect.throws(() {
102 Object f = c.f;
103 }, isTypeError);
104 Expect.throws(() => c.f, isTypeError);
105 Expect.throws(() => c.f(42), isTypeError);
106 Expect.throws(() => c.f('hi'), isTypeError);
107 FnChecks<String> cStr = c;
108 cStr.f('hi');
109 FnChecks<dynamic> cDyn = c;
110 cDyn.f; // allowed fuzzy arrow
111 Expect.throws(() => cDyn.f(42), isTypeError); // dcall throws
112 }
113
114 testFieldOfGenericFunctionType() {
115 FnChecks<Object> c = new FnChecks<num>()
116 ..g = <S extends num>(S s) => s.isNegative;
117
118 Expect.throws(() {
119 G<Object> g = c.g;
120 }, isTypeError);
121 Expect.throws(() {
122 var g = c.g;
123 }, isTypeError);
124 Expect.throws(() {
125 c.g<String>('hi');
126 }, isTypeError);
127 Expect.throws(() {
128 c.g<int>(42);
129 }, isTypeError);
130 FnChecks<num> cNum = c;
131 cNum.g(42);
132 }
133
134 class Base {
135 int _t = 0;
136 add(int t) {
137 _t += t;
138 }
139 }
140
141 abstract class I<T> {
142 add(T t);
143 }
144
145 class ExtendsBase extends Base implements I<int> {}
146
147 class MixinBase extends Object with Base implements I<int> {}
148
149 class MixinBase2 = Object with Base implements I<int>;
150
151 testMixinApplication() {
152 I<Object> i = new ExtendsBase();
153 I<Object> j = new MixinBase();
154 I<Object> k = new MixinBase2();
155 Expect.throws(() {
156 i.add('hi');
157 }, isTypeError);
158 Expect.throws(() {
159 j.add('hi');
160 }, isTypeError);
161 // TODO(jmesserly): this should also throw. It does not because DDC's
162 // technique for generating mixin aliases (mixin applications of the form
163 // `class X = Object with Y /* optional implements */;`) does not allow
164 // adding any methods in the class. The normal technique of generating
165 // a method that performs the check and then calls `super` will not work,
166 // because there is no superclass to call. We will need some sort of
167 // special case code to implement this, perhaps move the original
168 // method to a symbol, then generate a wrapper with the original method name,
169 // that checks and calls it.
170 k.add('hi');
171 }
172
173 abstract class GenericAdd<T> {
174 add<S extends T>(S t);
175 }
176
177 class GenericAdder implements GenericAdd<num> {
178 num _t = 0;
179 add<T extends num>(T t) {
180 _t = t;
181 }
182 }
183
184 testGenericMethodBounds() {
185 GenericAdd<Object> i = new GenericAdder();
186 // TODO(jmesserly): should generic method bounds use a different error type?
187 // This seems wrong. Also this Error type is not exposed from dart:core.
vsm 2017/07/06 15:43:02 File a lang bug to clarify?
Jennifer Messerly 2017/07/06 21:31:04 done! https://github.com/dart-lang/sdk/issues/3009
188 Expect.throws(() {
189 i.add('hi');
190 }, (e) => '${e.runtimeType}'.startsWith('StrongModeError'));
191 Expect.throws(() {
192 i.add<String>(null);
193 }, (e) => '${e.runtimeType}'.startsWith('StrongModeError'));
194 i.add(null);
195 i.add(42);
196 }
197
198 class ClassF<T> {
199 T x;
200 void call(T t) {
201 x = t;
202 }
203 }
204
205 testCallMethod() {
206 ClassF<int> cc = new ClassF<int>();
207 ClassF<Object> ca = cc; // An upcast, per covariance.
208 F<Object> f = ca;
209 Expect.equals(f.runtimeType.toString(), 'ClassF<int>');
210 Expect.throws(() {
211 f(new Object());
212 }, isTypeError);
213 }
214
215 main() {
216 testField();
217 testPrivateFields();
218 testClassBounds();
219 testReturnOfFunctionType();
220 testFieldOfFunctionType();
221 testFieldOfGenericFunctionType();
222 testMixinApplication();
223 testGenericMethodBounds();
224 testCallMethod();
225 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698