| // Copyright (c) 2014, 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'; |
| import "package:async_helper/async_helper.dart"; |
| import 'memory_compiler.dart'; |
| import 'compiler_helper.dart' show findElement; |
| |
| var SOURCES = const { |
| 'AddAll.dart': """ |
| var dictionaryA = {'string': "aString", 'int': 42, 'double': 21.5, |
| 'list': []}; |
| var dictionaryB = {'string': "aString", 'int': 42, 'double': 21.5, |
| 'list': []}; |
| var otherDict = {'stringTwo' : "anotherString", 'intTwo' : 84}; |
| var int = 0; |
| var anotherInt = 0; |
| var nullOrInt = 0; |
| var dynamic = 0; |
| |
| main() { |
| dictionaryA.addAll(otherDict); |
| dictionaryB.addAll({'stringTwo' : "anotherString", 'intTwo' : 84}); |
| int = dictionaryB['int']; |
| anotherInt = otherDict['intTwo']; |
| dynamic = dictionaryA['int']; |
| nullOrInt = dictionaryB['intTwo']; |
| } |
| """, |
| 'Union.dart': """ |
| var dictionaryA = {'string': "aString", 'int': 42, 'double': 21.5, |
| 'list': []}; |
| var dictionaryB = {'string': "aString", 'intTwo': 42, 'list': []}; |
| var nullOrInt = 0; |
| var aString = ""; |
| var doubleOrNull = 22.2; |
| var key = "string"; |
| |
| main() { |
| var union = dictionaryA['foo'] ? dictionaryA : dictionaryB; |
| nullOrInt = union['intTwo']; |
| aString = union['string']; |
| doubleOrNull = union['double']; |
| } |
| """, |
| 'ValueType.dart': """ |
| var dictionary = {'string': "aString", 'int': 42, 'double': 21.5, 'list': []}; |
| var keyD = 'double'; |
| var keyI = 'int'; |
| var keyN = 'notFoundInMap'; |
| var knownDouble = 42.2; |
| var intOrNull = dictionary[keyI]; |
| var justNull = dictionary[keyN]; |
| |
| main() { |
| knownDouble = dictionary[keyD]; |
| var x = [intOrNull, justNull]; |
| } |
| """, |
| 'Propagation.dart': """ |
| class A { |
| A(); |
| foo(value) { |
| return value['anInt']; |
| } |
| } |
| |
| class B { |
| B(); |
| foo(value) { |
| return 0; |
| } |
| } |
| |
| main() { |
| var dictionary = {'anInt': 42, 'aString': "theString"}; |
| var it; |
| if ([true, false][0]) { |
| it = new A(); |
| } else { |
| it = new B(); |
| } |
| print(it.foo(dictionary) + 2); |
| } |
| """, |
| 'Bailout.dart': """ |
| var dict = makeMap([1,2]); |
| var notInt = 0; |
| var alsoNotInt = 0; |
| |
| makeMap(values) { |
| return {'moo': values[0], 'boo': values[1]}; |
| } |
| |
| main () { |
| dict['goo'] = 42; |
| var closure = () => dict; |
| notInt = closure()['boo']; |
| alsoNotInt = dict['goo']; |
| print("\$notInt and \$alsoNotInt."); |
| } |
| """}; |
| |
| void main() { |
| asyncTest(() => |
| compileAndTest("AddAll.dart", (types, getType, compiler) { |
| Expect.equals(getType('int'), types.uint31Type); |
| Expect.equals(getType('anotherInt'), types.uint31Type); |
| Expect.equals(getType('dynamic'), types.dynamicType); |
| Expect.equals(getType('nullOrInt'), types.uint31Type.nullable()); |
| })); |
| asyncTest(() => compileAndTest("Union.dart", (types, getType, compiler) { |
| Expect.equals(getType('nullOrInt'), types.uint31Type.nullable()); |
| Expect.isTrue(getType('aString').containsOnlyString(compiler.world)); |
| Expect.equals(getType('doubleOrNull'), types.doubleType.nullable()); |
| })); |
| asyncTest(() => |
| compileAndTest("ValueType.dart", (types, getType, compiler) { |
| Expect.equals(getType('knownDouble'), types.doubleType); |
| Expect.equals(getType('intOrNull'), types.uint31Type.nullable()); |
| Expect.equals(getType('justNull'), types.nullType); |
| })); |
| asyncTest(() => compileAndTest("Propagation.dart", (code) { |
| Expect.isFalse(code.contains("J.\$add\$ns")); |
| }, createCode: true)); |
| asyncTest(() => compileAndTest("Bailout.dart", (types, getType, compiler) { |
| Expect.equals(getType('notInt'), types.dynamicType); |
| Expect.equals(getType('alsoNotInt'), types.dynamicType); |
| Expect.isFalse(getType('dict').isDictionary); |
| })); |
| } |
| |
| compileAndTest(source, checker, {createCode: false}) { |
| var compiler = compilerFor(SOURCES); |
| compiler.stopAfterTypeInference = !createCode; |
| var uri = Uri.parse('memory:'+source); |
| return compiler.runCompiler(uri).then((_) { |
| var typesTask = compiler.typesTask; |
| var typesInferrer = typesTask.typesInferrer; |
| getType(String name) { |
| var element = findElement(compiler, name); |
| return typesInferrer.getTypeOfElement(element); |
| } |
| if (!createCode) { |
| checker(typesTask, getType, compiler); |
| } else { |
| var element = compiler.mainApp.findExported('main'); |
| var code = compiler.backend.assembleCode(element); |
| checker(code); |
| } |
| }); |
| } |