OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015, 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 | |
5 // Verify semantics of the ??= operator, including order of operations, by | |
6 // keeping track of the operations performed. | |
7 | |
8 import "package:expect/expect.dart"; | |
9 import "if_null_assignment_helper.dart" as h; | |
10 | |
11 bad() { | |
12 Expect.fail('Should not be executed'); | |
13 } | |
14 | |
15 var xGetValue = null; | |
16 | |
17 get x { | |
18 h.operations.add('x'); | |
19 var tmp = xGetValue; | |
20 xGetValue = null; | |
21 return tmp; | |
22 } | |
23 | |
24 void set x(value) { | |
25 h.operations.add('x=$value'); | |
26 } | |
27 | |
28 var yGetValue = null; | |
29 | |
30 get y { | |
31 h.operations.add('y'); | |
32 var tmp = yGetValue; | |
33 yGetValue = null; | |
34 return tmp; | |
35 } | |
36 | |
37 void set y(value) { | |
38 h.operations.add('y=$value'); | |
39 } | |
40 | |
41 var zGetValue = null; | |
42 | |
43 get z { | |
44 h.operations.add('z'); | |
45 var tmp = zGetValue; | |
46 zGetValue = null; | |
47 return tmp; | |
48 } | |
49 | |
50 void set z(value) { | |
51 h.operations.add('z=$value'); | |
52 } | |
53 | |
54 var fValue = null; | |
55 | |
56 f() { | |
57 h.operations.add('f()'); | |
58 var tmp = fValue; | |
59 fValue = null; | |
60 return tmp; | |
61 } | |
62 | |
63 void check(expectedValue, f(), expectedOperations) { | |
64 Expect.equals(expectedValue, f()); | |
65 Expect.listEquals(expectedOperations, h.operations); | |
66 h.operations = []; | |
67 } | |
68 | |
69 void checkThrows(expectedException, f(), expectedOperations) { | |
70 Expect.throws(f, expectedException); | |
71 Expect.listEquals(expectedOperations, h.operations); | |
72 h.operations = []; | |
73 } | |
74 | |
75 noMethod(e) => e is NoSuchMethodError; | |
76 | |
77 class C { | |
78 final String s; | |
79 | |
80 C(this.s); | |
81 | |
82 @override | |
83 String toString() => s; | |
84 | |
85 static var xGetValue = null; | |
86 | |
87 static get x { | |
88 h.operations.add('C.x'); | |
89 var tmp = xGetValue; | |
90 xGetValue = null; | |
91 return tmp; | |
92 } | |
93 | |
94 static void set x(value) { | |
95 h.operations.add('C.x=$value'); | |
96 } | |
97 | |
98 var vGetValue = null; | |
99 | |
100 get v { | |
101 h.operations.add('$s.v'); | |
102 var tmp = vGetValue; | |
103 vGetValue = null; | |
104 return tmp; | |
105 } | |
106 | |
107 void set v(value) { | |
108 h.operations.add('$s.v=$value'); | |
109 } | |
110 | |
111 var indexGetValue = null; | |
112 | |
113 operator [](index) { | |
114 h.operations.add('$s[$index]'); | |
115 var tmp = indexGetValue; | |
116 indexGetValue = null; | |
117 return tmp; | |
118 } | |
119 | |
120 void operator []=(index, value) { | |
121 h.operations.add('$s[$index]=$value'); | |
122 } | |
123 | |
124 final finalOne = 1; | |
125 final finalNull = null; | |
126 | |
127 void instanceTest() { | |
128 // v ??= e is equivalent to ((x) => x == null ? v = e : x)(v) | |
129 vGetValue = 1; check(1, () => v ??= bad(), ['$s.v']); //# 01: ok | |
130 yGetValue = 1; check(1, () => v ??= y, ['$s.v', 'y', '$s.v=1']); //# 02: ok | |
131 check(1, () => finalOne ??= bad(), []); //# 03: static type warning | |
132 yGetValue = 1; checkThrows(noMethod, () => finalNull ??= y, ['y']); //# 04:
static type warning | |
133 } | |
134 } | |
135 | |
136 class D extends C { | |
137 D(String s) : super(s); | |
138 | |
139 get v => bad(); | |
140 | |
141 void set v(value) { | |
142 bad(); | |
143 } | |
144 | |
145 void derivedInstanceTest() { | |
146 // super.v ??= e is equivalent to | |
147 // ((x) => x == null ? super.v = e : x)(super.v) | |
148 vGetValue = 1; check(1, () => super.v ??= bad(), ['$s.v']); //# 05: ok | |
149 yGetValue = 1; check(1, () => super.v ??= y, ['$s.v', 'y', '$s.v=1']); //# 0
6: ok | |
150 } | |
151 } | |
152 | |
153 main() { | |
154 // Make sure the "none" test fails if "??=" is not implemented. This makes | |
155 // status files easier to maintain. | |
156 var _; | |
157 _ ??= null; | |
158 | |
159 new C('c').instanceTest(); | |
160 new D('d').derivedInstanceTest(); | |
161 | |
162 // v ??= e is equivalent to ((x) => x == null ? v = e : x)(v) | |
163 xGetValue = 1; check(1, () => x ??= bad(), ['x']); //# 07: ok | |
164 yGetValue = 1; check(1, () => x ??= y, ['x', 'y', 'x=1']); //# 08: ok | |
165 h.xGetValue = 1; check(1, () => h.x ??= bad(), ['h.x']); //# 09: ok | |
166 yGetValue = 1; check(1, () => h.x ??= y, ['h.x', 'y', 'h.x=1']); //# 10: ok | |
167 { var l = 1; check(1, () => l ??= bad(), []); } //# 11: ok | |
168 { var l; yGetValue = 1; check(1, () => l ??= y, ['y']); Expect.equals(1, l); }
//# 12: ok | |
169 { final l = 1; check(1, () => l ??= bad(), []); } //# 13: static type warning | |
170 { final l = null; yGetValue = 1; checkThrows(noMethod, () => l ??= y, ['y']);
} //# 14: static type warning | |
171 check(C, () => C ??= bad(), []); //# 15: static type warning | |
172 h ??= null; //# 29: compile-time error | |
173 h[0] ??= null; //# 30: compile-time error | |
174 | |
175 // C.v ??= e is equivalent to ((x) => x == null ? C.v = e : x)(C.v) | |
176 C.xGetValue = 1; check(1, () => C.x ??= bad(), ['C.x']); //# 16: ok | |
177 yGetValue = 1; check(1, () => C.x ??= y, ['C.x', 'y', 'C.x=1']); //# 17: ok | |
178 h.C.xGetValue = 1; check(1, () => h.C.x ??= bad(), ['h.C.x']); //# 18: ok | |
179 yGetValue = 1; check(1, () => h.C.x ??= y, ['h.C.x', 'y', 'h.C.x=1']); //# 19:
ok | |
180 | |
181 // e1.v ??= e2 is equivalent to | |
182 // ((x) => ((y) => y == null ? x.v = e2 : y)(x.v))(e1) | |
183 xGetValue = new C('x'); xGetValue.vGetValue = 1; //# 20: ok | |
184 check(1, () => x.v ??= bad(), ['x', 'x.v']); // //# 20: continued | |
185 xGetValue = new C('x'); yGetValue = 1; // //# 21: ok | |
186 check(1, () => x.v ??= y, ['x', 'x.v', 'y', 'x.v=1']); //# 21: continued | |
187 fValue = new C('f()'); fValue.vGetValue = 1; // //# 22: ok | |
188 check(1, () => f().v ??= bad(), ['f()', 'f().v']); //# 22: continued | |
189 fValue = new C('f()'); yGetValue = 1; // //# 23: ok | |
190 check(1, () => f().v ??= y, ['f()', 'f().v', 'y', 'f().v=1']); //# 23: continu
ed | |
191 | |
192 // e1[e2] ??= e3 is equivalent to | |
193 // ((a, i) => ((x) => x == null ? a[i] = e3 : x)(a[i]))(e1, e2) | |
194 xGetValue = new C('x'); yGetValue = 1; xGetValue.indexGetValue = 2; //# 24: ok | |
195 check(2, () => x[y] ??= bad(), ['x', 'y', 'x[1]']); // //# 24:
continued | |
196 xGetValue = new C('x'); yGetValue = 1; zGetValue = 2; // //# 25: ok | |
197 check(2, () => x[y] ??= z, ['x', 'y', 'x[1]', 'z', 'x[1]=2']); //# 25: continu
ed | |
198 | |
199 // e1?.v ??= e2 is equivalent to ((x) => x == null ? null : x.v ??= e2)(e1). | |
200 check(null, () => x?.v ??= bad(), ['x']); //# 26: ok | |
201 xGetValue = new C('x'); xGetValue.vGetValue = 1; //# 27: ok | |
202 check(1, () => x?.v ??= bad(), ['x', 'x.v']); // //# 27: continued | |
203 xGetValue = new C('x'); yGetValue = 1; // //# 28: ok | |
204 check(1, () => x?.v ??= y, ['x', 'x.v', 'y', 'x.v=1']); //# 28: continued | |
205 | |
206 // C?.v ??= e2 is equivalent to C.v ??= e2. | |
207 C.xGetValue = 1; // //# 29: ok | |
208 check(1, () => C?.x ??= bad(), ['C.x']); //# 29: continued | |
209 h.C.xgetValue = 1; // //# 30: ok | |
210 check(1, () => h.c?.x ??= bad(), ['h.C.x']); //# 30: continued | |
211 yGetValue = 1; // //# 31: ok | |
212 check(1, () => C?.x ??= y, ['C.x', 'y', 'C.x=1']); //# 31: continued | |
213 yGetValue = 1; // //# 32: ok | |
214 check(1, () => h.C?.x ??= y, ['h.C.x', 'y', 'h.C.x=1']); //# 32: continued | |
215 } | |
OLD | NEW |