OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library dart2js.constants.expressions.evaluate_test; | 5 library dart2js.constants.expressions.evaluate_test; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'package:async_helper/async_helper.dart'; | 8 import 'package:async_helper/async_helper.dart'; |
9 import 'package:expect/expect.dart'; | 9 import 'package:expect/expect.dart'; |
10 import 'package:compiler/src/constants/evaluation.dart'; | 10 import 'package:compiler/src/constants/evaluation.dart'; |
11 import 'package:compiler/src/constants/expressions.dart'; | 11 import 'package:compiler/src/constants/expressions.dart'; |
12 import 'package:compiler/src/constants/values.dart'; | 12 import 'package:compiler/src/constants/values.dart'; |
13 import 'package:compiler/src/constant_system_dart.dart'; | 13 import 'package:compiler/src/constant_system_dart.dart'; |
14 import 'package:compiler/src/compiler.dart'; | 14 import 'package:compiler/src/compiler.dart'; |
15 import 'package:compiler/src/elements/elements.dart'; | 15 import 'package:compiler/src/elements/elements.dart'; |
16 import 'memory_compiler.dart'; | 16 import 'memory_compiler.dart'; |
17 | 17 |
18 class TestData { | 18 class TestData { |
19 /// Declarations needed for the [constants]. | 19 /// Declarations needed for the [constants]. |
20 final String declarations; | 20 final String declarations; |
| 21 |
21 /// Tested constants. | 22 /// Tested constants. |
22 final List constants; | 23 final List constants; |
23 | 24 |
24 const TestData(this.declarations, this.constants); | 25 const TestData(this.declarations, this.constants); |
25 } | 26 } |
26 | 27 |
27 class ConstantData { | 28 class ConstantData { |
28 /// Source code for the constant expression. | 29 /// Source code for the constant expression. |
29 final String code; | 30 final String code; |
| 31 |
30 /// Map from environment to expected constant value as structured text. | 32 /// Map from environment to expected constant value as structured text. |
31 final Map<Map<String, String>, String> expectedValues; | 33 final Map<Map<String, String>, String> expectedValues; |
32 | 34 |
33 const ConstantData(this.code, | 35 const ConstantData(this.code, this.expectedValues); |
34 this.expectedValues); | |
35 } | 36 } |
36 | 37 |
37 class MemoryEnvironment implements Environment { | 38 class MemoryEnvironment implements Environment { |
38 final Compiler compiler; | 39 final Compiler compiler; |
39 final Map<String, String> env; | 40 final Map<String, String> env; |
40 | 41 |
41 MemoryEnvironment(this.compiler, | 42 MemoryEnvironment(this.compiler, [this.env = const <String, String>{}]); |
42 [this.env = const <String, String>{}]); | |
43 | 43 |
44 @override | 44 @override |
45 String readFromEnvironment(String name) => env[name]; | 45 String readFromEnvironment(String name) => env[name]; |
46 } | 46 } |
47 | 47 |
48 const List<TestData> DATA = const [ | 48 const List<TestData> DATA = const [ |
49 const TestData('', const [ | 49 const TestData('', const [ |
50 const ConstantData('null', const { const {} : 'NullConstant' }), | 50 const ConstantData('null', const {const {}: 'NullConstant'}), |
51 const ConstantData('false', const { const {} : 'BoolConstant(false)' }), | 51 const ConstantData('false', const {const {}: 'BoolConstant(false)'}), |
52 const ConstantData('true', const { const {} : 'BoolConstant(true)' }), | 52 const ConstantData('true', const {const {}: 'BoolConstant(true)'}), |
53 const ConstantData('0', const { const {} : 'IntConstant(0)' }), | 53 const ConstantData('0', const {const {}: 'IntConstant(0)'}), |
54 const ConstantData('0.0', const { const {} : 'DoubleConstant(0.0)' }), | 54 const ConstantData('0.0', const {const {}: 'DoubleConstant(0.0)'}), |
55 const ConstantData('"foo"', const { const {} : 'StringConstant("foo")' }), | 55 const ConstantData('"foo"', const {const {}: 'StringConstant("foo")'}), |
56 const ConstantData('1 + 2', const { const {} : 'IntConstant(3)' }), | 56 const ConstantData('1 + 2', const {const {}: 'IntConstant(3)'}), |
57 const ConstantData('-(1)', const { const {} : 'IntConstant(-1)' }), | 57 const ConstantData('-(1)', const {const {}: 'IntConstant(-1)'}), |
58 const ConstantData('1 == 2', const { const {} : 'BoolConstant(false)' }), | 58 const ConstantData('1 == 2', const {const {}: 'BoolConstant(false)'}), |
59 const ConstantData('1 != 2', const { const {} : 'BoolConstant(true)' }), | 59 const ConstantData('1 != 2', const {const {}: 'BoolConstant(true)'}), |
60 const ConstantData('"foo".length', const { const {} : 'IntConstant(3)' }), | 60 const ConstantData('"foo".length', const {const {}: 'IntConstant(3)'}), |
61 const ConstantData('identical(0, 1)', | 61 const ConstantData( |
62 const { const {} : 'BoolConstant(false)' }), | 62 'identical(0, 1)', const {const {}: 'BoolConstant(false)'}), |
63 const ConstantData('"a" "b"', const { const {} : 'StringConstant("ab")' }), | 63 const ConstantData('"a" "b"', const {const {}: 'StringConstant("ab")'}), |
64 const ConstantData(r'"${null}"', | 64 const ConstantData( |
65 const { const {} : 'StringConstant("null")' }), | 65 r'"${null}"', const {const {}: 'StringConstant("null")'}), |
66 const ConstantData('identical', | 66 const ConstantData( |
67 const { const {} : 'FunctionConstant(identical)' }), | 67 'identical', const {const {}: 'FunctionConstant(identical)'}), |
68 const ConstantData('true ? 0 : 1', const { const {} : 'IntConstant(0)' }), | 68 const ConstantData('true ? 0 : 1', const {const {}: 'IntConstant(0)'}), |
69 const ConstantData('proxy', | 69 const ConstantData( |
70 const { const {} : 'ConstructedConstant(_Proxy())' }), | 70 'proxy', const {const {}: 'ConstructedConstant(_Proxy())'}), |
71 const ConstantData('Object', const { const {} : 'TypeConstant(Object)' }), | 71 const ConstantData('Object', const {const {}: 'TypeConstant(Object)'}), |
72 const ConstantData('const [0, 1]', | 72 const ConstantData('const [0, 1]', |
73 const { const {} : 'ListConstant([IntConstant(0), IntConstant(1)])' }), | 73 const {const {}: 'ListConstant([IntConstant(0), IntConstant(1)])'}), |
74 const ConstantData('const <int>[0, 1]', const { | 74 const ConstantData('const <int>[0, 1]', const { |
75 const {} : 'ListConstant(<int>[IntConstant(0), IntConstant(1)])' }), | 75 const {}: 'ListConstant(<int>[IntConstant(0), IntConstant(1)])' |
76 const ConstantData('const {0: 1, 2: 3}', | 76 }), |
77 const { const {} : | 77 const ConstantData('const {0: 1, 2: 3}', const { |
78 'MapConstant({IntConstant(0): IntConstant(1), ' | 78 const {}: 'MapConstant({IntConstant(0): IntConstant(1), ' |
79 'IntConstant(2): IntConstant(3)})' }), | 79 'IntConstant(2): IntConstant(3)})' |
80 const ConstantData('const <int, int>{0: 1, 2: 3}', | 80 }), |
81 const { const {} : | 81 const ConstantData('const <int, int>{0: 1, 2: 3}', const { |
82 'MapConstant(<int, int>{IntConstant(0): IntConstant(1), ' | 82 const {}: 'MapConstant(<int, int>{IntConstant(0): IntConstant(1), ' |
83 'IntConstant(2): IntConstant(3)})' }), | 83 'IntConstant(2): IntConstant(3)})' |
84 const ConstantData('const <int, int>{0: 1, 0: 2}', | 84 }), |
85 const { const {} : | 85 const ConstantData('const <int, int>{0: 1, 0: 2}', const { |
86 'MapConstant(<int, int>{IntConstant(0): IntConstant(2)})' }), | 86 const {}: 'MapConstant(<int, int>{IntConstant(0): IntConstant(2)})' |
| 87 }), |
87 const ConstantData( | 88 const ConstantData( |
88 'const bool.fromEnvironment("foo", defaultValue: false)', | 89 'const bool.fromEnvironment("foo", defaultValue: false)', const { |
89 const { const {} : 'BoolConstant(false)', | 90 const {}: 'BoolConstant(false)', |
90 const {'foo': 'true'} : 'BoolConstant(true)'}), | 91 const {'foo': 'true'}: 'BoolConstant(true)' |
| 92 }), |
91 const ConstantData( | 93 const ConstantData( |
92 'const int.fromEnvironment("foo", defaultValue: 42)', | 94 'const int.fromEnvironment("foo", defaultValue: 42)', const { |
93 const { const {} : 'IntConstant(42)', | 95 const {}: 'IntConstant(42)', |
94 const {'foo': '87'} : 'IntConstant(87)'}), | 96 const {'foo': '87'}: 'IntConstant(87)' |
| 97 }), |
95 const ConstantData( | 98 const ConstantData( |
96 'const String.fromEnvironment("foo", defaultValue: "bar")', | 99 'const String.fromEnvironment("foo", defaultValue: "bar")', const { |
97 const { const {} : 'StringConstant("bar")', | 100 const {}: 'StringConstant("bar")', |
98 const {'foo': 'foo'} : 'StringConstant("foo")'}), | 101 const {'foo': 'foo'}: 'StringConstant("foo")' |
| 102 }), |
99 ]), | 103 ]), |
100 const TestData(''' | 104 const TestData( |
| 105 ''' |
101 const a = const bool.fromEnvironment("foo", defaultValue: true); | 106 const a = const bool.fromEnvironment("foo", defaultValue: true); |
102 const b = const int.fromEnvironment("bar", defaultValue: 42); | 107 const b = const int.fromEnvironment("bar", defaultValue: 42); |
103 | 108 |
104 class A { | 109 class A { |
105 const A(); | 110 const A(); |
106 } | 111 } |
107 class B { | 112 class B { |
108 final field1; | 113 final field1; |
109 const B(this.field1); | 114 const B(this.field1); |
110 } | 115 } |
111 class C extends B { | 116 class C extends B { |
112 final field2; | 117 final field2; |
113 const C({field1: 42, this.field2: false}) : super(field1); | 118 const C({field1: 42, this.field2: false}) : super(field1); |
114 const C.named([field = false]) : this(field1: field, field2: field); | 119 const C.named([field = false]) : this(field1: field, field2: field); |
115 } | 120 } |
116 class D extends C { | 121 class D extends C { |
117 final field3 = 99; | 122 final field3 = 99; |
118 const D(a, b) : super(field2: a, field1: b); | 123 const D(a, b) : super(field2: a, field1: b); |
119 } | 124 } |
120 ''', const [ | 125 ''', |
121 const ConstantData('const Object()', | 126 const [ |
122 const { const {} : 'ConstructedConstant(Object())' }), | 127 const ConstantData('const Object()', |
123 const ConstantData('const A()', | 128 const {const {}: 'ConstructedConstant(Object())'}), |
124 const { const {} : 'ConstructedConstant(A())' }), | 129 const ConstantData( |
125 const ConstantData('const B(0)', | 130 'const A()', const {const {}: 'ConstructedConstant(A())'}), |
126 const { const {} : 'ConstructedConstant(B(field1=IntConstant(0)))' }), | 131 const ConstantData('const B(0)', |
127 const ConstantData('const B(const A())', | 132 const {const {}: 'ConstructedConstant(B(field1=IntConstant(0)))'}), |
128 const { const {} : | 133 const ConstantData('const B(const A())', const { |
129 'ConstructedConstant(B(field1=ConstructedConstant(A())))' }), | 134 const {}: 'ConstructedConstant(B(field1=ConstructedConstant(A())))' |
130 const ConstantData('const C()', const { const {} : | 135 }), |
131 'ConstructedConstant(C(field1=IntConstant(42),' | 136 const ConstantData('const C()', const { |
132 'field2=BoolConstant(false)))' }), | 137 const {}: 'ConstructedConstant(C(field1=IntConstant(42),' |
133 const ConstantData('const C(field1: 87)', const { const {} : | 138 'field2=BoolConstant(false)))' |
134 'ConstructedConstant(C(field1=IntConstant(87),' | 139 }), |
135 'field2=BoolConstant(false)))' }), | 140 const ConstantData('const C(field1: 87)', const { |
136 const ConstantData('const C(field2: true)', const { const {} : | 141 const {}: 'ConstructedConstant(C(field1=IntConstant(87),' |
137 'ConstructedConstant(C(field1=IntConstant(42),' | 142 'field2=BoolConstant(false)))' |
138 'field2=BoolConstant(true)))' }), | 143 }), |
139 const ConstantData('const C.named()', const { const {} : | 144 const ConstantData('const C(field2: true)', const { |
140 'ConstructedConstant(C(field1=BoolConstant(false),' | 145 const {}: 'ConstructedConstant(C(field1=IntConstant(42),' |
141 'field2=BoolConstant(false)))' }), | 146 'field2=BoolConstant(true)))' |
142 const ConstantData('const C.named(87)', const { const {} : | 147 }), |
143 'ConstructedConstant(C(field1=IntConstant(87),' | 148 const ConstantData('const C.named()', const { |
144 'field2=IntConstant(87)))' }), | 149 const {}: 'ConstructedConstant(C(field1=BoolConstant(false),' |
145 const ConstantData('const C(field1: a, field2: b)', const { | 150 'field2=BoolConstant(false)))' |
146 const {} : | 151 }), |
147 'ConstructedConstant(C(field1=BoolConstant(true),' | 152 const ConstantData('const C.named(87)', const { |
148 'field2=IntConstant(42)))', | 153 const {}: 'ConstructedConstant(C(field1=IntConstant(87),' |
149 const {'foo': 'false', 'bar': '87'} : | 154 'field2=IntConstant(87)))' |
150 'ConstructedConstant(C(field1=BoolConstant(false),' | 155 }), |
151 'field2=IntConstant(87)))', }), | 156 const ConstantData('const C(field1: a, field2: b)', const { |
152 const ConstantData('const D(42, 87)', const { const {} : | 157 const {}: 'ConstructedConstant(C(field1=BoolConstant(true),' |
153 'ConstructedConstant(D(field1=IntConstant(87),' | 158 'field2=IntConstant(42)))', |
154 'field2=IntConstant(42),' | 159 const {'foo': 'false', 'bar': '87'}: |
155 'field3=IntConstant(99)))' }), | 160 'ConstructedConstant(C(field1=BoolConstant(false),' |
156 ]), | 161 'field2=IntConstant(87)))', |
157 const TestData(''' | 162 }), |
| 163 const ConstantData('const D(42, 87)', const { |
| 164 const {}: 'ConstructedConstant(D(field1=IntConstant(87),' |
| 165 'field2=IntConstant(42),' |
| 166 'field3=IntConstant(99)))' |
| 167 }), |
| 168 ]), |
| 169 const TestData( |
| 170 ''' |
158 class A<T> implements B { | 171 class A<T> implements B { |
159 final field1; | 172 final field1; |
160 const A({this.field1:42}); | 173 const A({this.field1:42}); |
161 } | 174 } |
162 class B<S> implements C { | 175 class B<S> implements C { |
163 const factory B({field1}) = A<B<S>>; | 176 const factory B({field1}) = A<B<S>>; |
164 const factory B.named() = A<S>; | 177 const factory B.named() = A<S>; |
165 } | 178 } |
166 class C<U> { | 179 class C<U> { |
167 const factory C({field1}) = A<B<double>>; | 180 const factory C({field1}) = A<B<double>>; |
168 } | 181 } |
169 ''', const [ | 182 ''', |
170 const ConstantData('const A()', | 183 const [ |
171 const { const {} : | 184 const ConstantData('const A()', const { |
172 'ConstructedConstant(A<dynamic>(field1=IntConstant(42)))' }), | 185 const {}: 'ConstructedConstant(A<dynamic>(field1=IntConstant(42)))' |
173 const ConstantData('const A<int>(field1: 87)', | 186 }), |
174 const { const {} : | 187 const ConstantData('const A<int>(field1: 87)', const { |
175 'ConstructedConstant(A<int>(field1=IntConstant(87)))' }), | 188 const {}: 'ConstructedConstant(A<int>(field1=IntConstant(87)))' |
176 const ConstantData('const B()', | 189 }), |
177 const { const {} : | 190 const ConstantData('const B()', const { |
178 'ConstructedConstant(A<B<dynamic>>(field1=IntConstant(42)))' }), | 191 const {}: 'ConstructedConstant(A<B<dynamic>>(field1=IntConstant(42)))' |
179 const ConstantData('const B<int>()', | 192 }), |
180 const { const {} : | 193 const ConstantData('const B<int>()', const { |
181 'ConstructedConstant(A<B<int>>(field1=IntConstant(42)))' }), | 194 const {}: 'ConstructedConstant(A<B<int>>(field1=IntConstant(42)))' |
182 const ConstantData('const B<int>(field1: 87)', | 195 }), |
183 const { const {} : | 196 const ConstantData('const B<int>(field1: 87)', const { |
184 'ConstructedConstant(A<B<int>>(field1=IntConstant(87)))' }), | 197 const {}: 'ConstructedConstant(A<B<int>>(field1=IntConstant(87)))' |
185 const ConstantData('const C<int>(field1: 87)', | 198 }), |
186 const { const {} : | 199 const ConstantData('const C<int>(field1: 87)', const { |
187 'ConstructedConstant(A<B<double>>(field1=IntConstant(87)))' }), | 200 const {}: 'ConstructedConstant(A<B<double>>(field1=IntConstant(87)))' |
188 const ConstantData('const B<int>.named()', | 201 }), |
189 const { const {} : | 202 const ConstantData('const B<int>.named()', const { |
190 'ConstructedConstant(A<int>(field1=IntConstant(42)))' }), | 203 const {}: 'ConstructedConstant(A<int>(field1=IntConstant(42)))' |
191 ]), | 204 }), |
192 const TestData(''' | 205 ]), |
| 206 const TestData( |
| 207 ''' |
193 const c = const int.fromEnvironment("foo", defaultValue: 5); | 208 const c = const int.fromEnvironment("foo", defaultValue: 5); |
194 const d = const int.fromEnvironment("bar", defaultValue: 10); | 209 const d = const int.fromEnvironment("bar", defaultValue: 10); |
195 | 210 |
196 class A { | 211 class A { |
197 final field; | 212 final field; |
198 const A(a, b) : field = a + b; | 213 const A(a, b) : field = a + b; |
199 } | 214 } |
200 | 215 |
201 class B extends A { | 216 class B extends A { |
202 const B(a) : super(a, a * 2); | 217 const B(a) : super(a, a * 2); |
203 } | 218 } |
204 ''', const [ | 219 ''', |
205 const ConstantData('const A(c, d)', const { | 220 const [ |
206 const {} : | 221 const ConstantData('const A(c, d)', const { |
207 'ConstructedConstant(A(field=IntConstant(15)))', | 222 const {}: 'ConstructedConstant(A(field=IntConstant(15)))', |
208 const {'foo': '7', 'bar': '11'} : | 223 const {'foo': '7', 'bar': '11'}: |
209 'ConstructedConstant(A(field=IntConstant(18)))', }), | 224 'ConstructedConstant(A(field=IntConstant(18)))', |
210 const ConstantData('const B(d)', const { | 225 }), |
211 const {} : | 226 const ConstantData('const B(d)', const { |
212 'ConstructedConstant(B(field=IntConstant(30)))', | 227 const {}: 'ConstructedConstant(B(field=IntConstant(30)))', |
213 const {'bar': '42'} : | 228 const {'bar': '42'}: 'ConstructedConstant(B(field=IntConstant(126)))', |
214 'ConstructedConstant(B(field=IntConstant(126)))', }), | 229 }), |
215 ]), | 230 ]), |
216 ]; | 231 ]; |
217 | 232 |
218 main() { | 233 main() { |
219 asyncTest(() => Future.forEach(DATA, testData)); | 234 asyncTest(() => Future.forEach(DATA, testData)); |
220 } | 235 } |
221 | 236 |
222 Future testData(TestData data) async { | 237 Future testData(TestData data) async { |
223 StringBuffer sb = new StringBuffer(); | 238 StringBuffer sb = new StringBuffer(); |
224 sb.write('${data.declarations}\n'); | 239 sb.write('${data.declarations}\n'); |
225 Map constants = {}; | 240 Map constants = {}; |
226 data.constants.forEach((ConstantData constantData) { | 241 data.constants.forEach((ConstantData constantData) { |
227 String name = 'c${constants.length}'; | 242 String name = 'c${constants.length}'; |
228 sb.write('const $name = ${constantData.code};\n'); | 243 sb.write('const $name = ${constantData.code};\n'); |
229 constants[name] = constantData; | 244 constants[name] = constantData; |
230 }); | 245 }); |
231 sb.write('main() {}\n'); | 246 sb.write('main() {}\n'); |
232 String source = sb.toString(); | 247 String source = sb.toString(); |
233 CompilationResult result = await runCompiler( | 248 CompilationResult result = await runCompiler( |
234 memorySourceFiles: {'main.dart': source}, options: ['--analyze-all']); | 249 memorySourceFiles: {'main.dart': source}, options: ['--analyze-all']); |
235 Compiler compiler = result.compiler; | 250 Compiler compiler = result.compiler; |
236 var library = compiler.mainApp; | 251 var library = compiler.mainApp; |
237 constants.forEach((String name, ConstantData data) { | 252 constants.forEach((String name, ConstantData data) { |
238 FieldElement field = library.localLookup(name); | 253 FieldElement field = library.localLookup(name); |
239 ConstantExpression constant = field.constant; | 254 ConstantExpression constant = field.constant; |
240 data.expectedValues.forEach( | 255 data.expectedValues.forEach((Map<String, String> env, String expectedText) { |
241 (Map<String, String> env, String expectedText) { | |
242 Environment environment = new MemoryEnvironment(compiler, env); | 256 Environment environment = new MemoryEnvironment(compiler, env); |
243 ConstantValue value = | 257 ConstantValue value = |
244 constant.evaluate(environment, DART_CONSTANT_SYSTEM); | 258 constant.evaluate(environment, DART_CONSTANT_SYSTEM); |
245 String valueText = value.toStructuredText(); | 259 String valueText = value.toStructuredText(); |
246 Expect.equals(expectedText, valueText, | 260 Expect.equals( |
| 261 expectedText, |
| 262 valueText, |
247 "Unexpected value '${valueText}' for contant " | 263 "Unexpected value '${valueText}' for contant " |
248 "`${constant.toDartText()}`, expected '${expectedText}'."); | 264 "`${constant.toDartText()}`, expected '${expectedText}'."); |
249 }); | 265 }); |
250 }); | 266 }); |
251 } | 267 } |
OLD | NEW |