| 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 |