├── testcases ├── .gitignore ├── input │ ├── static_setter.dart │ ├── void-methods.dart │ ├── closure.dart │ ├── fallthrough.dart │ ├── override.dart │ ├── bad_store.dart │ ├── argument.dart │ ├── arithmetic.dart │ ├── stringliteral.dart │ ├── null_aware.dart │ ├── external.dart │ ├── store_load.dart │ ├── escape.dart │ ├── uninitialized_fields.dart │ ├── prefer_baseclass.dart │ ├── async_function.dart │ ├── named_parameters.dart │ ├── redirecting_factory.dart │ ├── optional.dart │ ├── call.dart │ └── micro.dart ├── spec-mode │ ├── static_setter.baseline.txt │ ├── arithmetic.baseline.txt │ ├── external.baseline.txt │ ├── stringliteral.baseline.txt │ ├── void-methods.baseline.txt │ ├── bad_store.baseline.txt │ ├── closure.baseline.txt │ ├── fallthrough.baseline.txt │ ├── override.baseline.txt │ ├── store_load.baseline.txt │ ├── null_aware.baseline.txt │ ├── argument.baseline.txt │ ├── async_function.baseline.txt │ ├── uninitialized_fields.baseline.txt │ ├── prefer_baseclass.baseline.txt │ ├── named_parameters.baseline.txt │ ├── escape.baseline.txt │ ├── call.baseline.txt │ ├── redirecting_factory.baseline.txt │ ├── optional.baseline.txt │ └── micro.baseline.txt ├── strong-mode │ ├── static_setter.baseline.txt │ ├── arithmetic.baseline.txt │ ├── external.baseline.txt │ ├── stringliteral.baseline.txt │ ├── bad_store.baseline.txt │ ├── closure.baseline.txt │ ├── fallthrough.baseline.txt │ ├── void-methods.baseline.txt │ ├── override.baseline.txt │ ├── argument.baseline.txt │ ├── store_load.baseline.txt │ ├── async_function.baseline.txt │ ├── null_aware.baseline.txt │ ├── uninitialized_fields.baseline.txt │ ├── prefer_baseclass.baseline.txt │ ├── escape.baseline.txt │ ├── named_parameters.baseline.txt │ ├── redirecting_factory.baseline.txt │ ├── call.baseline.txt │ ├── optional.baseline.txt │ └── micro.baseline.txt └── type-propagation │ ├── static_setter.baseline.txt │ ├── external.baseline.txt │ ├── arithmetic.baseline.txt │ ├── stringliteral.baseline.txt │ ├── void-methods.baseline.txt │ ├── fallthrough.baseline.txt │ ├── closure.baseline.txt │ ├── bad_store.baseline.txt │ ├── override.baseline.txt │ ├── store_load.baseline.txt │ ├── argument.baseline.txt │ ├── async_function.baseline.txt │ ├── null_aware.baseline.txt │ ├── prefer_baseclass.baseline.txt │ ├── uninitialized_fields.baseline.txt │ ├── escape.baseline.txt │ ├── named_parameters.baseline.txt │ ├── redirecting_factory.baseline.txt │ ├── call.baseline.txt │ ├── optional.baseline.txt │ └── micro.baseline.txt ├── lib ├── analyzer │ ├── readme.md │ └── analyzer.dart ├── frontend │ ├── readme.md │ └── super_initializers.dart ├── target │ ├── readme.md │ ├── targets.dart │ ├── flutter.dart │ └── vm.dart ├── binary │ ├── readme.md │ ├── loader.dart │ └── tag.dart ├── text │ └── readme.md ├── log.dart ├── transformations │ ├── flags.dart │ ├── sanitize_for_vm.dart │ ├── infer_values.dart │ ├── setup_builtin_library.dart │ └── erasure.dart ├── kernel.dart ├── repository.dart ├── core_types.dart ├── type_propagation │ └── canonicalizer.dart ├── import_table.dart └── checks.dart ├── .gitignore ├── test ├── data │ ├── boms.dill │ ├── dart2js.dill │ ├── dart2js-strong.dill │ └── boms.dart ├── parent_pointer_test.dart ├── class_hierarchy_test.dart ├── round_trip_test.dart ├── baseline_spec_mode_test.dart ├── uint31_pair_map_test.dart ├── type_substitution_identity_test.dart ├── serialize_bench.dart ├── ast_membench.dart ├── type_hashcode_test.dart ├── baseline_type_propagation_test.dart ├── typecheck.dart ├── type_hashcode_quality.dart ├── treeshaker_check.dart ├── uint31_pair_map_bench.dart ├── class_hierarchy_membench.dart ├── treeshaker_membench.dart ├── baseline_strong_mode_test.dart ├── frontend_bench.dart ├── round_trip.dart ├── batch_consistency.dart ├── treeshaker_bench.dart ├── baseline_tester.dart ├── type_substitute_bounds_test.dart ├── treeshaker_stacktracer.dart └── treeshaker_dump.dart ├── .analysis_options ├── AUTHORS ├── codereview.settings ├── bin ├── dump.dart ├── batch_util.dart └── transform.dart ├── pubspec.yaml ├── LICENSE ├── README.md └── tool └── regenerate_dill_files.dart /testcases/.gitignore: -------------------------------------------------------------------------------- 1 | *.current.txt 2 | -------------------------------------------------------------------------------- /lib/analyzer/readme.md: -------------------------------------------------------------------------------- 1 | A frontend using the Dart analyzer. 2 | -------------------------------------------------------------------------------- /lib/frontend/readme.md: -------------------------------------------------------------------------------- 1 | Utility method to help the frontend generate kernel IR. 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .packages 2 | .pub 3 | packages 4 | pubspec.lock 5 | bin/dartk.snapshot 6 | -------------------------------------------------------------------------------- /test/data/boms.dill: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/kernel/master/test/data/boms.dill -------------------------------------------------------------------------------- /test/data/dart2js.dill: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/kernel/master/test/data/dart2js.dill -------------------------------------------------------------------------------- /.analysis_options: -------------------------------------------------------------------------------- 1 | analyzer: 2 | language: 3 | enableSuperMixins: true 4 | exclude: 5 | - testcases/** 6 | -------------------------------------------------------------------------------- /lib/target/readme.md: -------------------------------------------------------------------------------- 1 | Target configurations. 2 | 3 | A target can tailor the kernel IR for a specific backend. 4 | -------------------------------------------------------------------------------- /test/data/dart2js-strong.dill: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/kernel/master/test/data/dart2js-strong.dill -------------------------------------------------------------------------------- /lib/binary/readme.md: -------------------------------------------------------------------------------- 1 | Conversion to and from a binary format. 2 | 3 | The binary format is described in [binary.md](../../binary.md). 4 | -------------------------------------------------------------------------------- /testcases/input/static_setter.dart: -------------------------------------------------------------------------------- 1 | class Foo {} 2 | 3 | set foo(x) { 4 | 5 | } 6 | 7 | main() { 8 | foo = new Foo(); 9 | } 10 | -------------------------------------------------------------------------------- /lib/text/readme.md: -------------------------------------------------------------------------------- 1 | Conversion to a textual format. 2 | 3 | The text format is currently very ad-hoc and there is no conversion back, but 4 | it's a pleasant way to view the IR. 5 | -------------------------------------------------------------------------------- /test/data/boms.dart: -------------------------------------------------------------------------------- 1 | main() { 2 | print('\ufeff'); 3 | print('\ufeff\ufeff'); 4 | print('\ufeff\ufeff_'); 5 | print('\ufeff_\ufeff_'); 6 | print('_\ufeff_\ufeff_'); 7 | print('_\ufeff\ufeff_'); 8 | } 9 | -------------------------------------------------------------------------------- /testcases/input/void-methods.dart: -------------------------------------------------------------------------------- 1 | class Foo { 2 | List list = [1,2,3]; 3 | set first(x) => list[0] = x; 4 | operator[]=(x,y) => list[x] = y; 5 | void clear() => list.clear(); 6 | } 7 | 8 | main() { 9 | new Foo().first = 4; 10 | new Foo()[3] = 4; 11 | new Foo().clear(); 12 | } 13 | -------------------------------------------------------------------------------- /testcases/input/closure.dart: -------------------------------------------------------------------------------- 1 | class Foo { 2 | var _field = new Bar(); 3 | } 4 | 5 | class Bar {} 6 | 7 | useCallback(callback) { 8 | var _ = callback(); 9 | } 10 | 11 | main() { 12 | var x; 13 | inner() { 14 | x = new Foo(); 15 | return new Foo(); 16 | } 17 | useCallback(inner); 18 | var _ = inner()._field; 19 | } 20 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # Below is a list of people and organizations that have contributed 2 | # to the project. Names should be added to the list like so: 3 | # 4 | # Name/Organization 5 | 6 | Google Inc. 7 | 8 | Asger Feldthaus 9 | Martin Kustermann 10 | Kevin Millikin 11 | -------------------------------------------------------------------------------- /testcases/input/fallthrough.dart: -------------------------------------------------------------------------------- 1 | void main(List args) { 2 | var x = args.length; 3 | switch (x) { 4 | case 3: 5 | x = 4; 6 | case 5: 7 | break; 8 | case 6: 9 | case 7: 10 | if (args[0] == '') { 11 | break; 12 | } else { 13 | return; 14 | } 15 | case 4: 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /testcases/spec-mode/static_setter.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | } 10 | static set foo(dynamic x) → dynamic {} 11 | static method main() → dynamic { 12 | self::foo = new self::Foo::•(); 13 | } 14 | -------------------------------------------------------------------------------- /testcases/strong-mode/static_setter.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | } 10 | static set foo(dynamic x) → dynamic {} 11 | static method main() → dynamic { 12 | self::foo = new self::Foo::•(); 13 | } 14 | -------------------------------------------------------------------------------- /testcases/type-propagation/static_setter.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | } 10 | static set foo(dynamic/self::Foo! {other} x) → dynamic/Null {} 11 | static method main() → dynamic/Null { 12 | self::foo = new self::Foo::•(); 13 | } 14 | -------------------------------------------------------------------------------- /lib/log.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.log; 5 | 6 | import 'package:logging/logging.dart'; 7 | export 'package:logging/logging.dart'; 8 | 9 | final Logger log = new Logger("dart-kernel"); 10 | -------------------------------------------------------------------------------- /codereview.settings: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016, 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 | CODE_REVIEW_SERVER: http://codereview.chromium.org 5 | VIEW_VC: https://github.com/dart-lang/kernel/commit/ 6 | PROJECT: Dart Kernel 7 | CC_LIST: dart-kernel+reviews@google.com 8 | -------------------------------------------------------------------------------- /testcases/input/override.dart: -------------------------------------------------------------------------------- 1 | class Foo {} 2 | class Bar extends Foo {} 3 | 4 | class Base { 5 | Foo method() { 6 | return new Foo(); 7 | } 8 | } 9 | 10 | class Sub extends Base { 11 | Foo method() { 12 | return new Bar(); 13 | } 14 | } 15 | 16 | main(List args) { 17 | var object = args.length == 0 ? new Base() : new Sub(); 18 | var a = object.method(); 19 | print(a); 20 | } 21 | -------------------------------------------------------------------------------- /testcases/input/bad_store.dart: -------------------------------------------------------------------------------- 1 | class Foo { 2 | var field; 3 | } 4 | 5 | dynamic identity(x) => x; 6 | 7 | void use(x) {} 8 | 9 | main(List args) { 10 | dynamic foo = identity(new Foo()); 11 | if (args.length > 1) { 12 | foo.field = "string"; 13 | var first = foo.field; 14 | use(first); 15 | foo.noField = "string"; 16 | var second = foo.noField; 17 | use(second); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /bin/dump.dart: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env dart 2 | // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 3 | // for details. All rights reserved. Use of this source code is governed by a 4 | // BSD-style license that can be found in the LICENSE file. 5 | 6 | import 'package:kernel/kernel.dart'; 7 | 8 | main(args) { 9 | var binary = loadProgramFromBinary(args[0]); 10 | writeProgramToText(binary, path: args[1]); 11 | } 12 | -------------------------------------------------------------------------------- /test/parent_pointer_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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:kernel/kernel.dart'; 5 | import 'package:kernel/checks.dart'; 6 | 7 | main() { 8 | Program program = loadProgramFromBinary('test/data/dart2js.dill'); 9 | CheckParentPointers.check(program); 10 | } 11 | -------------------------------------------------------------------------------- /testcases/input/argument.dart: -------------------------------------------------------------------------------- 1 | abstract class Base {} 2 | 3 | class Foo extends Base {} 4 | class Bar extends Base {} 5 | class Baz extends Base {} 6 | 7 | void foo(x) { 8 | 9 | } 10 | 11 | void bar(x) { 12 | 13 | } 14 | 15 | void foo_escaped(x) { 16 | 17 | } 18 | 19 | void bar_escaped(x) { 20 | 21 | } 22 | 23 | void escape(fn) { 24 | fn(new Baz()); 25 | } 26 | 27 | main() { 28 | foo(new Foo()); 29 | bar(new Bar()); 30 | escape(foo_escaped); 31 | escape(bar_escaped); 32 | } 33 | -------------------------------------------------------------------------------- /testcases/spec-mode/arithmetic.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | static method foo(core::int x, core::int y) → core::int { 6 | dynamic z = x.+(y); 7 | return z.<<(4); 8 | } 9 | static method loop(core::List xs) → void { 10 | core::int _ = xs.length; 11 | for (core::int i = 0; i.<(xs.length); i = i.+(1)) { 12 | } 13 | } 14 | static method main() → dynamic { 15 | self::foo(4, 5); 16 | self::foo(6, 7); 17 | self::loop(["dfg"]); 18 | } 19 | -------------------------------------------------------------------------------- /testcases/input/arithmetic.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | int foo(int x, int y) { 5 | var z = x + y; 6 | return z << 4; 7 | } 8 | 9 | void loop(List xs) { 10 | int _ = xs.length; 11 | for (int i = 0; i < xs.length; i++) {} 12 | } 13 | 14 | main() { 15 | foo(4, 5); 16 | foo(6, 7); 17 | loop(['dfg']); 18 | } 19 | -------------------------------------------------------------------------------- /testcases/input/stringliteral.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | var color = 'brown'; 5 | var thing = 'lazy dog'; 6 | var phrase = "The quick $color fox\njumped over the $thing.\n"; 7 | var adjacent = '$color$color$color'; 8 | var linebreaks = '$color\n$color\n$color'; 9 | var other = '$color\n is \n$color'; 10 | 11 | main() {} 12 | -------------------------------------------------------------------------------- /testcases/spec-mode/external.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | import "dart:isolate" as iso; 5 | 6 | static field dynamic subscription = null; 7 | static method onData(dynamic x) → void { 8 | core::print(x); 9 | self::subscription.cancel(); 10 | } 11 | static method main() → dynamic { 12 | dynamic string = core::String::fromCharCode(65); 13 | dynamic port = iso::ReceivePort::•(); 14 | self::subscription = port.listen(self::onData); 15 | port.sendPort.send(string); 16 | } 17 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: kernel 2 | version: 0.2.0 3 | author: Dart Team 4 | description: Dart IR (Intermediate Representation) 5 | homepage: https://github.com/dart-lang/kernel 6 | environment: 7 | sdk: ">=1.8.0" 8 | dependencies: 9 | # We import some of the analyzer's internal files, so lock the patch version. 10 | analyzer: 0.29.0 11 | path: ^1.3.9 12 | args: ^0.13.4 13 | logging: ^0.11.2 14 | package_config: ^1.0.0 15 | dev_dependencies: 16 | test: ^0.12.15+6 17 | stack_trace: ^1.6.6 18 | ansicolor: ^0.0.9 19 | -------------------------------------------------------------------------------- /testcases/spec-mode/stringliteral.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | 4 | static field dynamic color = "brown"; 5 | static field dynamic thing = "lazy dog"; 6 | static field dynamic phrase = "The quick ${self::color} fox\njumped over the ${self::thing}.\n"; 7 | static field dynamic adjacent = "${self::color}${self::color}${self::color}"; 8 | static field dynamic linebreaks = "${self::color}\n${self::color}\n${self::color}"; 9 | static field dynamic other = "${self::color}\n is \n${self::color}"; 10 | static method main() → dynamic {} 11 | -------------------------------------------------------------------------------- /test/class_hierarchy_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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:kernel/kernel.dart'; 5 | import 'package:test/test.dart'; 6 | import 'class_hierarchy_tester.dart'; 7 | 8 | main() { 9 | test('All-pairs class hierarchy tests on dart2js', () { 10 | testClassHierarchyOnProgram( 11 | loadProgramFromBinary('test/data/dart2js.dill')); 12 | }); 13 | } 14 | -------------------------------------------------------------------------------- /testcases/strong-mode/arithmetic.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | static method foo(core::int x, core::int y) → core::int { 6 | core::int z = x.{core::num::+}(y); 7 | return z.{core::int::<<}(4); 8 | } 9 | static method loop(core::List xs) → void { 10 | core::int _ = xs.{core::List::length}; 11 | for (core::int i = 0; i.{core::num::<}(xs.{core::List::length}); i = i.{core::num::+}(1)) { 12 | } 13 | } 14 | static method main() → dynamic { 15 | self::foo(4, 5); 16 | self::foo(6, 7); 17 | self::loop(["dfg"]); 18 | } 19 | -------------------------------------------------------------------------------- /testcases/strong-mode/external.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | import "dart:isolate" as iso; 5 | 6 | static field dynamic subscription = null; 7 | static method onData(dynamic x) → void { 8 | core::print(x); 9 | self::subscription.cancel(); 10 | } 11 | static method main() → dynamic { 12 | core::String string = core::String::fromCharCode(65); 13 | iso::ReceivePort port = iso::ReceivePort::•(); 14 | self::subscription = port.{iso::ReceivePort::listen}(self::onData); 15 | port.{iso::ReceivePort::sendPort}.{iso::SendPort::send}(string); 16 | } 17 | -------------------------------------------------------------------------------- /testcases/input/null_aware.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | class Foo { 5 | int field; 6 | static int staticField; 7 | } 8 | 9 | main() { 10 | Foo foo = new Foo(); 11 | foo?.field = 5; 12 | Foo?.staticField = 5; 13 | foo.field ??= 5; 14 | Foo.staticField ??= 5; 15 | foo?.field ??= 5; 16 | Foo?.staticField ??= 5; 17 | 18 | int intValue = foo.field ?? 6; 19 | num numValue = foo.field ?? 4.5; 20 | } 21 | -------------------------------------------------------------------------------- /testcases/strong-mode/stringliteral.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | static field core::String color = "brown"; 6 | static field core::String thing = "lazy dog"; 7 | static field core::String phrase = "The quick ${self::color} fox\njumped over the ${self::thing}.\n"; 8 | static field core::String adjacent = "${self::color}${self::color}${self::color}"; 9 | static field core::String linebreaks = "${self::color}\n${self::color}\n${self::color}"; 10 | static field core::String other = "${self::color}\n is \n${self::color}"; 11 | static method main() → dynamic {} 12 | -------------------------------------------------------------------------------- /test/round_trip_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.round_trip_test; 5 | 6 | import 'package:test/test.dart'; 7 | import 'round_trip.dart' as cmd; 8 | 9 | void main() { 10 | test('dart2js', () { 11 | cmd.main(['test/data/dart2js.dill']); 12 | }); 13 | test('dart2js-strong', () { 14 | cmd.main(['test/data/dart2js-strong.dill']); 15 | }); 16 | test('boms', () { 17 | cmd.main(['test/data/boms.dill']); 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /testcases/input/external.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 'dart:isolate'; 5 | 6 | var subscription; 7 | 8 | void onData(x) { 9 | print(x); 10 | subscription.cancel(); 11 | } 12 | 13 | main() { 14 | var string = new String.fromCharCode(65); // External string factory. 15 | var port = new ReceivePort(); // External factory. 16 | subscription = port.listen(onData); // Dynamic call on external instance. 17 | port.sendPort.send(string); 18 | } 19 | -------------------------------------------------------------------------------- /testcases/spec-mode/void-methods.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | field core::List list = [1, 2, 3]; 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | set first(dynamic x) → dynamic 11 | this.list.[]=(0, x); 12 | operator []=(dynamic x, dynamic y) → dynamic 13 | this.list.[]=(x, y); 14 | method clear() → void 15 | return this.list.clear(); 16 | } 17 | static method main() → dynamic { 18 | new self::Foo::•().first = 4; 19 | new self::Foo::•().[]=(3, 4); 20 | new self::Foo::•().clear(); 21 | } 22 | -------------------------------------------------------------------------------- /testcases/type-propagation/external.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | import "dart:isolate" as iso; 5 | 6 | static field dynamic/dart.async::StreamSubscription* {null,other} subscription = null; 7 | static method onData(dynamic/core::Object* {*} x) → void/Null { 8 | core::print(x); 9 | self::subscription.cancel(); 10 | } 11 | static method main() → dynamic/Null { 12 | dynamic/core::String* {string} string = core::String::fromCharCode(65); 13 | dynamic/iso::ReceivePort* {other} port = iso::ReceivePort::•(); 14 | self::subscription = port.listen(self::onData); 15 | port.sendPort.send(string); 16 | } 17 | -------------------------------------------------------------------------------- /testcases/input/store_load.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | class Foo { 5 | var _field; 6 | } 7 | class FooValue {} 8 | 9 | class Bar { 10 | var _field; // Same name. 11 | } 12 | class BarValue {} 13 | 14 | main() { 15 | var foo = new Foo(); 16 | foo._field = new FooValue(); 17 | var fooValue = foo._field; 18 | print(fooValue); 19 | 20 | var bar = new Bar(); 21 | bar._field = new BarValue(); 22 | var barValue = bar._field; 23 | print(barValue); 24 | } 25 | -------------------------------------------------------------------------------- /testcases/type-propagation/arithmetic.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | static method foo(core::int/core::int* {int} x, core::int/core::int* {int} y) → core::int/core::int* {int} { 6 | dynamic/core::num* {int,double} z = x.+(y); 7 | return z.<<(4); 8 | } 9 | static method loop(core::List/core::List* {other} xs) → void/Null { 10 | core::int/core::int* {int} _ = xs.length; 11 | for (core::int/core::num* {int,double} i = 0; i.<(xs.length); i = i.+(1)) { 12 | } 13 | } 14 | static method main() → dynamic/Null { 15 | self::foo(4, 5); 16 | self::foo(6, 7); 17 | self::loop(["dfg"]); 18 | } 19 | -------------------------------------------------------------------------------- /lib/transformations/flags.dart: -------------------------------------------------------------------------------- 1 | library kernel.transformations.flags; 2 | 3 | import '../ast.dart'; 4 | 5 | /// Flags summarizing the kinds of AST nodes contained in a given member or 6 | /// class, for speeding up transformations that only affect certain types of 7 | /// nodes. 8 | /// 9 | /// These are set by the frontend and the deserializer. 10 | class TransformerFlag { 11 | /// The class or member contains 'super' calls, that is, one of the AST nodes 12 | /// [SuperPropertyGet], [SuperPropertySet], [SuperMethodInvocation]. 13 | static const int superCalls = 1 << 0; 14 | 15 | // TODO(asgerf): We could also add a flag for 'async' and will probably have 16 | // one for closures as well. 17 | } 18 | -------------------------------------------------------------------------------- /testcases/input/escape.dart: -------------------------------------------------------------------------------- 1 | class A { 2 | var field; 3 | } 4 | class B { 5 | var field; 6 | } 7 | class C { 8 | operator==(x) => false; 9 | } 10 | 11 | class X implements A, B { 12 | var field; 13 | } 14 | 15 | void useAsA(A object) { 16 | var _ = object.field; 17 | } 18 | 19 | void useAsB(B object) { 20 | var _ = object.field; 21 | escape(object); 22 | } 23 | 24 | void escape(x) { 25 | x ??= ""; 26 | x ??= 45; 27 | if (x is! int && x is! String) { 28 | x.field = 45; 29 | } 30 | } 31 | 32 | main() { 33 | // escape(""); 34 | // escape(45); 35 | 36 | var object = new X(); 37 | useAsA(new A()); 38 | useAsA(object); 39 | 40 | useAsB(new B()); 41 | useAsB(object); 42 | } 43 | -------------------------------------------------------------------------------- /testcases/spec-mode/bad_store.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | field dynamic field = null; 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | } 11 | static method identity(dynamic x) → dynamic 12 | return x; 13 | static method use(dynamic x) → void {} 14 | static method main(core::List args) → dynamic { 15 | dynamic foo = self::identity(new self::Foo::•()); 16 | if(args.length.>(1)) { 17 | foo.field = "string"; 18 | dynamic first = foo.field; 19 | self::use(first); 20 | foo.noField = "string"; 21 | dynamic second = foo.noField; 22 | self::use(second); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testcases/type-propagation/stringliteral.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | 4 | static field dynamic/dart.core::String* {string} color = "brown"; 5 | static field dynamic/dart.core::String* {string} thing = "lazy dog"; 6 | static field dynamic/dart.core::String* {string} phrase = "The quick ${self::color} fox\njumped over the ${self::thing}.\n"; 7 | static field dynamic/dart.core::String* {string} adjacent = "${self::color}${self::color}${self::color}"; 8 | static field dynamic/dart.core::String* {string} linebreaks = "${self::color}\n${self::color}\n${self::color}"; 9 | static field dynamic/dart.core::String* {string} other = "${self::color}\n is \n${self::color}"; 10 | static method main() → dynamic/Null {} 11 | -------------------------------------------------------------------------------- /testcases/spec-mode/closure.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | field dynamic _field = new self::Bar::•(); 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | } 11 | class Bar extends core::Object { 12 | constructor •() → void 13 | : super core::Object::•() 14 | ; 15 | } 16 | static method useCallback(dynamic callback) → dynamic { 17 | dynamic _ = callback.call(); 18 | } 19 | static method main() → dynamic { 20 | dynamic x; 21 | function inner() → dynamic { 22 | x = new self::Foo::•(); 23 | return new self::Foo::•(); 24 | } 25 | self::useCallback(inner); 26 | dynamic _ = inner.call()._field; 27 | } 28 | -------------------------------------------------------------------------------- /testcases/input/uninitialized_fields.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | class Uninitialized { 5 | int x; 6 | } 7 | class PartiallyInitialized { 8 | int x; 9 | PartiallyInitialized(this.x); 10 | PartiallyInitialized.noInitializer(); 11 | } 12 | class Initialized { 13 | int x; 14 | Initialized(this.x); 15 | } 16 | class Forwarding { 17 | int x; 18 | Forwarding.initialize(this.x); 19 | Forwarding(int arg) : this.initialize(arg); 20 | } 21 | 22 | int uninitializedTopLevel; 23 | int initializedTopLevel = 4; 24 | 25 | main() { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /testcases/type-propagation/void-methods.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | field core::List/core::List* {other} list = [1, 2, 3]; 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | set first(dynamic/core::int* {int} x) → dynamic/Null 11 | this.list.[]=(0, x); 12 | operator []=(dynamic/core::int* {int} x, dynamic/core::int* {int} y) → dynamic/Null 13 | this.list.[]=(x, y); 14 | method clear() → void/Null 15 | return this.list.clear(); 16 | } 17 | static method main() → dynamic/Null { 18 | new self::Foo::•().first = 4; 19 | new self::Foo::•().[]=(3, 4); 20 | new self::Foo::•().clear(); 21 | } 22 | -------------------------------------------------------------------------------- /testcases/input/prefer_baseclass.dart: -------------------------------------------------------------------------------- 1 | class A {} 2 | class B {} 3 | 4 | class AB1 extends A implements B {} 5 | class AB2 extends A implements B {} 6 | 7 | class BA1 extends B implements A {} 8 | class BA2 extends B implements A {} 9 | 10 | takeSubclassOfA(obj) { 11 | // The analysis should at least infer that 'obj' is a subclass of A, 12 | // When the upper bound is ambiguous, it should use the common superclass, if 13 | // there is one besides Object. 14 | } 15 | 16 | takeSubclassOfB(obj) { 17 | // Likewise, the analysis should infer that 'obj' is a subclass of B. 18 | } 19 | 20 | main() { 21 | takeSubclassOfA(new AB1()); 22 | takeSubclassOfA(new AB2()); 23 | 24 | takeSubclassOfB(new BA1()); 25 | takeSubclassOfB(new BA2()); 26 | } 27 | -------------------------------------------------------------------------------- /testcases/strong-mode/bad_store.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | field dynamic field = null; 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | } 11 | static method identity(dynamic x) → dynamic 12 | return x; 13 | static method use(dynamic x) → void {} 14 | static method main(core::List args) → dynamic { 15 | dynamic foo = self::identity(new self::Foo::•()); 16 | if(args.{core::List::length}.{core::num::>}(1)) { 17 | foo.field = "string"; 18 | dynamic first = foo.field; 19 | self::use(first); 20 | foo.noField = "string"; 21 | dynamic second = foo.noField; 22 | self::use(second); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /testcases/strong-mode/closure.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | field self::Bar _field = new self::Bar::•(); 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | } 11 | class Bar extends core::Object { 12 | constructor •() → void 13 | : super core::Object::•() 14 | ; 15 | } 16 | static method useCallback(dynamic callback) → dynamic { 17 | dynamic _ = callback.call(); 18 | } 19 | static method main() → dynamic { 20 | dynamic x; 21 | function inner() → dynamic { 22 | x = new self::Foo::•(); 23 | return new self::Foo::•(); 24 | } 25 | self::useCallback(inner); 26 | self::Bar _ = inner.call().{self::Foo::_field}; 27 | } 28 | -------------------------------------------------------------------------------- /lib/analyzer/analyzer.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | /// A library that re-exports the analyzer's program representation parts. 5 | library kernel.analyzer.frontend; 6 | 7 | export 'package:analyzer/dart/ast/visitor.dart'; 8 | export 'package:analyzer/dart/ast/ast.dart'; 9 | export 'package:analyzer/dart/element/element.dart'; 10 | export 'package:analyzer/dart/element/type.dart'; 11 | export 'package:analyzer/src/generated/utilities_dart.dart' show ParameterKind; 12 | export 'package:analyzer/src/dart/element/member.dart' show Member; 13 | export 'package:analyzer/dart/ast/token.dart' show Token; 14 | -------------------------------------------------------------------------------- /testcases/spec-mode/fallthrough.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | static method main(core::List args) → void { 6 | dynamic x = args.length; 7 | #L1: 8 | switch(x) { 9 | #L2: 10 | case 3: 11 | { 12 | x = 4; 13 | throw new core::FallThroughError::•(); 14 | } 15 | #L3: 16 | case 5: 17 | { 18 | break #L1; 19 | } 20 | #L4: 21 | case 6: 22 | case 7: 23 | { 24 | if(args.[](0).==("")) { 25 | break #L1; 26 | } 27 | else { 28 | return; 29 | } 30 | throw new core::FallThroughError::•(); 31 | } 32 | #L5: 33 | case 4: 34 | { 35 | break #L1; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /testcases/type-propagation/fallthrough.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | static method main(core::List/Nothing args) → void/Null { 6 | dynamic/core::int* {int} x = args.length; 7 | #L1: 8 | switch(x) { 9 | #L2: 10 | case 3: 11 | { 12 | x = 4; 13 | throw new core::FallThroughError::•(); 14 | } 15 | #L3: 16 | case 5: 17 | { 18 | break #L1; 19 | } 20 | #L4: 21 | case 6: 22 | case 7: 23 | { 24 | if(args.[](0).==("")) { 25 | break #L1; 26 | } 27 | else { 28 | return; 29 | } 30 | throw new core::FallThroughError::•(); 31 | } 32 | #L5: 33 | case 4: 34 | { 35 | break #L1; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /testcases/strong-mode/fallthrough.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | static method main(core::List args) → void { 6 | core::int x = args.{core::List::length}; 7 | #L1: 8 | switch(x) { 9 | #L2: 10 | case 3: 11 | { 12 | x = 4; 13 | throw new core::FallThroughError::•(); 14 | } 15 | #L3: 16 | case 5: 17 | { 18 | break #L1; 19 | } 20 | #L4: 21 | case 6: 22 | case 7: 23 | { 24 | if(args.{core::List::[]}(0).{core::String::==}("")) { 25 | break #L1; 26 | } 27 | else { 28 | return; 29 | } 30 | throw new core::FallThroughError::•(); 31 | } 32 | #L5: 33 | case 4: 34 | { 35 | break #L1; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /testcases/strong-mode/void-methods.baseline.txt: -------------------------------------------------------------------------------- 1 | // dynamic is not a subtype of dart.core::int (void-methods.dart:4:27) 2 | library; 3 | import self as self; 4 | import "dart:core" as core; 5 | 6 | class Foo extends core::Object { 7 | field core::List list = [1, 2, 3]; 8 | constructor •() → void 9 | : super core::Object::•() 10 | ; 11 | set first(dynamic x) → void 12 | this.{self::Foo::list}.{core::List::[]=}(0, x); 13 | operator []=(dynamic x, dynamic y) → dynamic 14 | this.{self::Foo::list}.{core::List::[]=}(x, y); 15 | method clear() → void 16 | this.{self::Foo::list}.{core::List::clear}(); 17 | } 18 | static method main() → dynamic { 19 | new self::Foo::•().{self::Foo::first} = 4; 20 | new self::Foo::•().{self::Foo::[]=}(3, 4); 21 | new self::Foo::•().{self::Foo::clear}(); 22 | } 23 | -------------------------------------------------------------------------------- /testcases/type-propagation/closure.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | field dynamic/self::Bar! {other} _field = new self::Bar::•(); 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | } 11 | class Bar extends core::Object { 12 | constructor •() → void 13 | : super core::Object::•() 14 | ; 15 | } 16 | static method useCallback(dynamic/core::Function* {other} callback) → dynamic/Null { 17 | dynamic/self::Foo! {other} _ = callback.call(); 18 | } 19 | static method main() → dynamic/Null { 20 | dynamic/self::Foo! {null,other} x; 21 | function inner() → dynamic/self::Foo! {other} { 22 | x = new self::Foo::•(); 23 | return new self::Foo::•(); 24 | } 25 | self::useCallback(inner); 26 | dynamic/self::Bar! {other} _ = inner.call()._field; 27 | } 28 | -------------------------------------------------------------------------------- /testcases/type-propagation/bad_store.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | field dynamic/core::String* {null,string} field = null; 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | } 11 | static method identity(dynamic/self::Foo! {other} x) → dynamic/self::Foo! {other} 12 | return x; 13 | static method use(dynamic/core::String* {null,string} x) → void/Null {} 14 | static method main(core::List/Nothing args) → dynamic/Null { 15 | dynamic/self::Foo! {other} foo = self::identity(new self::Foo::•()); 16 | if(args.length.>(1)) { 17 | foo.field = "string"; 18 | dynamic/core::String* {null,string} first = foo.field; 19 | self::use(first); 20 | foo.noField = "string"; 21 | dynamic/Nothing second = foo.noField; 22 | self::use(second); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/baseline_spec_mode_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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:kernel/kernel.dart'; 5 | import 'package:kernel/transformations/mixin_full_resolution.dart'; 6 | 7 | import 'baseline_tester.dart'; 8 | 9 | class SpecModeTest extends TestTarget { 10 | @override 11 | List get extraRequiredLibraries => []; 12 | 13 | @override 14 | String get name => 'spec-mode-test'; 15 | 16 | @override 17 | bool get strongMode => false; 18 | 19 | @override 20 | List transformProgram(Program program) { 21 | new MixinFullResolution().transform(program); 22 | return const []; 23 | } 24 | } 25 | 26 | void main() { 27 | runBaselineTests('spec-mode', new SpecModeTest()); 28 | } 29 | -------------------------------------------------------------------------------- /lib/transformations/sanitize_for_vm.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.transformations.fixvm; 5 | 6 | import '../ast.dart'; 7 | 8 | /// Ensures that classes all have either a constructor or a procedure. 9 | /// 10 | /// VM-specific constraints that don't fit in anywhere else can be put here. 11 | class SanitizeForVM { 12 | void transform(Program program) { 13 | for (var library in program.libraries) { 14 | for (var class_ in library.classes) { 15 | if (class_.constructors.isEmpty && class_.procedures.isEmpty) { 16 | class_.addMember(new Constructor( 17 | new FunctionNode(new InvalidStatement()), 18 | name: new Name(''))); 19 | } 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /testcases/spec-mode/override.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | } 10 | class Bar extends self::Foo { 11 | constructor •() → void 12 | : super self::Foo::•() 13 | ; 14 | } 15 | class Base extends core::Object { 16 | constructor •() → void 17 | : super core::Object::•() 18 | ; 19 | method method() → self::Foo { 20 | return new self::Foo::•(); 21 | } 22 | } 23 | class Sub extends self::Base { 24 | constructor •() → void 25 | : super self::Base::•() 26 | ; 27 | method method() → self::Foo { 28 | return new self::Bar::•(); 29 | } 30 | } 31 | static method main(core::List args) → dynamic { 32 | dynamic object = args.length.==(0) ? new self::Base::•() : new self::Sub::•(); 33 | dynamic a = object.method(); 34 | core::print(a); 35 | } 36 | -------------------------------------------------------------------------------- /testcases/input/async_function.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 'dart:async'; 5 | 6 | Future asyncString() async { 7 | return "foo"; 8 | } 9 | 10 | Future asyncString2() async { 11 | return asyncString(); 12 | } 13 | 14 | Iterable syncStarString() sync* { 15 | yield "foo"; 16 | yield* syncStarString2(); 17 | yield* stringList; 18 | } 19 | 20 | Iterable syncStarString2() sync* { 21 | yield "foo"; 22 | } 23 | 24 | Stream asyncStarString() async* { 25 | yield "foo"; 26 | yield* asyncStarString2(); 27 | yield await asyncString(); 28 | } 29 | 30 | Stream asyncStarString2() async* { 31 | yield "bar"; 32 | } 33 | 34 | List stringList = ["bar"]; 35 | 36 | main() async { 37 | String str = await asyncString(); 38 | } 39 | -------------------------------------------------------------------------------- /testcases/input/named_parameters.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | class Superclass { 5 | foo({alpha, beta}) {} 6 | bar({beta, alpha}) {} 7 | 8 | namedCallback(callback({String alpha, int beta})) { 9 | callback(alpha: 'one', beta: 2); 10 | callback(beta: 1, alpha: 'two'); 11 | } 12 | } 13 | 14 | class Subclass extends Superclass { 15 | foo({beta, alpha}) {} 16 | bar({alpha, beta}) {} 17 | 18 | namedCallback(callback({int beta, String alpha})) {} 19 | } 20 | 21 | topLevelNamed(beta, alpha, {gamma, delta}) {} 22 | topLevelOptional(beta, alpha, [gamma, delta]) {} 23 | 24 | main() { 25 | new Subclass().foo(beta: 1, alpha: 2); 26 | new Subclass().foo(alpha: 1, beta: 2); 27 | topLevelNamed(1, 2, gamma: 3, delta: 4); 28 | topLevelNamed(1, 2, delta: 3, gamma: 4); 29 | } 30 | -------------------------------------------------------------------------------- /testcases/input/redirecting_factory.dart: -------------------------------------------------------------------------------- 1 | abstract class FooBase { 2 | int get x; 3 | factory FooBase(int x) = Foo; 4 | } 5 | 6 | abstract class Foo implements FooBase { 7 | factory Foo(int x) = Bar; 8 | } 9 | 10 | class Bar implements Foo { 11 | int x; 12 | Bar(this.x) { 13 | print('Bar<$Sb,$Tb>'); 14 | } 15 | } 16 | 17 | class Builder { 18 | method() { 19 | return new FooBase(4); 20 | } 21 | } 22 | 23 | class SimpleCase { 24 | factory SimpleCase() = SimpleCaseImpl; 25 | } 26 | 27 | class SimpleCaseImpl implements SimpleCase { 28 | factory SimpleCaseImpl() = SimpleCaseImpl2; 29 | } 30 | 31 | class SimpleCaseImpl2 implements SimpleCaseImpl { 32 | } 33 | 34 | class Base { 35 | 36 | } 37 | class Mixin { 38 | 39 | } 40 | 41 | class Mix = Base with Mixin; 42 | 43 | main() { 44 | print(new FooBase(4).x); 45 | new SimpleCase(); 46 | new Mix(); 47 | } 48 | -------------------------------------------------------------------------------- /testcases/strong-mode/override.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | } 10 | class Bar extends self::Foo { 11 | constructor •() → void 12 | : super self::Foo::•() 13 | ; 14 | } 15 | class Base extends core::Object { 16 | constructor •() → void 17 | : super core::Object::•() 18 | ; 19 | method method() → self::Foo { 20 | return new self::Foo::•(); 21 | } 22 | } 23 | class Sub extends self::Base { 24 | constructor •() → void 25 | : super self::Base::•() 26 | ; 27 | method method() → self::Foo { 28 | return new self::Bar::•(); 29 | } 30 | } 31 | static method main(core::List args) → dynamic { 32 | self::Base object = args.{core::List::length}.{core::num::==}(0) ? new self::Base::•() : new self::Sub::•(); 33 | self::Foo a = object.{self::Base::method}(); 34 | core::print(a); 35 | } 36 | -------------------------------------------------------------------------------- /testcases/spec-mode/store_load.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | field dynamic _field = null; 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | } 11 | class FooValue extends core::Object { 12 | constructor •() → void 13 | : super core::Object::•() 14 | ; 15 | } 16 | class Bar extends core::Object { 17 | field dynamic _field = null; 18 | constructor •() → void 19 | : super core::Object::•() 20 | ; 21 | } 22 | class BarValue extends core::Object { 23 | constructor •() → void 24 | : super core::Object::•() 25 | ; 26 | } 27 | static method main() → dynamic { 28 | dynamic foo = new self::Foo::•(); 29 | foo._field = new self::FooValue::•(); 30 | dynamic fooValue = foo._field; 31 | core::print(fooValue); 32 | dynamic bar = new self::Bar::•(); 33 | bar._field = new self::BarValue::•(); 34 | dynamic barValue = bar._field; 35 | core::print(barValue); 36 | } 37 | -------------------------------------------------------------------------------- /testcases/spec-mode/null_aware.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | field core::int field = null; 7 | static field core::int staticField = null; 8 | constructor •() → void 9 | : super core::Object::•() 10 | ; 11 | } 12 | static method main() → dynamic { 13 | self::Foo foo = new self::Foo::•(); 14 | let final dynamic #t1 = foo in #t1.==(null) ? null : #t1.field = 5; 15 | self::Foo::staticField = 5; 16 | let final dynamic #t2 = foo in #t2.field.==(null) ? #t2.field = 5 : null; 17 | self::Foo::staticField.==(null) ? self::Foo::staticField = 5 : null; 18 | let final dynamic #t3 = foo in #t3.==(null) ? null : #t3.field.==(null) ? #t3.field = 5 : null; 19 | self::Foo::staticField.==(null) ? self::Foo::staticField = 5 : null; 20 | core::int intValue = let final dynamic #t4 = foo.field in #t4.==(null) ? 6 : #t4; 21 | core::num numValue = let final dynamic #t5 = foo.field in #t5.==(null) ? 4.5 : #t5; 22 | } 23 | -------------------------------------------------------------------------------- /testcases/type-propagation/override.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | } 10 | class Bar extends self::Foo { 11 | constructor •() → void 12 | : super self::Foo::•() 13 | ; 14 | } 15 | class Base extends core::Object { 16 | constructor •() → void 17 | : super core::Object::•() 18 | ; 19 | method method() → self::Foo/self::Foo! {other} { 20 | return new self::Foo::•(); 21 | } 22 | } 23 | class Sub extends self::Base { 24 | constructor •() → void 25 | : super self::Base::•() 26 | ; 27 | method method() → self::Foo/self::Bar! {other} { 28 | return new self::Bar::•(); 29 | } 30 | } 31 | static method main(core::List/Nothing args) → dynamic/Null { 32 | dynamic/self::Base+ {other} object = args.length.==(0) ? new self::Base::•() : new self::Sub::•(); 33 | dynamic/self::Foo+ {other} a = object.method(); 34 | core::print(a); 35 | } 36 | -------------------------------------------------------------------------------- /testcases/spec-mode/argument.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | abstract class Base extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | } 10 | class Foo extends self::Base { 11 | constructor •() → void 12 | : super self::Base::•() 13 | ; 14 | } 15 | class Bar extends self::Base { 16 | constructor •() → void 17 | : super self::Base::•() 18 | ; 19 | } 20 | class Baz extends self::Base { 21 | constructor •() → void 22 | : super self::Base::•() 23 | ; 24 | } 25 | static method foo(dynamic x) → void {} 26 | static method bar(dynamic x) → void {} 27 | static method foo_escaped(dynamic x) → void {} 28 | static method bar_escaped(dynamic x) → void {} 29 | static method escape(dynamic fn) → void { 30 | fn.call(new self::Baz::•()); 31 | } 32 | static method main() → dynamic { 33 | self::foo(new self::Foo::•()); 34 | self::bar(new self::Bar::•()); 35 | self::escape(self::foo_escaped); 36 | self::escape(self::bar_escaped); 37 | } 38 | -------------------------------------------------------------------------------- /testcases/strong-mode/argument.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | abstract class Base extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | } 10 | class Foo extends self::Base { 11 | constructor •() → void 12 | : super self::Base::•() 13 | ; 14 | } 15 | class Bar extends self::Base { 16 | constructor •() → void 17 | : super self::Base::•() 18 | ; 19 | } 20 | class Baz extends self::Base { 21 | constructor •() → void 22 | : super self::Base::•() 23 | ; 24 | } 25 | static method foo(dynamic x) → void {} 26 | static method bar(dynamic x) → void {} 27 | static method foo_escaped(dynamic x) → void {} 28 | static method bar_escaped(dynamic x) → void {} 29 | static method escape(dynamic fn) → void { 30 | fn.call(new self::Baz::•()); 31 | } 32 | static method main() → dynamic { 33 | self::foo(new self::Foo::•()); 34 | self::bar(new self::Bar::•()); 35 | self::escape(self::foo_escaped); 36 | self::escape(self::bar_escaped); 37 | } 38 | -------------------------------------------------------------------------------- /testcases/strong-mode/store_load.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | field dynamic _field = null; 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | } 11 | class FooValue extends core::Object { 12 | constructor •() → void 13 | : super core::Object::•() 14 | ; 15 | } 16 | class Bar extends core::Object { 17 | field dynamic _field = null; 18 | constructor •() → void 19 | : super core::Object::•() 20 | ; 21 | } 22 | class BarValue extends core::Object { 23 | constructor •() → void 24 | : super core::Object::•() 25 | ; 26 | } 27 | static method main() → dynamic { 28 | self::Foo foo = new self::Foo::•(); 29 | foo.{self::Foo::_field} = new self::FooValue::•(); 30 | dynamic fooValue = foo.{self::Foo::_field}; 31 | core::print(fooValue); 32 | self::Bar bar = new self::Bar::•(); 33 | bar.{self::Bar::_field} = new self::BarValue::•(); 34 | dynamic barValue = bar.{self::Bar::_field}; 35 | core::print(barValue); 36 | } 37 | -------------------------------------------------------------------------------- /testcases/spec-mode/async_function.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:async" as asy; 4 | import "dart:core" as core; 5 | 6 | static field core::List stringList = ["bar"]; 7 | static method asyncString() → asy::Future async { 8 | return "foo"; 9 | } 10 | static method asyncString2() → asy::Future async { 11 | return self::asyncString(); 12 | } 13 | static method syncStarString() → core::Iterable sync* { 14 | yield "foo"; 15 | yield* self::syncStarString2(); 16 | yield* self::stringList; 17 | } 18 | static method syncStarString2() → core::Iterable sync* { 19 | yield "foo"; 20 | } 21 | static method asyncStarString() → asy::Stream async* { 22 | yield "foo"; 23 | yield* self::asyncStarString2(); 24 | yield await self::asyncString(); 25 | } 26 | static method asyncStarString2() → asy::Stream async* { 27 | yield "bar"; 28 | } 29 | static method main() → dynamic async { 30 | core::String str = await self::asyncString(); 31 | } 32 | -------------------------------------------------------------------------------- /testcases/strong-mode/async_function.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:async" as asy; 4 | import "dart:core" as core; 5 | 6 | static field core::List stringList = ["bar"]; 7 | static method asyncString() → asy::Future async { 8 | return "foo"; 9 | } 10 | static method asyncString2() → asy::Future async { 11 | return self::asyncString(); 12 | } 13 | static method syncStarString() → core::Iterable sync* { 14 | yield "foo"; 15 | yield* self::syncStarString2(); 16 | yield* self::stringList; 17 | } 18 | static method syncStarString2() → core::Iterable sync* { 19 | yield "foo"; 20 | } 21 | static method asyncStarString() → asy::Stream async* { 22 | yield "foo"; 23 | yield* self::asyncStarString2(); 24 | yield await self::asyncString(); 25 | } 26 | static method asyncStarString2() → asy::Stream async* { 27 | yield "bar"; 28 | } 29 | static method main() → dynamic async { 30 | core::String str = await self::asyncString(); 31 | } 32 | -------------------------------------------------------------------------------- /testcases/strong-mode/null_aware.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | field core::int field = null; 7 | static field core::int staticField = null; 8 | constructor •() → void 9 | : super core::Object::•() 10 | ; 11 | } 12 | static method main() → dynamic { 13 | self::Foo foo = new self::Foo::•(); 14 | let final self::Foo #t1 = foo in #t1.==(null) ? null : #t1.{self::Foo::field} = 5; 15 | self::Foo::staticField = 5; 16 | let final self::Foo #t2 = foo in #t2.{self::Foo::field}.==(null) ? #t2.{self::Foo::field} = 5 : null; 17 | self::Foo::staticField.==(null) ? self::Foo::staticField = 5 : null; 18 | let final self::Foo #t3 = foo in #t3.==(null) ? null : #t3.{self::Foo::field}.==(null) ? #t3.{self::Foo::field} = 5 : null; 19 | self::Foo::staticField.==(null) ? self::Foo::staticField = 5 : null; 20 | core::int intValue = let final core::int #t4 = foo.{self::Foo::field} in #t4.==(null) ? 6 : #t4; 21 | core::num numValue = let final core::int #t5 = foo.{self::Foo::field} in #t5.==(null) ? 4.5 : #t5; 22 | } 23 | -------------------------------------------------------------------------------- /test/uint31_pair_map_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'package:kernel/type_propagation/canonicalizer.dart'; 3 | import 'package:test/test.dart'; 4 | 5 | Random random = new Random(12345); 6 | 7 | main() { 8 | test('Uint31PairMap randomized tests', runTest); 9 | } 10 | 11 | runTest() { 12 | const int trials = 1000; 13 | const int insertions = 1000; 14 | const int uniqueKeys = 900; 15 | for (int trial = 0; trial < trials; ++trial) { 16 | int nextValue = 1; 17 | Map, int> trusted = , int>{}; 18 | Uint31PairMap candidate = new Uint31PairMap(); 19 | for (int i = 0; i < insertions; ++i) { 20 | int x = random.nextInt(uniqueKeys); 21 | int y = random.nextInt(uniqueKeys); 22 | Point key = new Point(x, y); 23 | int trustedValue = trusted[key]; 24 | int candidateValue = candidate.lookup(x, y); 25 | expect(candidateValue, equals(trustedValue)); 26 | if (trustedValue == null) { 27 | int newValue = nextValue++; 28 | trusted[key] = newValue; 29 | candidate.put(newValue); 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /testcases/type-propagation/store_load.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | field dynamic/self::FooValue! {null,other} _field = null; 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | } 11 | class FooValue extends core::Object { 12 | constructor •() → void 13 | : super core::Object::•() 14 | ; 15 | } 16 | class Bar extends core::Object { 17 | field dynamic/self::BarValue! {null,other} _field = null; 18 | constructor •() → void 19 | : super core::Object::•() 20 | ; 21 | } 22 | class BarValue extends core::Object { 23 | constructor •() → void 24 | : super core::Object::•() 25 | ; 26 | } 27 | static method main() → dynamic/Null { 28 | dynamic/self::Foo! {other} foo = new self::Foo::•(); 29 | foo._field = new self::FooValue::•(); 30 | dynamic/self::FooValue! {null,other} fooValue = foo._field; 31 | core::print(fooValue); 32 | dynamic/self::Bar! {other} bar = new self::Bar::•(); 33 | bar._field = new self::BarValue::•(); 34 | dynamic/self::BarValue! {null,other} barValue = bar._field; 35 | core::print(barValue); 36 | } 37 | -------------------------------------------------------------------------------- /test/type_substitution_identity_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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:kernel/kernel.dart'; 5 | import 'package:kernel/type_algebra.dart'; 6 | import 'type_parser.dart'; 7 | import 'type_unification_test.dart' show testCases; 8 | import 'package:test/test.dart'; 9 | 10 | checkType(DartType type) { 11 | var map = {new TypeParameter(): const DynamicType()}; 12 | var other = substitute(type, map); 13 | if (!identical(type, other)) { 14 | fail('Identity substitution test failed for $type'); 15 | } 16 | other = Substitution.fromUpperAndLowerBounds(map, map).substituteType(type); 17 | if (!identical(type, other)) { 18 | fail('Identity bounded substitution test failed for $type'); 19 | } 20 | } 21 | 22 | main() { 23 | for (var testCase in testCases) { 24 | test('$testCase', () { 25 | var env = new LazyTypeEnvironment(); 26 | checkType(env.parse(testCase.type1)); 27 | checkType(env.parse(testCase.type2)); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /testcases/type-propagation/argument.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | abstract class Base extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | } 10 | class Foo extends self::Base { 11 | constructor •() → void 12 | : super self::Base::•() 13 | ; 14 | } 15 | class Bar extends self::Base { 16 | constructor •() → void 17 | : super self::Base::•() 18 | ; 19 | } 20 | class Baz extends self::Base { 21 | constructor •() → void 22 | : super self::Base::•() 23 | ; 24 | } 25 | static method foo(dynamic/self::Foo! {other} x) → void/Null {} 26 | static method bar(dynamic/self::Bar! {other} x) → void/Null {} 27 | static method foo_escaped(dynamic/core::Object+ {*} x) → void/Null {} 28 | static method bar_escaped(dynamic/core::Object+ {*} x) → void/Null {} 29 | static method escape(dynamic/core::Function* {other} fn) → void/Null { 30 | fn.call(new self::Baz::•()); 31 | } 32 | static method main() → dynamic/Null { 33 | self::foo(new self::Foo::•()); 34 | self::bar(new self::Bar::•()); 35 | self::escape(self::foo_escaped); 36 | self::escape(self::bar_escaped); 37 | } 38 | -------------------------------------------------------------------------------- /testcases/type-propagation/async_function.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:async" as asy; 4 | import "dart:core" as core; 5 | 6 | static field core::List/core::List* {other} stringList = ["bar"]; 7 | static method asyncString() → asy::Future/core::String* {string} async { 8 | return "foo"; 9 | } 10 | static method asyncString2() → asy::Future/core::String* {string} async { 11 | return self::asyncString(); 12 | } 13 | static method syncStarString() → core::Iterable/Null sync* { 14 | yield "foo"; 15 | yield* self::syncStarString2(); 16 | yield* self::stringList; 17 | } 18 | static method syncStarString2() → core::Iterable/Null sync* { 19 | yield "foo"; 20 | } 21 | static method asyncStarString() → asy::Stream/Null async* { 22 | yield "foo"; 23 | yield* self::asyncStarString2(); 24 | yield await self::asyncString(); 25 | } 26 | static method asyncStarString2() → asy::Stream/Null async* { 27 | yield "bar"; 28 | } 29 | static method main() → dynamic/Null async { 30 | core::String/core::Object* {*} str = await self::asyncString(); 31 | } 32 | -------------------------------------------------------------------------------- /test/serialize_bench.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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:kernel/kernel.dart'; 5 | import 'dart:io'; 6 | 7 | final String usage = ''' 8 | Usage: serialize_bench INPUT.dill OUTPUT.dill 9 | 10 | Deserialize INPUT and write it back to OUTPUT several times, measuring 11 | the time it takes, including I/O time. 12 | '''; 13 | 14 | main(List args) async { 15 | if (args.length != 2) { 16 | print(usage); 17 | exit(1); 18 | } 19 | Program program = loadProgramFromBinary(args[0]); 20 | 21 | String destination = args[1]; 22 | var watch = new Stopwatch()..start(); 23 | await writeProgramToBinary(program, destination); 24 | int coldTime = watch.elapsedMilliseconds; 25 | 26 | watch.reset(); 27 | int numTrials = 10; 28 | for (int i = 0; i < numTrials; ++i) { 29 | await writeProgramToBinary(program, destination); 30 | } 31 | double hotTime = watch.elapsedMilliseconds / numTrials; 32 | 33 | print('Cold time: $coldTime ms'); 34 | print('Hot time: $hotTime ms'); 35 | } 36 | -------------------------------------------------------------------------------- /testcases/spec-mode/uninitialized_fields.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Uninitialized extends core::Object { 6 | field core::int x = null; 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | } 11 | class PartiallyInitialized extends core::Object { 12 | field core::int x = null; 13 | constructor •(core::int x) → void 14 | : self::PartiallyInitialized::x = x, super core::Object::•() 15 | ; 16 | constructor noInitializer() → void 17 | : super core::Object::•() 18 | ; 19 | } 20 | class Initialized extends core::Object { 21 | field core::int x; 22 | constructor •(core::int x) → void 23 | : self::Initialized::x = x, super core::Object::•() 24 | ; 25 | } 26 | class Forwarding extends core::Object { 27 | field core::int x; 28 | constructor initialize(core::int x) → void 29 | : self::Forwarding::x = x, super core::Object::•() 30 | ; 31 | constructor •(core::int arg) → void 32 | : this self::Forwarding::initialize(arg) 33 | ; 34 | } 35 | static field core::int uninitializedTopLevel = null; 36 | static field core::int initializedTopLevel = 4; 37 | static method main() → dynamic {} 38 | -------------------------------------------------------------------------------- /testcases/type-propagation/null_aware.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | field core::int/core::int* {null,int} field = null; 7 | static field core::int/core::int* {null,int} staticField = null; 8 | constructor •() → void 9 | : super core::Object::•() 10 | ; 11 | } 12 | static method main() → dynamic/Null { 13 | self::Foo/self::Foo! {other} foo = new self::Foo::•(); 14 | let final dynamic/ #t1 = foo in #t1.==(null) ? null : #t1.field = 5; 15 | self::Foo::staticField = 5; 16 | let final dynamic/ #t2 = foo in #t2.field.==(null) ? #t2.field = 5 : null; 17 | self::Foo::staticField.==(null) ? self::Foo::staticField = 5 : null; 18 | let final dynamic/ #t3 = foo in #t3.==(null) ? null : #t3.field.==(null) ? #t3.field = 5 : null; 19 | self::Foo::staticField.==(null) ? self::Foo::staticField = 5 : null; 20 | core::int/core::int* {null,int} intValue = let final dynamic/ #t4 = foo.field in #t4.==(null) ? 6 : #t4; 21 | core::num/core::num* {null,int,double} numValue = let final dynamic/ #t5 = foo.field in #t5.==(null) ? 4.5 : #t5; 22 | } 23 | -------------------------------------------------------------------------------- /testcases/strong-mode/uninitialized_fields.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Uninitialized extends core::Object { 6 | field core::int x = null; 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | } 11 | class PartiallyInitialized extends core::Object { 12 | field core::int x = null; 13 | constructor •(core::int x) → void 14 | : self::PartiallyInitialized::x = x, super core::Object::•() 15 | ; 16 | constructor noInitializer() → void 17 | : super core::Object::•() 18 | ; 19 | } 20 | class Initialized extends core::Object { 21 | field core::int x; 22 | constructor •(core::int x) → void 23 | : self::Initialized::x = x, super core::Object::•() 24 | ; 25 | } 26 | class Forwarding extends core::Object { 27 | field core::int x; 28 | constructor initialize(core::int x) → void 29 | : self::Forwarding::x = x, super core::Object::•() 30 | ; 31 | constructor •(core::int arg) → void 32 | : this self::Forwarding::initialize(arg) 33 | ; 34 | } 35 | static field core::int uninitializedTopLevel = null; 36 | static field core::int initializedTopLevel = 4; 37 | static method main() → dynamic {} 38 | -------------------------------------------------------------------------------- /testcases/spec-mode/prefer_baseclass.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class A extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | } 10 | class B extends core::Object { 11 | constructor •() → void 12 | : super core::Object::•() 13 | ; 14 | } 15 | class AB1 extends self::A implements self::B { 16 | constructor •() → void 17 | : super self::A::•() 18 | ; 19 | } 20 | class AB2 extends self::A implements self::B { 21 | constructor •() → void 22 | : super self::A::•() 23 | ; 24 | } 25 | class BA1 extends self::B implements self::A { 26 | constructor •() → void 27 | : super self::B::•() 28 | ; 29 | } 30 | class BA2 extends self::B implements self::A { 31 | constructor •() → void 32 | : super self::B::•() 33 | ; 34 | } 35 | static method takeSubclassOfA(dynamic obj) → dynamic {} 36 | static method takeSubclassOfB(dynamic obj) → dynamic {} 37 | static method main() → dynamic { 38 | self::takeSubclassOfA(new self::AB1::•()); 39 | self::takeSubclassOfA(new self::AB2::•()); 40 | self::takeSubclassOfB(new self::BA1::•()); 41 | self::takeSubclassOfB(new self::BA2::•()); 42 | } 43 | -------------------------------------------------------------------------------- /testcases/strong-mode/prefer_baseclass.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class A extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | } 10 | class B extends core::Object { 11 | constructor •() → void 12 | : super core::Object::•() 13 | ; 14 | } 15 | class AB1 extends self::A implements self::B { 16 | constructor •() → void 17 | : super self::A::•() 18 | ; 19 | } 20 | class AB2 extends self::A implements self::B { 21 | constructor •() → void 22 | : super self::A::•() 23 | ; 24 | } 25 | class BA1 extends self::B implements self::A { 26 | constructor •() → void 27 | : super self::B::•() 28 | ; 29 | } 30 | class BA2 extends self::B implements self::A { 31 | constructor •() → void 32 | : super self::B::•() 33 | ; 34 | } 35 | static method takeSubclassOfA(dynamic obj) → dynamic {} 36 | static method takeSubclassOfB(dynamic obj) → dynamic {} 37 | static method main() → dynamic { 38 | self::takeSubclassOfA(new self::AB1::•()); 39 | self::takeSubclassOfA(new self::AB2::•()); 40 | self::takeSubclassOfB(new self::BA1::•()); 41 | self::takeSubclassOfB(new self::BA2::•()); 42 | } 43 | -------------------------------------------------------------------------------- /test/ast_membench.dart: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env dart 2 | // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 3 | // for details. All rights reserved. Use of this source code is governed by a 4 | // BSD-style license that can be found in the LICENSE file. 5 | import 'package:kernel/kernel.dart'; 6 | import 'dart:io'; 7 | 8 | /// Builds N copies of the AST for the given program. 9 | /// Pass --print-metrics to the Dart VM to measure the memory use. 10 | main(List args) { 11 | if (args.length == 0) { 12 | print('USAGE: ast_membench FILE.dill NUM_COPIES'); 13 | exit(1); 14 | } 15 | String filename = args[0]; 16 | 17 | const int defaultCopyCount = 10; 18 | int copyCount = args.length == 2 ? int.parse(args[1]) : defaultCopyCount; 19 | List keepAlive = []; 20 | for (int i = 0; i < copyCount; ++i) { 21 | keepAlive.add(loadProgramFromBinary(filename)); 22 | } 23 | 24 | print('$copyCount copies built'); 25 | 26 | if (args.contains('-v')) { 27 | // Use of the list for something to avoid premature GC. 28 | int size = 0; 29 | for (var program in keepAlive) { 30 | size += program.libraries.length; 31 | } 32 | print(size); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /testcases/type-propagation/prefer_baseclass.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class A extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | } 10 | class B extends core::Object { 11 | constructor •() → void 12 | : super core::Object::•() 13 | ; 14 | } 15 | class AB1 extends self::A implements self::B { 16 | constructor •() → void 17 | : super self::A::•() 18 | ; 19 | } 20 | class AB2 extends self::A implements self::B { 21 | constructor •() → void 22 | : super self::A::•() 23 | ; 24 | } 25 | class BA1 extends self::B implements self::A { 26 | constructor •() → void 27 | : super self::B::•() 28 | ; 29 | } 30 | class BA2 extends self::B implements self::A { 31 | constructor •() → void 32 | : super self::B::•() 33 | ; 34 | } 35 | static method takeSubclassOfA(dynamic/self::A+ {other} obj) → dynamic/Null {} 36 | static method takeSubclassOfB(dynamic/self::B+ {other} obj) → dynamic/Null {} 37 | static method main() → dynamic/Null { 38 | self::takeSubclassOfA(new self::AB1::•()); 39 | self::takeSubclassOfA(new self::AB2::•()); 40 | self::takeSubclassOfB(new self::BA1::•()); 41 | self::takeSubclassOfB(new self::BA2::•()); 42 | } 43 | -------------------------------------------------------------------------------- /testcases/type-propagation/uninitialized_fields.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Uninitialized extends core::Object { 6 | field core::int/Null x = null; 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | } 11 | class PartiallyInitialized extends core::Object { 12 | field core::int/Null x = null; 13 | constructor •(core::int/Nothing x) → void 14 | : self::PartiallyInitialized::x = x, super core::Object::•() 15 | ; 16 | constructor noInitializer() → void 17 | : super core::Object::•() 18 | ; 19 | } 20 | class Initialized extends core::Object { 21 | field core::int/Nothing x; 22 | constructor •(core::int/Nothing x) → void 23 | : self::Initialized::x = x, super core::Object::•() 24 | ; 25 | } 26 | class Forwarding extends core::Object { 27 | field core::int/Null x; 28 | constructor initialize(core::int/Nothing x) → void 29 | : self::Forwarding::x = x, super core::Object::•() 30 | ; 31 | constructor •(core::int/Nothing arg) → void 32 | : this self::Forwarding::initialize(arg) 33 | ; 34 | } 35 | static field core::int/Null uninitializedTopLevel = null; 36 | static field core::int/core::int* {int} initializedTopLevel = 4; 37 | static method main() → dynamic/Null {} 38 | -------------------------------------------------------------------------------- /testcases/input/optional.dart: -------------------------------------------------------------------------------- 1 | class Foo { 2 | method(x, [y, z]) { 3 | return "string"; 4 | } 5 | } 6 | 7 | abstract class External { 8 | String externalMethod(int x, [int y, int z]); 9 | void listen(Listener listener); 10 | } 11 | external External createExternal(); 12 | 13 | abstract class Listener { 14 | void event(String input, [int x, int y]); 15 | } 16 | 17 | class TestListener extends Listener { 18 | void event(input, [x, y]) {} 19 | } 20 | 21 | class ExtendedListener extends Listener { 22 | void event(input, [x, y, z]) {} 23 | } 24 | 25 | class InvalidListener { 26 | void event(input, [x]) {} 27 | } 28 | 29 | main() { 30 | var foo = new Foo(); 31 | var string1 = foo.method(1); 32 | var string2 = foo.method(1, 2); 33 | var string3 = foo.method(1, 2, 3); 34 | 35 | var extern = createExternal(); 36 | var string4 = extern.externalMethod(1); 37 | var string5 = extern.externalMethod(1, 2); 38 | var string6 = extern.externalMethod(1, 2, 3); 39 | 40 | extern.listen(new TestListener()); 41 | extern.listen(new ExtendedListener()); 42 | extern.listen(new InvalidListener()); 43 | 44 | var nothing1 = foo.method(); 45 | var nothing2 = foo.method(1, 2, 3, 4); 46 | var nothing3 = extern.externalMethod(); 47 | var nothing4 = extern.externalMethod(1, 2, 3, 4); 48 | } 49 | -------------------------------------------------------------------------------- /testcases/input/call.dart: -------------------------------------------------------------------------------- 1 | class Callable { 2 | call(x) { 3 | return "string"; 4 | } 5 | } 6 | 7 | class CallableGetter { 8 | get call => new Callable(); 9 | } 10 | 11 | main() { 12 | var closure = (x) => x; 13 | var int1 = closure(1); 14 | var int2 = closure.call(1); 15 | var int3 = closure.call.call(1); 16 | var int4 = closure.call.call.call(1); 17 | 18 | var callable = new Callable(); 19 | var string1 = callable(1); 20 | var string2 = callable.call(1); 21 | var string3 = callable.call.call(1); 22 | var string4 = callable.call.call.call(1); 23 | 24 | var callableGetter = new CallableGetter(); 25 | var string5 = callableGetter(1); 26 | var string6 = callableGetter.call(1); 27 | var string7 = callableGetter.call.call(1); 28 | var string8 = callableGetter.call.call.call(1); 29 | 30 | var nothing1 = closure(); 31 | var nothing2 = closure.call(); 32 | var nothing3 = closure.call.call(); 33 | var nothing4 = closure.call.call.call(); 34 | 35 | var nothing5 = callable(); 36 | var nothing6 = callable.call(); 37 | var nothing7 = callable.call.call(); 38 | var nothing8 = callable.call.call.call(); 39 | 40 | var nothing9 = callableGetter(); 41 | var nothing10 = callableGetter.call(); 42 | var nothing11 = callableGetter.call.call(); 43 | var nothing12 = callableGetter.call.call.call(); 44 | } 45 | -------------------------------------------------------------------------------- /testcases/spec-mode/named_parameters.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Superclass extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | method foo({dynamic alpha, dynamic beta}) → dynamic {} 10 | method bar({dynamic alpha, dynamic beta}) → dynamic {} 11 | method namedCallback(({alpha: core::String, beta: core::int}) → dynamic callback) → dynamic { 12 | callback.call(alpha: "one", beta: 2); 13 | callback.call(beta: 1, alpha: "two"); 14 | } 15 | } 16 | class Subclass extends self::Superclass { 17 | constructor •() → void 18 | : super self::Superclass::•() 19 | ; 20 | method foo({dynamic alpha, dynamic beta}) → dynamic {} 21 | method bar({dynamic alpha, dynamic beta}) → dynamic {} 22 | method namedCallback(({alpha: core::String, beta: core::int}) → dynamic callback) → dynamic {} 23 | } 24 | static method topLevelNamed(dynamic beta, dynamic alpha, {dynamic delta, dynamic gamma}) → dynamic {} 25 | static method topLevelOptional(dynamic beta, dynamic alpha, [dynamic gamma, dynamic delta]) → dynamic {} 26 | static method main() → dynamic { 27 | new self::Subclass::•().foo(beta: 1, alpha: 2); 28 | new self::Subclass::•().foo(alpha: 1, beta: 2); 29 | self::topLevelNamed(1, 2, gamma: 3, delta: 4); 30 | self::topLevelNamed(1, 2, delta: 3, gamma: 4); 31 | } 32 | -------------------------------------------------------------------------------- /testcases/spec-mode/escape.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class A extends core::Object { 6 | field dynamic field = null; 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | } 11 | class B extends core::Object { 12 | field dynamic field = null; 13 | constructor •() → void 14 | : super core::Object::•() 15 | ; 16 | } 17 | class C extends core::Object { 18 | constructor •() → void 19 | : super core::Object::•() 20 | ; 21 | operator ==(dynamic x) → dynamic 22 | return false; 23 | } 24 | class X extends core::Object implements self::A, self::B { 25 | field dynamic field = null; 26 | constructor •() → void 27 | : super core::Object::•() 28 | ; 29 | } 30 | static method useAsA(self::A object) → void { 31 | dynamic _ = object.field; 32 | } 33 | static method useAsB(self::B object) → void { 34 | dynamic _ = object.field; 35 | self::escape(object); 36 | } 37 | static method escape(dynamic x) → void { 38 | x.==(null) ? x = "" : null; 39 | x.==(null) ? x = 45 : null; 40 | if(!(x is core::int) && !(x is core::String)) { 41 | x.field = 45; 42 | } 43 | } 44 | static method main() → dynamic { 45 | dynamic object = new self::X::•(); 46 | self::useAsA(new self::A::•()); 47 | self::useAsA(object); 48 | self::useAsB(new self::B::•()); 49 | self::useAsB(object); 50 | } 51 | -------------------------------------------------------------------------------- /test/type_hashcode_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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:kernel/kernel.dart'; 5 | import 'type_parser.dart'; 6 | import 'type_unification_test.dart' show testCases; 7 | import 'package:test/test.dart'; 8 | 9 | void checkHashCodeEquality(DartType type1, DartType type2) { 10 | if (type1 == type2 && type1.hashCode != type2.hashCode) { 11 | fail('Equal types with different hash codes: $type1 and $type2'); 12 | } 13 | } 14 | 15 | const int MinimumSmi = -(1 << 30); 16 | const int MaximumSmi = (1 << 30) - 1; 17 | 18 | bool isSmallInteger(int hash) { 19 | return MinimumSmi <= hash && hash <= MaximumSmi; 20 | } 21 | 22 | void checkHashCodeRange(DartType type) { 23 | int hash = type.hashCode; 24 | if (!isSmallInteger(hash)) { 25 | fail('Hash code for $type is not a SMI: $hash'); 26 | } 27 | } 28 | 29 | void main() { 30 | for (var testCase in testCases) { 31 | test('$testCase', () { 32 | var env = new LazyTypeEnvironment(); 33 | var type1 = env.parse(testCase.type1); 34 | var type2 = env.parse(testCase.type2); 35 | checkHashCodeEquality(type1, type2); 36 | checkHashCodeRange(type1); 37 | checkHashCodeRange(type2); 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /testcases/strong-mode/escape.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class A extends core::Object { 6 | field dynamic field = null; 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | } 11 | class B extends core::Object { 12 | field dynamic field = null; 13 | constructor •() → void 14 | : super core::Object::•() 15 | ; 16 | } 17 | class C extends core::Object { 18 | constructor •() → void 19 | : super core::Object::•() 20 | ; 21 | operator ==(dynamic x) → core::bool 22 | return false; 23 | } 24 | class X extends core::Object implements self::A, self::B { 25 | field dynamic field = null; 26 | constructor •() → void 27 | : super core::Object::•() 28 | ; 29 | } 30 | static method useAsA(self::A object) → void { 31 | dynamic _ = object.{self::A::field}; 32 | } 33 | static method useAsB(self::B object) → void { 34 | dynamic _ = object.{self::B::field}; 35 | self::escape(object); 36 | } 37 | static method escape(dynamic x) → void { 38 | x.==(null) ? x = "" : null; 39 | x.==(null) ? x = 45 : null; 40 | if(!(x is core::int) && !(x is core::String)) { 41 | x.field = 45; 42 | } 43 | } 44 | static method main() → dynamic { 45 | self::X object = new self::X::•(); 46 | self::useAsA(new self::A::•()); 47 | self::useAsA(object); 48 | self::useAsB(new self::B::•()); 49 | self::useAsB(object); 50 | } 51 | -------------------------------------------------------------------------------- /testcases/strong-mode/named_parameters.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Superclass extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | method foo({dynamic alpha, dynamic beta}) → dynamic {} 10 | method bar({dynamic alpha, dynamic beta}) → dynamic {} 11 | method namedCallback(({alpha: core::String, beta: core::int}) → dynamic callback) → dynamic { 12 | callback.call(alpha: "one", beta: 2); 13 | callback.call(beta: 1, alpha: "two"); 14 | } 15 | } 16 | class Subclass extends self::Superclass { 17 | constructor •() → void 18 | : super self::Superclass::•() 19 | ; 20 | method foo({dynamic alpha, dynamic beta}) → dynamic {} 21 | method bar({dynamic alpha, dynamic beta}) → dynamic {} 22 | method namedCallback(({alpha: core::String, beta: core::int}) → dynamic callback) → dynamic {} 23 | } 24 | static method topLevelNamed(dynamic beta, dynamic alpha, {dynamic delta, dynamic gamma}) → dynamic {} 25 | static method topLevelOptional(dynamic beta, dynamic alpha, [dynamic gamma, dynamic delta]) → dynamic {} 26 | static method main() → dynamic { 27 | new self::Subclass::•().{self::Subclass::foo}(beta: 1, alpha: 2); 28 | new self::Subclass::•().{self::Subclass::foo}(alpha: 1, beta: 2); 29 | self::topLevelNamed(1, 2, gamma: 3, delta: 4); 30 | self::topLevelNamed(1, 2, delta: 3, gamma: 4); 31 | } 32 | -------------------------------------------------------------------------------- /test/baseline_type_propagation_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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:kernel/kernel.dart'; 5 | import 'package:kernel/text/ast_to_text.dart'; 6 | import 'package:kernel/transformations/mixin_full_resolution.dart'; 7 | import 'package:kernel/type_propagation/builder.dart'; 8 | import 'package:kernel/type_propagation/solver.dart'; 9 | import 'package:kernel/type_propagation/visualizer.dart'; 10 | 11 | import 'baseline_tester.dart'; 12 | 13 | class TypePropagationTest extends TestTarget { 14 | @override 15 | Annotator annotator; 16 | 17 | @override 18 | List get extraRequiredLibraries => []; 19 | 20 | @override 21 | String get name => 'type-propagation-test'; 22 | 23 | @override 24 | bool get strongMode => false; 25 | 26 | @override 27 | List transformProgram(Program program) { 28 | new MixinFullResolution().transform(program); 29 | var visualizer = new Visualizer(program); 30 | var builder = new Builder(program, visualizer: visualizer); 31 | var solver = new Solver(builder); 32 | solver.solve(); 33 | visualizer.solver = solver; 34 | annotator = new TextAnnotator(visualizer); 35 | return const []; 36 | } 37 | } 38 | 39 | void main() { 40 | runBaselineTests('type-propagation', new TypePropagationTest()); 41 | } 42 | -------------------------------------------------------------------------------- /lib/transformations/infer_values.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.transformations.infer_types; 6 | 7 | import '../ast.dart'; 8 | import '../type_propagation/type_propagation.dart'; 9 | 10 | Program transformProgram(Program program) { 11 | TypePropagation propagation = new TypePropagation(program); 12 | 13 | var attacher = new InferredValueAttacher(propagation, program); 14 | attacher.attachInferredValues(); 15 | 16 | return program; 17 | } 18 | 19 | class InferredValueAttacher extends RecursiveVisitor { 20 | final TypePropagation propagation; 21 | final Program program; 22 | 23 | InferredValueAttacher(this.propagation, this.program); 24 | 25 | attachInferredValues() => program.accept(this); 26 | 27 | visitField(Field node) { 28 | node.inferredValue = propagation.getFieldValue(node); 29 | super.visitField(node); 30 | } 31 | 32 | visitFunctionNode(FunctionNode node) { 33 | node.positionalParameters.forEach(_annotateVariableDeclaration); 34 | node.namedParameters.forEach(_annotateVariableDeclaration); 35 | node.inferredReturnValue = propagation.getReturnValue(node); 36 | super.visitFunctionNode(node); 37 | } 38 | 39 | _annotateVariableDeclaration(VariableDeclaration variable) { 40 | variable.inferredValue = propagation.getParameterValue(variable); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /testcases/input/micro.dart: -------------------------------------------------------------------------------- 1 | staticMethod() { 2 | return "sdfg"; 3 | } 4 | 5 | class Foo { 6 | instanceMethod() { 7 | return 123; 8 | } 9 | } 10 | 11 | external bool externalStatic(); 12 | 13 | abstract class ExternalValue {} 14 | 15 | abstract class Bar { 16 | ExternalValue externalInstanceMethod(); 17 | } 18 | 19 | external Bar createBar(); 20 | 21 | class Box { 22 | var field; 23 | } 24 | 25 | stringArgument(x) { 26 | } 27 | 28 | intArgument(x) { 29 | } 30 | 31 | class FinalBox { 32 | final finalField; 33 | FinalBox(this.finalField); 34 | } 35 | 36 | class SubFinalBox extends FinalBox { 37 | SubFinalBox(value) : super(value); 38 | } 39 | 40 | class DynamicReceiver1 { 41 | dynamicallyCalled(x) {} 42 | } 43 | class DynamicReceiver2 { 44 | dynamicallyCalled(x) {} 45 | } 46 | 47 | void makeDynamicCall(receiver) { 48 | receiver.dynamicallyCalled("sdfg"); 49 | } 50 | 51 | main() { 52 | var x = staticMethod(); 53 | var y = new Foo().instanceMethod(); 54 | var z = externalStatic(); 55 | var w = createBar().externalInstanceMethod(); 56 | 57 | stringArgument("sdfg"); 58 | intArgument(42); 59 | 60 | var box = new Box(); 61 | box.field = "sdfg"; 62 | var a = box.field; 63 | 64 | var finalBox = new FinalBox("dfg"); 65 | var b = finalBox.finalField; 66 | 67 | var subBox = new SubFinalBox("dfg"); 68 | var c = subBox.finalField; 69 | 70 | makeDynamicCall(new DynamicReceiver1()); 71 | makeDynamicCall(new DynamicReceiver2()); 72 | 73 | var list = ["string"]; 74 | var d = list[0]; 75 | } 76 | -------------------------------------------------------------------------------- /test/typecheck.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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:kernel/kernel.dart'; 5 | import 'package:kernel/class_hierarchy.dart'; 6 | import 'package:kernel/core_types.dart'; 7 | import 'package:kernel/type_checker.dart'; 8 | import 'dart:io'; 9 | 10 | final String usage = ''' 11 | Usage: typecheck FILE.dill 12 | 13 | Runs the strong mode type checker on the given program. 14 | '''; 15 | 16 | main(List args) { 17 | if (args.length != 1) { 18 | print(usage); 19 | exit(1); 20 | } 21 | var program = loadProgramFromBinary(args[0]); 22 | var coreTypes = new CoreTypes(program); 23 | var hierarchy = new ClassHierarchy(program); 24 | new TestTypeChecker(coreTypes, hierarchy).checkProgram(program); 25 | } 26 | 27 | class TestTypeChecker extends TypeChecker { 28 | TestTypeChecker(CoreTypes coreTypes, ClassHierarchy hierarchy) 29 | : super(coreTypes, hierarchy); 30 | 31 | @override 32 | void checkAssignable(TreeNode where, DartType from, DartType to) { 33 | if (!environment.isSubtypeOf(from, to)) { 34 | fail(where, '$from is not a subtype of $to'); 35 | } 36 | } 37 | 38 | @override 39 | void fail(TreeNode where, String message) { 40 | Location location = where.location; 41 | String locationString = location == null ? '' : '($location)'; 42 | print('[error] $message $locationString'); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/type_hashcode_quality.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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:kernel/kernel.dart'; 5 | import 'dart:io'; 6 | 7 | String usage = ''' 8 | Usage: type_hashcode_quality FILE.dill 9 | 10 | Counts the number of hash collisions between DartTypes in the given file. 11 | '''; 12 | 13 | void main(List args) { 14 | if (args.length == 0) { 15 | print(usage); 16 | exit(1); 17 | } 18 | Program program = loadProgramFromBinary(args[0]); 19 | var visitor = new DartTypeCollector(); 20 | program.accept(visitor); 21 | print(''' 22 | Types: ${visitor.numberOfTypes} 23 | Collisions: ${visitor.numberOfCollisions}'''); 24 | } 25 | 26 | class DartTypeCollector extends RecursiveVisitor { 27 | final Set seenTypes = new Set(); 28 | final Map table = {}; 29 | int numberOfCollisions = 0; 30 | int numberOfTypes = 0; 31 | 32 | @override 33 | defaultDartType(DartType node) { 34 | if (!seenTypes.add(node)) return; 35 | ++numberOfTypes; 36 | int hash = node.hashCode; 37 | if (hash == 0) { 38 | print('Type has a hash code of zero: $node'); 39 | } 40 | DartType existing = table[hash]; 41 | if (existing == null) { 42 | table[hash] = node; 43 | } else if (existing != node) { 44 | print('Collision between $existing and $node'); 45 | ++numberOfCollisions; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2016, the Dart project authors. All rights reserved. 2 | Redistribution and use in source and binary forms, with or without 3 | modification, are permitted provided that the following conditions are 4 | met: 5 | * Redistributions of source code must retain the above copyright 6 | notice, this list of conditions and the following disclaimer. 7 | * Redistributions in binary form must reproduce the above 8 | copyright notice, this list of conditions and the following 9 | disclaimer in the documentation and/or other materials provided 10 | with the distribution. 11 | * Neither the name of Google Inc. nor the names of its 12 | contributors may be used to endorse or promote products derived 13 | from this software without specific prior written permission. 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /lib/transformations/setup_builtin_library.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.transformations.setup_builtin_library; 6 | 7 | import '../ast.dart'; 8 | 9 | // The DartVM has a special `dart:_builtin` library which exposes a 10 | // `_getMainClosure()` method. We need to change this method to return a 11 | // closure of `main()`. 12 | Program transformProgram(Program program, 13 | {String libraryUri: 'dart:_builtin'}) { 14 | Procedure mainMethod = program.mainMethod; 15 | 16 | Library builtinLibrary; 17 | for (Library library in program.libraries) { 18 | if (library.importUri.toString() == libraryUri) { 19 | builtinLibrary = library; 20 | break; 21 | } 22 | } 23 | 24 | if (builtinLibrary == null) { 25 | throw new Exception('Could not find "dart:_builtin" library'); 26 | } 27 | 28 | FunctionNode getMainClosure; 29 | for (Procedure procedure in builtinLibrary.procedures) { 30 | if (procedure.name.name == '_getMainClosure') { 31 | getMainClosure = procedure.function; 32 | break; 33 | } 34 | } 35 | 36 | if (getMainClosure == null) { 37 | throw new Exception('Could not find "_getMainClosure" in "$libraryUri"'); 38 | } 39 | 40 | var returnMainStatement = new ReturnStatement(new StaticGet(mainMethod)); 41 | getMainClosure.body = returnMainStatement; 42 | returnMainStatement.parent = getMainClosure; 43 | 44 | return program; 45 | } 46 | -------------------------------------------------------------------------------- /testcases/type-propagation/escape.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class A extends core::Object { 6 | field dynamic/Null field = null; 7 | constructor •() → void 8 | : super core::Object::•() 9 | ; 10 | } 11 | class B extends core::Object { 12 | field dynamic/core::int* {null,int} field = null; 13 | constructor •() → void 14 | : super core::Object::•() 15 | ; 16 | } 17 | class C extends core::Object { 18 | constructor •() → void 19 | : super core::Object::•() 20 | ; 21 | operator ==(dynamic/Nothing x) → dynamic/core::bool* {other} 22 | return false; 23 | } 24 | class X extends core::Object implements self::A, self::B { 25 | field dynamic/core::int* {null,int} field = null; 26 | constructor •() → void 27 | : super core::Object::•() 28 | ; 29 | } 30 | static method useAsA(self::A/self::A* {other} object) → void/Null { 31 | dynamic/core::int* {null,int} _ = object.field; 32 | } 33 | static method useAsB(self::B/self::B* {other} object) → void/Null { 34 | dynamic/core::int* {null,int} _ = object.field; 35 | self::escape(object); 36 | } 37 | static method escape(dynamic/core::Object+ {int,string,other} x) → void/Null { 38 | x.==(null) ? x = "" : null; 39 | x.==(null) ? x = 45 : null; 40 | if(!(x is core::int) && !(x is core::String)) { 41 | x.field = 45; 42 | } 43 | } 44 | static method main() → dynamic/Null { 45 | dynamic/self::X! {other} object = new self::X::•(); 46 | self::useAsA(new self::A::•()); 47 | self::useAsA(object); 48 | self::useAsB(new self::B::•()); 49 | self::useAsB(object); 50 | } 51 | -------------------------------------------------------------------------------- /testcases/type-propagation/named_parameters.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Superclass extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | method foo({dynamic/Null alpha, dynamic/Null beta}) → dynamic/Null {} 10 | method bar({dynamic/Null alpha, dynamic/Null beta}) → dynamic/Null {} 11 | method namedCallback(({alpha: core::String, beta: core::int}) → dynamic/Nothing callback) → dynamic/Null { 12 | callback.call(alpha: "one", beta: 2); 13 | callback.call(beta: 1, alpha: "two"); 14 | } 15 | } 16 | class Subclass extends self::Superclass { 17 | constructor •() → void 18 | : super self::Superclass::•() 19 | ; 20 | method foo({dynamic/core::int* {null,int} alpha, dynamic/core::int* {null,int} beta}) → dynamic/Null {} 21 | method bar({dynamic/Null alpha, dynamic/Null beta}) → dynamic/Null {} 22 | method namedCallback(({alpha: core::String, beta: core::int}) → dynamic/Nothing callback) → dynamic/Null {} 23 | } 24 | static method topLevelNamed(dynamic/core::int* {int} beta, dynamic/core::int* {int} alpha, {dynamic/core::int* {null,int} delta, dynamic/core::int* {null,int} gamma}) → dynamic/Null {} 25 | static method topLevelOptional(dynamic/Nothing beta, dynamic/Nothing alpha, [dynamic/Null gamma, dynamic/Null delta]) → dynamic/Null {} 26 | static method main() → dynamic/Null { 27 | new self::Subclass::•().foo(beta: 1, alpha: 2); 28 | new self::Subclass::•().foo(alpha: 1, beta: 2); 29 | self::topLevelNamed(1, 2, gamma: 3, delta: 4); 30 | self::topLevelNamed(1, 2, delta: 3, gamma: 4); 31 | } 32 | -------------------------------------------------------------------------------- /test/treeshaker_check.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.treeshaker_check; 5 | 6 | import 'package:kernel/kernel.dart'; 7 | import 'package:kernel/transformations/treeshaker.dart'; 8 | import 'dart:io'; 9 | 10 | String usage = ''' 11 | Usage: treeshaker_check FILE.dill 12 | 13 | Run the tree shaker on FILE.dill and perform some internal sanity checks. 14 | '''; 15 | 16 | main(List args) { 17 | if (args.length == 0) { 18 | print(usage); 19 | exit(1); 20 | } 21 | var program = loadProgramFromBinary(args[0]); 22 | var shaker = new TreeShaker(program); 23 | shaker.transform(program); 24 | new TreeShakingSanityCheck(shaker).visit(program); 25 | } 26 | 27 | class TreeShakingSanityCheck extends RecursiveVisitor { 28 | final TreeShaker shaker; 29 | bool isInCoreLibrary = false; 30 | 31 | TreeShakingSanityCheck(this.shaker); 32 | 33 | void visit(Node node) { 34 | node.accept(this); 35 | } 36 | 37 | visitLibrary(Library node) { 38 | isInCoreLibrary = (node.importUri.scheme == 'dart'); 39 | super.visitLibrary(node); 40 | } 41 | 42 | defaultMember(Member member) { 43 | if (!isInCoreLibrary && 44 | member is! Constructor && 45 | !shaker.isMemberUsed(member)) { 46 | throw 'Unused member $member was not removed'; 47 | } 48 | } 49 | 50 | defaultMemberReference(Member target) { 51 | if (!shaker.isMemberUsed(target)) { 52 | throw 'Found reference to $target'; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /testcases/spec-mode/call.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Callable extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | method call(dynamic x) → dynamic { 10 | return "string"; 11 | } 12 | } 13 | class CallableGetter extends core::Object { 14 | constructor •() → void 15 | : super core::Object::•() 16 | ; 17 | get call() → dynamic 18 | return new self::Callable::•(); 19 | } 20 | static method main() → dynamic { 21 | dynamic closure = (dynamic x) → dynamic => x; 22 | dynamic int1 = closure.call(1); 23 | dynamic int2 = closure.call(1); 24 | dynamic int3 = closure.call.call(1); 25 | dynamic int4 = closure.call.call.call(1); 26 | dynamic callable = new self::Callable::•(); 27 | dynamic string1 = callable.call(1); 28 | dynamic string2 = callable.call(1); 29 | dynamic string3 = callable.call.call(1); 30 | dynamic string4 = callable.call.call.call(1); 31 | dynamic callableGetter = new self::CallableGetter::•(); 32 | dynamic string5 = callableGetter.call(1); 33 | dynamic string6 = callableGetter.call(1); 34 | dynamic string7 = callableGetter.call.call(1); 35 | dynamic string8 = callableGetter.call.call.call(1); 36 | dynamic nothing1 = closure.call(); 37 | dynamic nothing2 = closure.call(); 38 | dynamic nothing3 = closure.call.call(); 39 | dynamic nothing4 = closure.call.call.call(); 40 | dynamic nothing5 = callable.call(); 41 | dynamic nothing6 = callable.call(); 42 | dynamic nothing7 = callable.call.call(); 43 | dynamic nothing8 = callable.call.call.call(); 44 | dynamic nothing9 = callableGetter.call(); 45 | dynamic nothing10 = callableGetter.call(); 46 | dynamic nothing11 = callableGetter.call.call(); 47 | dynamic nothing12 = callableGetter.call.call.call(); 48 | } 49 | -------------------------------------------------------------------------------- /test/uint31_pair_map_bench.dart: -------------------------------------------------------------------------------- 1 | import 'package:kernel/type_propagation/canonicalizer.dart'; 2 | 3 | main() { 4 | Stopwatch watch = new Stopwatch()..start(); 5 | 6 | const int lowBiasKeys = 100; 7 | const int highBiasKeys = 10000; 8 | const int noBiasKeys = 1000; 9 | 10 | Uint31PairMap map; 11 | 12 | // Warm up. 13 | map = new Uint31PairMap(); 14 | for (int i = 0; i < noBiasKeys; ++i) { 15 | for (int j = 0; j < noBiasKeys; ++j) { 16 | map.lookup(i, j); 17 | map.put(i + j); 18 | } 19 | } 20 | 21 | // Even distributed tuple components. 22 | watch.reset(); 23 | map = new Uint31PairMap(); 24 | for (int i = 0; i < noBiasKeys; ++i) { 25 | for (int j = 0; j < noBiasKeys; ++j) { 26 | map.lookup(i, j); 27 | map.put(i + j); 28 | } 29 | } 30 | int noBiasTime = watch.elapsedMicroseconds; 31 | 32 | // Left-bias: more unique keys in the first component. 33 | watch.reset(); 34 | map = new Uint31PairMap(); 35 | for (int i = 0; i < highBiasKeys; ++i) { 36 | for (int j = 0; j < lowBiasKeys; ++j) { 37 | map.lookup(i, j); 38 | map.put(i + j); 39 | } 40 | } 41 | int leftBiasTime = watch.elapsedMicroseconds; 42 | 43 | // Right-bias: more unique keys in the second component. 44 | watch.reset(); 45 | map = new Uint31PairMap(); 46 | for (int i = 0; i < lowBiasKeys; ++i) { 47 | for (int j = 0; j < highBiasKeys; ++j) { 48 | map.lookup(i, j); 49 | map.put(i + j); 50 | } 51 | } 52 | int rightBiasTime = watch.elapsedMicroseconds; 53 | 54 | print(''' 55 | bias.none: ${formatTime(noBiasTime)} 56 | bias.left: ${formatTime(leftBiasTime)} 57 | bias.right: ${formatTime(rightBiasTime)} 58 | '''); 59 | } 60 | 61 | 62 | String formatTime(int microseconds) { 63 | double seconds = microseconds / 1000000.0; 64 | return '$seconds s'; 65 | } 66 | -------------------------------------------------------------------------------- /bin/batch_util.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.batch_util; 5 | 6 | import 'dart:async'; 7 | import 'dart:convert'; 8 | import 'dart:io'; 9 | 10 | enum CompilerOutcome { Ok, Fail, } 11 | 12 | typedef Future BatchCallback(List arguments); 13 | 14 | /// Runs the given [callback] in the batch mode for use by the test framework in 15 | /// `dart-lang/sdk`. 16 | /// 17 | /// The [callback] should behave as a main method, except it should return a 18 | /// [CompilerOutcome] for reporting its outcome to the testing framework. 19 | Future runBatch(BatchCallback callback) async { 20 | int totalTests = 0; 21 | int testsFailed = 0; 22 | var watch = new Stopwatch()..start(); 23 | print('>>> BATCH START'); 24 | Stream input = stdin.transform(UTF8.decoder).transform(new LineSplitter()); 25 | await for (String line in input) { 26 | if (line.isEmpty) { 27 | int time = watch.elapsedMilliseconds; 28 | print('>>> BATCH END ' 29 | '(${totalTests - testsFailed})/$totalTests ${time}ms'); 30 | break; 31 | } 32 | ++totalTests; 33 | var arguments = line.split(new RegExp(r'\s+')); 34 | try { 35 | var outcome = await callback(arguments); 36 | stderr.writeln('>>> EOF STDERR'); 37 | if (outcome == CompilerOutcome.Ok) { 38 | print('>>> TEST PASS ${watch.elapsedMilliseconds}ms'); 39 | } else { 40 | print('>>> TEST FAIL ${watch.elapsedMilliseconds}ms'); 41 | } 42 | } catch (e, stackTrace) { 43 | stderr.writeln(e); 44 | stderr.writeln(stackTrace); 45 | stderr.writeln('>>> EOF STDERR'); 46 | print('>>> TEST CRASH'); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /test/class_hierarchy_membench.dart: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env dart 2 | // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 3 | // for details. All rights reserved. Use of this source code is governed by a 4 | // BSD-style license that can be found in the LICENSE file. 5 | import 'package:kernel/kernel.dart'; 6 | import 'package:kernel/class_hierarchy.dart'; 7 | import 'package:args/args.dart'; 8 | import 'class_hierarchy_basic.dart'; 9 | import 'dart:io'; 10 | 11 | ArgParser argParser = new ArgParser() 12 | ..addFlag('basic', help: 'Measure the basic implementation', negatable: false) 13 | ..addOption('count', abbr: 'c', 14 | help: 'Build N copies of the class hierarchy', 15 | defaultsTo: '300'); 16 | 17 | String usage = """ 18 | Usage: class_hierarchy_membench [options] FILE.dart 19 | 20 | Options: 21 | ${argParser.usage} 22 | """; 23 | 24 | /// Builds N copies of the class hierarchy for the given program. 25 | /// Pass --print-metrics to the Dart VM to measure the memory use. 26 | main(List args) { 27 | if (args.length == 0) { 28 | print(usage); 29 | exit(1); 30 | } 31 | ArgResults options = argParser.parse(args); 32 | if (options.rest.length != 1) { 33 | print('Exactly one file should be given'); 34 | exit(1); 35 | } 36 | String filename = options.rest.single; 37 | 38 | Program program = loadProgramFromBinary(filename); 39 | 40 | int copyCount = int.parse(options['count']); 41 | 42 | ClassHierarchy buildHierarchy() { 43 | return options['basic'] 44 | ? new BasicClassHierarchy(program) 45 | : new ClassHierarchy(program); 46 | } 47 | 48 | List keepAlive = []; 49 | for (int i = 0; i < copyCount; ++i) { 50 | keepAlive.add(buildHierarchy()); 51 | } 52 | 53 | print('$copyCount copies built'); 54 | 55 | if (args.contains('-v')) { 56 | // Use of the list for something to avoid premature GC. 57 | int size = 0; 58 | for (var classHierarchy in keepAlive) { 59 | size += classHierarchy.getSuperTypeHashTableSize(); 60 | } 61 | print(size); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /test/treeshaker_membench.dart: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env dart 2 | // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 3 | // for details. All rights reserved. Use of this source code is governed by a 4 | // BSD-style license that can be found in the LICENSE file. 5 | library kernel.treeshaker_membench; 6 | 7 | import 'package:kernel/kernel.dart'; 8 | import 'package:kernel/transformations/treeshaker.dart'; 9 | import 'package:kernel/class_hierarchy.dart'; 10 | import 'package:kernel/core_types.dart'; 11 | import 'package:args/args.dart'; 12 | import 'dart:io'; 13 | 14 | ArgParser argParser = new ArgParser() 15 | ..addOption('count', abbr: 'c', 16 | help: 'Build N copies of the tree shaker', 17 | defaultsTo: '100'); 18 | 19 | String usage = """ 20 | Usage: treeshaker_membench [options] FILE.dart 21 | 22 | Options: 23 | ${argParser.usage} 24 | """; 25 | 26 | /// Builds N copies of the tree shaker data structure for the given program. 27 | /// Pass --print-metrics to the Dart VM to measure the memory use. 28 | main(List args) { 29 | if (args.length == 0) { 30 | print(usage); 31 | exit(1); 32 | } 33 | ArgResults options = argParser.parse(args); 34 | if (options.rest.length != 1) { 35 | print('Exactly one file should be given'); 36 | exit(1); 37 | } 38 | String filename = options.rest.single; 39 | 40 | Program program = loadProgramFromBinary(filename); 41 | ClassHierarchy hierarchy = new ClassHierarchy(program); 42 | CoreTypes coreTypes = new CoreTypes(program); 43 | 44 | int copyCount = int.parse(options['count']); 45 | 46 | TreeShaker buildTreeShaker() { 47 | return new TreeShaker(program, hierarchy: hierarchy, coreTypes: coreTypes); 48 | } 49 | 50 | List keepAlive = []; 51 | for (int i = 0; i < copyCount; ++i) { 52 | keepAlive.add(buildTreeShaker()); 53 | } 54 | 55 | print('$copyCount copies built'); 56 | 57 | if (args.contains('-v')) { 58 | // Use of the list for something to avoid premature GC. 59 | for (var treeShaker in keepAlive) { 60 | treeShaker.getClassRetention(hierarchy.rootClass); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /testcases/spec-mode/redirecting_factory.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | abstract class FooBase extends core::Object { 6 | abstract get x() → core::int; 7 | } 8 | abstract class Foo extends core::Object implements self::FooBase { 9 | } 10 | class Bar extends core::Object implements self::Foo { 11 | field core::int x; 12 | constructor •(core::int x) → void 13 | : self::Bar::x = x, super core::Object::•() { 14 | core::print("Bar<${self::Bar::Sb},${self::Bar::Tb}>"); 15 | } 16 | } 17 | class Builder extends core::Object { 18 | constructor •() → void 19 | : super core::Object::•() 20 | ; 21 | method method() → dynamic { 22 | return new self::Bar::•(4); 23 | } 24 | } 25 | class SimpleCase extends core::Object { 26 | } 27 | class SimpleCaseImpl extends core::Object implements self::SimpleCase { 28 | } 29 | class SimpleCaseImpl2 extends core::Object implements self::SimpleCaseImpl { 30 | constructor •() → void 31 | : super core::Object::•() 32 | ; 33 | } 34 | class Base extends core::Object { 35 | constructor •() → void 36 | : super core::Object::•() 37 | ; 38 | } 39 | class Mixin extends core::Object { 40 | constructor •() → void 41 | : super core::Object::•() 42 | ; 43 | } 44 | class Mix extends self::Base implements self::Mixin { 45 | constructor •() → void 46 | : super self::Base::•() 47 | ; 48 | } 49 | static method main() → dynamic { 50 | core::print(new self::Bar::•(4).x); 51 | new self::SimpleCaseImpl2::•(); 52 | new self::Mix::•(); 53 | } 54 | -------------------------------------------------------------------------------- /lib/kernel.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | /// Conventions for paths: 6 | /// 7 | /// - Use the [Uri] class for paths that may have the `file`, `dart` or 8 | /// `package` scheme. Never use [Uri] for relative paths. 9 | /// - Use [String]s for all filenames and paths that have no scheme prefix. 10 | /// - Never translate a `dart:` or `package:` URI into a `file:` URI, instead 11 | /// translate it to a [String] if the file system path is needed. 12 | /// - Only use [File] from dart:io at the last moment when it is needed. 13 | /// 14 | library kernel; 15 | 16 | import 'ast.dart'; 17 | import 'binary/ast_to_binary.dart'; 18 | import 'binary/loader.dart'; 19 | import 'dart:async'; 20 | import 'dart:io'; 21 | import 'repository.dart'; 22 | import 'text/ast_to_text.dart'; 23 | 24 | export 'ast.dart'; 25 | export 'repository.dart'; 26 | 27 | Program loadProgramFromBinary(String path, [Repository repository]) { 28 | repository ??= new Repository(); 29 | return new BinaryLoader(repository).loadProgram(path); 30 | } 31 | 32 | Future writeProgramToBinary(Program program, String path) { 33 | var sink = new File(path).openWrite(); 34 | var future; 35 | try { 36 | new BinaryPrinter(sink).writeProgramFile(program); 37 | } finally { 38 | future = sink.close(); 39 | } 40 | return future; 41 | } 42 | 43 | void writeLibraryToText(Library library, {String path}) { 44 | StringBuffer buffer = new StringBuffer(); 45 | new Printer(buffer).writeLibraryFile(library); 46 | if (path == null) { 47 | print(buffer); 48 | } else { 49 | new File(path).writeAsStringSync('$buffer'); 50 | } 51 | } 52 | 53 | void writeProgramToText(Program program, {String path, bool showExternal: false}) { 54 | StringBuffer buffer = new StringBuffer(); 55 | new Printer(buffer, showExternal: showExternal).writeProgramFile(program); 56 | if (path == null) { 57 | print(buffer); 58 | } else { 59 | new File(path).writeAsStringSync('$buffer'); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /test/baseline_strong_mode_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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:kernel/class_hierarchy.dart'; 5 | import 'package:kernel/core_types.dart'; 6 | import 'package:kernel/kernel.dart'; 7 | import 'package:kernel/transformations/mixin_full_resolution.dart'; 8 | import 'package:kernel/type_checker.dart'; 9 | import 'package:path/path.dart' as pathlib; 10 | 11 | import 'baseline_tester.dart'; 12 | 13 | class StrongModeTest extends TestTarget { 14 | @override 15 | List get extraRequiredLibraries => []; 16 | 17 | @override 18 | String get name => 'strong-mode-test'; 19 | 20 | @override 21 | bool get strongMode => true; 22 | 23 | @override 24 | List transformProgram(Program program) { 25 | List errors = []; 26 | new MixinFullResolution().transform(program); 27 | new TestTypeChecker( 28 | errors, new CoreTypes(program), new ClassHierarchy(program)) 29 | .checkProgram(program); 30 | return errors; 31 | } 32 | } 33 | 34 | class TestTypeChecker extends TypeChecker { 35 | final List errors; 36 | 37 | TestTypeChecker(this.errors, CoreTypes coreTypes, ClassHierarchy hierarchy) 38 | : super(coreTypes, hierarchy); 39 | 40 | @override 41 | void checkAssignable(TreeNode where, DartType from, DartType to) { 42 | if (!environment.isSubtypeOf(from, to)) { 43 | fail(where, '$from is not a subtype of $to'); 44 | } 45 | } 46 | 47 | @override 48 | void fail(TreeNode where, String message) { 49 | var location = where.location; 50 | var locationString; 51 | if (location != null) { 52 | var file = pathlib.basename(Uri.parse(location.file).path); 53 | locationString = '($file:${location.line}:${location.column})'; 54 | } else { 55 | locationString = '(no location)'; 56 | } 57 | errors.add('$message $locationString'); 58 | } 59 | } 60 | 61 | void main() { 62 | runBaselineTests('strong-mode', new StrongModeTest()); 63 | } 64 | -------------------------------------------------------------------------------- /test/frontend_bench.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | import 'dart:io'; 6 | import 'package:analyzer/src/context/cache.dart'; 7 | import 'package:analyzer/task/model.dart'; 8 | import 'package:args/args.dart'; 9 | import 'package:kernel/analyzer/loader.dart'; 10 | import 'package:kernel/kernel.dart'; 11 | import 'package:package_config/discovery.dart'; 12 | 13 | ArgParser parser = new ArgParser() 14 | ..addOption('sdk', 15 | help: 'Path to Dart SDK', valueHelp: 'path', defaultsTo: '/usr/lib/dart') 16 | ..addOption('packages', 17 | abbr: 'p', 18 | help: 'Path to the packages folder or .packages file', 19 | valueHelp: 'path') 20 | ..addFlag('strong', help: 'Use strong mode'); 21 | 22 | String get usage => ''' 23 | Usage: frontend_bench [options] FILE.dart 24 | 25 | Benchmark the analyzer-based frontend. 26 | 27 | Options: 28 | ${parser.options} 29 | '''; 30 | 31 | main(List args) { 32 | if (args.length == 0) { 33 | print(usage); 34 | exit(1); 35 | } 36 | ArgResults options = parser.parse(args); 37 | 38 | if (options.rest.length != 1) { 39 | print('Exactly one file must be given'); 40 | exit(1); 41 | } 42 | 43 | String sdk = options['sdk']; 44 | String packagePath = options['packages']; 45 | bool strongMode = options['strong']; 46 | 47 | String path = options.rest.single; 48 | var packages = 49 | getPackagesDirectory(new Uri(scheme: 'file', path: packagePath)); 50 | Repository repository = new Repository(); 51 | 52 | new DartLoader( 53 | repository, 54 | new DartOptions( 55 | strongMode: strongMode, sdk: sdk, packagePath: packagePath), 56 | packages) 57 | .loadProgram(path); 58 | 59 | CacheEntry.recomputedCounts.forEach((key, value) { 60 | print('Recomputed $key $value times'); 61 | }); 62 | 63 | AnalysisTask.stopwatchMap.forEach((key, Stopwatch watch) { 64 | print('$key took ${watch.elapsedMilliseconds} ms'); 65 | }); 66 | } 67 | -------------------------------------------------------------------------------- /testcases/strong-mode/redirecting_factory.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | abstract class FooBase extends core::Object { 6 | abstract get x() → core::int; 7 | } 8 | abstract class Foo extends core::Object implements self::FooBase { 9 | } 10 | class Bar extends core::Object implements self::Foo { 11 | field core::int x; 12 | constructor •(core::int x) → void 13 | : self::Bar::x = x, super core::Object::•() { 14 | core::print("Bar<${self::Bar::Sb},${self::Bar::Tb}>"); 15 | } 16 | } 17 | class Builder extends core::Object { 18 | constructor •() → void 19 | : super core::Object::•() 20 | ; 21 | method method() → dynamic { 22 | return new self::Bar::•(4); 23 | } 24 | } 25 | class SimpleCase extends core::Object { 26 | } 27 | class SimpleCaseImpl extends core::Object implements self::SimpleCase { 28 | } 29 | class SimpleCaseImpl2 extends core::Object implements self::SimpleCaseImpl { 30 | constructor •() → void 31 | : super core::Object::•() 32 | ; 33 | } 34 | class Base extends core::Object { 35 | constructor •() → void 36 | : super core::Object::•() 37 | ; 38 | } 39 | class Mixin extends core::Object { 40 | constructor •() → void 41 | : super core::Object::•() 42 | ; 43 | } 44 | class Mix extends self::Base implements self::Mixin { 45 | constructor •() → void 46 | : super self::Base::•() 47 | ; 48 | } 49 | static method main() → dynamic { 50 | core::print(new self::Bar::•(4).{self::FooBase::x}); 51 | new self::SimpleCaseImpl2::•(); 52 | new self::Mix::•(); 53 | } 54 | -------------------------------------------------------------------------------- /testcases/type-propagation/redirecting_factory.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | abstract class FooBase extends core::Object { 6 | abstract get x() → core::int/; 7 | } 8 | abstract class Foo extends core::Object implements self::FooBase { 9 | } 10 | class Bar extends core::Object implements self::Foo { 11 | field core::int/core::int* {int} x; 12 | constructor •(core::int/core::int* {int} x) → void 13 | : self::Bar::x = x, super core::Object::•() { 14 | core::print("Bar<${self::Bar::Sb},${self::Bar::Tb}>"); 15 | } 16 | } 17 | class Builder extends core::Object { 18 | constructor •() → void 19 | : super core::Object::•() 20 | ; 21 | method method() → dynamic/self::Bar! {other} { 22 | return new self::Bar::•(4); 23 | } 24 | } 25 | class SimpleCase extends core::Object { 26 | } 27 | class SimpleCaseImpl extends core::Object implements self::SimpleCase { 28 | } 29 | class SimpleCaseImpl2 extends core::Object implements self::SimpleCaseImpl { 30 | constructor •() → void 31 | : super core::Object::•() 32 | ; 33 | } 34 | class Base extends core::Object { 35 | constructor •() → void 36 | : super core::Object::•() 37 | ; 38 | } 39 | class Mixin extends core::Object { 40 | constructor •() → void 41 | : super core::Object::•() 42 | ; 43 | } 44 | class Mix extends self::Base implements self::Mixin { 45 | constructor •() → void 46 | : super self::Base::•() 47 | ; 48 | } 49 | static method main() → dynamic/Null { 50 | core::print(new self::Bar::•(4).x); 51 | new self::SimpleCaseImpl2::•(); 52 | new self::Mix::•(); 53 | } 54 | -------------------------------------------------------------------------------- /testcases/spec-mode/optional.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | method method(dynamic x, [dynamic y, dynamic z]) → dynamic { 10 | return "string"; 11 | } 12 | } 13 | abstract class External extends core::Object { 14 | constructor •() → void 15 | : super core::Object::•() 16 | ; 17 | abstract method externalMethod(core::int x, [core::int y, core::int z]) → core::String; 18 | abstract method listen(self::Listener listener) → void; 19 | } 20 | abstract class Listener extends core::Object { 21 | constructor •() → void 22 | : super core::Object::•() 23 | ; 24 | abstract method event(core::String input, [core::int x, core::int y]) → void; 25 | } 26 | class TestListener extends self::Listener { 27 | constructor •() → void 28 | : super self::Listener::•() 29 | ; 30 | method event(dynamic input, [dynamic x, dynamic y]) → void {} 31 | } 32 | class ExtendedListener extends self::Listener { 33 | constructor •() → void 34 | : super self::Listener::•() 35 | ; 36 | method event(dynamic input, [dynamic x, dynamic y, dynamic z]) → void {} 37 | } 38 | class InvalidListener extends core::Object { 39 | constructor •() → void 40 | : super core::Object::•() 41 | ; 42 | method event(dynamic input, [dynamic x]) → void {} 43 | } 44 | external static method createExternal() → self::External; 45 | static method main() → dynamic { 46 | dynamic foo = new self::Foo::•(); 47 | dynamic string1 = foo.method(1); 48 | dynamic string2 = foo.method(1, 2); 49 | dynamic string3 = foo.method(1, 2, 3); 50 | dynamic extern = self::createExternal(); 51 | dynamic string4 = extern.externalMethod(1); 52 | dynamic string5 = extern.externalMethod(1, 2); 53 | dynamic string6 = extern.externalMethod(1, 2, 3); 54 | extern.listen(new self::TestListener::•()); 55 | extern.listen(new self::ExtendedListener::•()); 56 | extern.listen(new self::InvalidListener::•()); 57 | dynamic nothing1 = foo.method(); 58 | dynamic nothing2 = foo.method(1, 2, 3, 4); 59 | dynamic nothing3 = extern.externalMethod(); 60 | dynamic nothing4 = extern.externalMethod(1, 2, 3, 4); 61 | } 62 | -------------------------------------------------------------------------------- /lib/target/targets.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.target.targets; 5 | 6 | import '../ast.dart'; 7 | 8 | import 'vm.dart'; 9 | import 'flutter.dart'; 10 | 11 | final List targetNames = targets.keys.toList(); 12 | 13 | class TargetFlags { 14 | bool strongMode; 15 | TargetFlags({this.strongMode: false}); 16 | } 17 | 18 | typedef Target _TargetBuilder(TargetFlags flags); 19 | 20 | final Map targets = { 21 | 'none': (TargetFlags flags) => new NoneTarget(flags), 22 | 'vm': (TargetFlags flags) => new VmTarget(flags), 23 | 'flutter': (TargetFlags flags) => new FlutterTarget(flags), 24 | }; 25 | 26 | Target getTarget(String name, TargetFlags flags) { 27 | var builder = targets[name]; 28 | if (builder == null) return null; 29 | return builder(flags); 30 | } 31 | 32 | /// A target provides backend-specific options for generating kernel IR. 33 | abstract class Target { 34 | String get name; 35 | 36 | /// A list of URIs of required libraries, not including dart:core. 37 | /// 38 | /// Libraries will be loaded in order. 39 | List get extraRequiredLibraries => []; 40 | 41 | /// Additional declared variables implied by this target. 42 | /// 43 | /// These can also be passed on the command-line of form `-D=`, 44 | /// and those provided on the command-line take precedence over those defined 45 | /// by the target. 46 | Map get extraDeclaredVariables => const {}; 47 | 48 | bool get strongMode; 49 | 50 | /// If true, the SDK should be loaded in strong mode. 51 | bool get strongModeSdk => strongMode; 52 | 53 | void transformProgram(Program program); 54 | 55 | String toString() => 'Target($name)'; 56 | } 57 | 58 | class NoneTarget extends Target { 59 | final TargetFlags flags; 60 | 61 | NoneTarget(this.flags); 62 | 63 | bool get strongMode => flags.strongMode; 64 | String get name => 'none'; 65 | List get extraRequiredLibraries => []; 66 | void transformProgram(Program program) {} 67 | } 68 | -------------------------------------------------------------------------------- /lib/target/flutter.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.target.flutter; 5 | 6 | import '../ast.dart'; 7 | import '../transformations/continuation.dart' as cont; 8 | import '../transformations/erasure.dart'; 9 | import '../transformations/sanitize_for_vm.dart'; 10 | import '../transformations/mixin_full_resolution.dart' as mix; 11 | import '../transformations/setup_builtin_library.dart' as setup_builtin_library; 12 | import 'targets.dart'; 13 | 14 | class FlutterTarget extends Target { 15 | final TargetFlags flags; 16 | 17 | FlutterTarget(this.flags); 18 | 19 | bool get strongMode => flags.strongMode; 20 | 21 | bool get strongModeSdk => false; 22 | 23 | String get name => 'flutter'; 24 | 25 | // This is the order that bootstrap libraries are loaded according to 26 | // `runtime/vm/object_store.h`. 27 | List get extraRequiredLibraries => const [ 28 | 'dart:async', 29 | 'dart:collection', 30 | 'dart:convert', 31 | 'dart:developer', 32 | 'dart:_internal', 33 | 'dart:isolate', 34 | 'dart:math', 35 | 36 | // The library dart:mirrors may be ignored by the VM, e.g. when built in 37 | // PRODUCT mode. 38 | 'dart:mirrors', 39 | 40 | 'dart:profiler', 41 | 'dart:typed_data', 42 | 'dart:_vmservice', 43 | 'dart:_builtin', 44 | 'dart:nativewrappers', 45 | 'dart:io', 46 | 47 | // Required for flutter. 48 | 'dart:ui', 49 | 'dart:jni', 50 | 'dart:mojo.internal', 51 | 'dart:vmservice_sky', 52 | ]; 53 | 54 | void transformProgram(Program program) { 55 | new mix.MixinFullResolution().transform(program); 56 | cont.transformProgram(program); 57 | 58 | // Repair `_getMainClosure()` function in dart:{_builtin,ui} libraries. 59 | setup_builtin_library.transformProgram(program); 60 | setup_builtin_library.transformProgram(program, libraryUri: 'dart:ui'); 61 | 62 | if (strongMode) { 63 | new Erasure().transform(program); 64 | } 65 | 66 | new SanitizeForVM().transform(program); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/target/vm.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.target.vm; 5 | 6 | import '../ast.dart'; 7 | import '../transformations/continuation.dart' as cont; 8 | import '../transformations/erasure.dart'; 9 | import '../transformations/mixin_full_resolution.dart' as mix; 10 | import '../transformations/sanitize_for_vm.dart'; 11 | import '../transformations/setup_builtin_library.dart' as setup_builtin_library; 12 | import 'targets.dart'; 13 | 14 | /// Specializes the kernel IR to the Dart VM. 15 | class VmTarget extends Target { 16 | final TargetFlags flags; 17 | 18 | VmTarget(this.flags); 19 | 20 | bool get strongMode => flags.strongMode; 21 | 22 | /// The VM patch files are not strong mode clean, so we adopt a hybrid mode 23 | /// where the SDK is internally unchecked, but trusted to satisfy the types 24 | /// declared on its interface. 25 | bool get strongModeSdk => false; 26 | 27 | String get name => 'vm'; 28 | 29 | // This is the order that bootstrap libraries are loaded according to 30 | // `runtime/vm/object_store.h`. 31 | List get extraRequiredLibraries => const [ 32 | 'dart:async', 33 | 'dart:collection', 34 | 'dart:convert', 35 | 'dart:developer', 36 | 'dart:_internal', 37 | 'dart:isolate', 38 | 'dart:math', 39 | 40 | // The library dart:mirrors may be ignored by the VM, e.g. when built in 41 | // PRODUCT mode. 42 | 'dart:mirrors', 43 | 44 | 'dart:profiler', 45 | 'dart:typed_data', 46 | 'dart:vmservice_io', 47 | 'dart:_vmservice', 48 | 'dart:_builtin', 49 | 'dart:nativewrappers', 50 | 'dart:io', 51 | ]; 52 | 53 | void transformProgram(Program program) { 54 | new mix.MixinFullResolution().transform(program); 55 | cont.transformProgram(program); 56 | 57 | // Repair `_getMainClosure()` function in dart:_builtin. 58 | setup_builtin_library.transformProgram(program); 59 | 60 | if (strongMode) { 61 | new Erasure().transform(program); 62 | } 63 | 64 | new SanitizeForVM().transform(program); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /testcases/type-propagation/call.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Callable extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | method call(dynamic/core::int* {int} x) → dynamic/core::String* {string} { 10 | return "string"; 11 | } 12 | } 13 | class CallableGetter extends core::Object { 14 | constructor •() → void 15 | : super core::Object::•() 16 | ; 17 | get call() → dynamic/self::Callable! {other} 18 | return new self::Callable::•(); 19 | } 20 | static method main() → dynamic/Null { 21 | dynamic/core::Function* {other} closure = (dynamic/core::int* {int} x) → dynamic/core::int* {int} => x; 22 | dynamic/core::int* {int} int1 = closure.call(1); 23 | dynamic/core::int* {int} int2 = closure.call(1); 24 | dynamic/core::int* {int} int3 = closure.call.call(1); 25 | dynamic/core::int* {int} int4 = closure.call.call.call(1); 26 | dynamic/self::Callable! {other} callable = new self::Callable::•(); 27 | dynamic/core::String* {string} string1 = callable.call(1); 28 | dynamic/core::String* {string} string2 = callable.call(1); 29 | dynamic/core::String* {string} string3 = callable.call.call(1); 30 | dynamic/core::String* {string} string4 = callable.call.call.call(1); 31 | dynamic/self::CallableGetter! {other} callableGetter = new self::CallableGetter::•(); 32 | dynamic/core::String* {string} string5 = callableGetter.call(1); 33 | dynamic/core::String* {string} string6 = callableGetter.call(1); 34 | dynamic/core::String* {string} string7 = callableGetter.call.call(1); 35 | dynamic/core::String* {string} string8 = callableGetter.call.call.call(1); 36 | dynamic/Nothing nothing1 = closure.call(); 37 | dynamic/Nothing nothing2 = closure.call(); 38 | dynamic/Nothing nothing3 = closure.call.call(); 39 | dynamic/Nothing nothing4 = closure.call.call.call(); 40 | dynamic/Nothing nothing5 = callable.call(); 41 | dynamic/Nothing nothing6 = callable.call(); 42 | dynamic/Nothing nothing7 = callable.call.call(); 43 | dynamic/Nothing nothing8 = callable.call.call.call(); 44 | dynamic/Nothing nothing9 = callableGetter.call(); 45 | dynamic/Nothing nothing10 = callableGetter.call(); 46 | dynamic/Nothing nothing11 = callableGetter.call.call(); 47 | dynamic/Nothing nothing12 = callableGetter.call.call.call(); 48 | } 49 | -------------------------------------------------------------------------------- /testcases/strong-mode/call.baseline.txt: -------------------------------------------------------------------------------- 1 | // Too few positional arguments (call.dart:30:17) 2 | // Too few positional arguments (call.dart:31:25) 3 | // Too few positional arguments (call.dart:35:17) 4 | // Too few positional arguments (call.dart:36:26) 5 | // Too few positional arguments (call.dart:37:31) 6 | library; 7 | import self as self; 8 | import "dart:core" as core; 9 | 10 | class Callable extends core::Object { 11 | constructor •() → void 12 | : super core::Object::•() 13 | ; 14 | method call(dynamic x) → dynamic { 15 | return "string"; 16 | } 17 | } 18 | class CallableGetter extends core::Object { 19 | constructor •() → void 20 | : super core::Object::•() 21 | ; 22 | get call() → dynamic 23 | return new self::Callable::•(); 24 | } 25 | static method main() → dynamic { 26 | (dynamic) → dynamic closure = (dynamic x) → dynamic => x; 27 | dynamic int1 = closure.call(1); 28 | dynamic int2 = closure.call(1); 29 | dynamic int3 = closure.call.call(1); 30 | dynamic int4 = closure.call.call.call(1); 31 | self::Callable callable = new self::Callable::•(); 32 | dynamic string1 = callable.{self::Callable::call}(1); 33 | dynamic string2 = callable.{self::Callable::call}(1); 34 | dynamic string3 = callable.{self::Callable::call}.call(1); 35 | dynamic string4 = callable.{self::Callable::call}.call.call(1); 36 | self::CallableGetter callableGetter = new self::CallableGetter::•(); 37 | dynamic string5 = callableGetter.call(1); 38 | dynamic string6 = callableGetter.{self::CallableGetter::call}.call(1); 39 | dynamic string7 = callableGetter.{self::CallableGetter::call}.call(1); 40 | dynamic string8 = callableGetter.{self::CallableGetter::call}.call.call(1); 41 | dynamic nothing1 = closure.call(); 42 | dynamic nothing2 = closure.call(); 43 | dynamic nothing3 = closure.call.call(); 44 | dynamic nothing4 = closure.call.call.call(); 45 | dynamic nothing5 = callable.{self::Callable::call}(); 46 | dynamic nothing6 = callable.{self::Callable::call}(); 47 | dynamic nothing7 = callable.{self::Callable::call}.call(); 48 | dynamic nothing8 = callable.{self::Callable::call}.call.call(); 49 | dynamic nothing9 = callableGetter.call(); 50 | dynamic nothing10 = callableGetter.{self::CallableGetter::call}.call(); 51 | dynamic nothing11 = callableGetter.{self::CallableGetter::call}.call(); 52 | dynamic nothing12 = callableGetter.{self::CallableGetter::call}.call.call(); 53 | } 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Moved 2 | ===== 3 | 4 | This has moved into the [Dart SDK repository](github.com/dart-lang/sdk). 5 | 6 | This repository is not kept up-to-date. 7 | 8 | Dart Kernel 9 | =========== 10 | **Dart Kernel** is a small high-level language derived from Dart. 11 | It is designed for use as an intermediate format for whole-program analysis 12 | and transformations, and as a frontend for codegen and execution backends. 13 | 14 | The kernel language has in-memory representations in Dart and C++, and 15 | can be serialized as binary or text. 16 | 17 | Both the kernel language and its implementations are unstable and are under development. 18 | 19 | This package contains the Dart part of the implementation and contains: 20 | - A transformable IR for the kernel language 21 | - A frontend based on the analyzer 22 | - Serialization of kernel code 23 | 24 | Getting Kernel 25 | ------------ 26 | 27 | Checkout the repository and run pub get: 28 | ```bash 29 | git clone https://github.com/dart-lang/kernel 30 | cd kernel 31 | pub get 32 | ``` 33 | 34 | Command-Line Tool 35 | ----------------- 36 | 37 | Run `bin/dartk.dart` from the command-line to convert between .dart files 38 | and the serialized binary and textual formats. 39 | 40 | `dartk` expects the `.dill` extension for files in the binary format. 41 | The textual format has no preferred extension right now. 42 | 43 | Example commands: 44 | ```bash 45 | dartk foo.dart # print text IR for foo.dart 46 | dartk foo.dart -ofoo.dill # write binary IR for foo.dart to foo.dill 47 | dartk foo.dill # print text IR for binary file foo.dill 48 | ``` 49 | 50 | Pass the `--link` or `-l` flag to link all transitive dependencies into one file: 51 | ```bash 52 | dartk myapp.dart -ppackages -l -omyapp.dill # Bundle everything. 53 | dartk myapp.dill # Print it back out in a (very, very long) textual format. 54 | ``` 55 | 56 | See [ast.dart](lib/ast.dart) for the in-memory IR, or [binary.md](binary.md) for 57 | a description of the binary format. For now, the textual format is very ad-hoc 58 | and cannot be parsed back in. 59 | 60 | 61 | Testing 62 | ------- 63 | 64 | If you plan to make changes to kernel, get a checkout of the Dartk SDK and run: 65 | ```bash 66 | tool/regenerate_dill_files.dart --sdk 67 | pub run test 68 | ``` 69 | 70 | 71 | Linking 72 | ------------------------- 73 | Linking from binary files is not yet implemented. In order to compile a whole 74 | program, currently everything must be compiled from source at once. 75 | -------------------------------------------------------------------------------- /test/round_trip.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.round_trip; 5 | 6 | import 'dart:async'; 7 | import 'dart:io'; 8 | import 'package:kernel/binary/ast_from_binary.dart'; 9 | import 'package:kernel/binary/ast_to_binary.dart'; 10 | import 'package:kernel/binary/loader.dart'; 11 | import 'package:kernel/kernel.dart'; 12 | 13 | const String usage = ''' 14 | Usage: round_trip.dart FILE.dill 15 | 16 | Deserialize and serialize the given program and check that the resulting byte 17 | sequence is identical to the original. 18 | '''; 19 | 20 | void main(List args) { 21 | if (args.length != 1) { 22 | print(usage); 23 | exit(1); 24 | } 25 | testRoundTrip(new File(args[0]).readAsBytesSync()); 26 | } 27 | 28 | void testRoundTrip(List bytes) { 29 | var loader = new BinaryLoader(new Repository()); 30 | var program = new BinaryBuilder(loader, bytes).readProgramFile(); 31 | new BinaryPrinterWithExpectedOutput(bytes).writeProgramFile(program); 32 | } 33 | 34 | class DummyStreamConsumer extends StreamConsumer> { 35 | @override 36 | Future addStream(Stream> stream) async => null; 37 | 38 | @override 39 | Future close() async => null; 40 | } 41 | 42 | /// Variant of the binary serializer that compares the output against an 43 | /// existing buffer. 44 | /// 45 | /// As opposed to comparing binary files directly, when this fails, the stack 46 | /// trace shows what the serializer was doing when the output started to differ. 47 | class BinaryPrinterWithExpectedOutput extends BinaryPrinter { 48 | final List expectedBytes; 49 | int offset = 0; 50 | 51 | static const int eof = -1; 52 | 53 | BinaryPrinterWithExpectedOutput(this.expectedBytes) 54 | : super(new IOSink(new DummyStreamConsumer())); 55 | 56 | 57 | String show(int byte) { 58 | if (byte == eof) return 'EOF'; 59 | return '$byte (0x${byte.toRadixString(16).padLeft(2, "0")})'; 60 | } 61 | 62 | @override 63 | void writeByte(int byte) { 64 | if (offset == expectedBytes.length || expectedBytes[offset] != byte) { 65 | int expected = 66 | (offset >= expectedBytes.length) ? eof : expectedBytes[offset]; 67 | throw 'At offset $offset: ' 68 | 'Expected ${show(expected)} but found ${show(byte)}'; 69 | } 70 | ++offset; 71 | } 72 | 73 | @override 74 | void writeBytes(List bytes) { 75 | bytes.forEach(writeByte); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /testcases/spec-mode/micro.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | method instanceMethod() → dynamic { 10 | return 123; 11 | } 12 | } 13 | abstract class ExternalValue extends core::Object { 14 | constructor •() → void 15 | : super core::Object::•() 16 | ; 17 | } 18 | abstract class Bar extends core::Object { 19 | constructor •() → void 20 | : super core::Object::•() 21 | ; 22 | abstract method externalInstanceMethod() → self::ExternalValue; 23 | } 24 | class Box extends core::Object { 25 | field dynamic field = null; 26 | constructor •() → void 27 | : super core::Object::•() 28 | ; 29 | } 30 | class FinalBox extends core::Object { 31 | final field dynamic finalField; 32 | constructor •(dynamic finalField) → void 33 | : self::FinalBox::finalField = finalField, super core::Object::•() 34 | ; 35 | } 36 | class SubFinalBox extends self::FinalBox { 37 | constructor •(dynamic value) → void 38 | : super self::FinalBox::•(value) 39 | ; 40 | } 41 | class DynamicReceiver1 extends core::Object { 42 | constructor •() → void 43 | : super core::Object::•() 44 | ; 45 | method dynamicallyCalled(dynamic x) → dynamic {} 46 | } 47 | class DynamicReceiver2 extends core::Object { 48 | constructor •() → void 49 | : super core::Object::•() 50 | ; 51 | method dynamicallyCalled(dynamic x) → dynamic {} 52 | } 53 | static method staticMethod() → dynamic { 54 | return "sdfg"; 55 | } 56 | external static method externalStatic() → core::bool; 57 | external static method createBar() → self::Bar; 58 | static method stringArgument(dynamic x) → dynamic {} 59 | static method intArgument(dynamic x) → dynamic {} 60 | static method makeDynamicCall(dynamic receiver) → void { 61 | receiver.dynamicallyCalled("sdfg"); 62 | } 63 | static method main() → dynamic { 64 | dynamic x = self::staticMethod(); 65 | dynamic y = new self::Foo::•().instanceMethod(); 66 | dynamic z = self::externalStatic(); 67 | dynamic w = self::createBar().externalInstanceMethod(); 68 | self::stringArgument("sdfg"); 69 | self::intArgument(42); 70 | dynamic box = new self::Box::•(); 71 | box.field = "sdfg"; 72 | dynamic a = box.field; 73 | dynamic finalBox = new self::FinalBox::•("dfg"); 74 | dynamic b = finalBox.finalField; 75 | dynamic subBox = new self::SubFinalBox::•("dfg"); 76 | dynamic c = subBox.finalField; 77 | self::makeDynamicCall(new self::DynamicReceiver1::•()); 78 | self::makeDynamicCall(new self::DynamicReceiver2::•()); 79 | dynamic list = ["string"]; 80 | dynamic d = list.[](0); 81 | } 82 | -------------------------------------------------------------------------------- /lib/frontend/super_initializers.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | /// A library to help move super calls last in the initializer list. 6 | library kernel.frontend.super_calls; 7 | 8 | import '../ast.dart'; 9 | 10 | /// Mutates the initializer list of [node] so that its super initializer occurs 11 | /// last, while its arguments are evaluated at the correct place. 12 | /// 13 | /// Does nothing if there is no super initializer or if it is already last. 14 | void moveSuperInitializerLast(Constructor node) { 15 | List initializers = node.initializers; 16 | if (initializers.isEmpty) return; 17 | if (initializers.last is SuperInitializer) return; 18 | int superIndex = -1; 19 | for (int i = initializers.length - 1; i >= 0; --i) { 20 | Initializer initializer = initializers[i]; 21 | if (initializer is SuperInitializer) { 22 | superIndex = i; 23 | break; 24 | } 25 | } 26 | if (superIndex == -1) return; 27 | SuperInitializer superCall = initializers[superIndex]; 28 | Arguments arguments = superCall.arguments; 29 | int argumentCount = arguments.positional.length + arguments.named.length; 30 | 31 | // We move all initializers after the super call to the place where the super 32 | // call was, but reserve [argumentCount] slots before that for 33 | // [LocalInitializer]s. 34 | initializers.length += argumentCount; 35 | initializers.setRange( 36 | superIndex + argumentCount, // desination start (inclusive) 37 | initializers.length - 1, // desination end (exclusive) 38 | initializers, // source list 39 | superIndex + 1); // source start index 40 | initializers[initializers.length - 1] = superCall; 41 | 42 | // Fill in the [argumentCount] reserved slots with the evaluation expressions 43 | // of the arguments to the super constructor call. 44 | int storeIndex = superIndex; 45 | for (int i = 0; i < arguments.positional.length; ++i) { 46 | var variable = new VariableDeclaration.forValue(arguments.positional[i]); 47 | arguments.positional[i] = new VariableGet(variable)..parent = arguments; 48 | initializers[storeIndex++] = new LocalInitializer(variable)..parent = node; 49 | } 50 | for (int i = 0; i < arguments.named.length; ++i) { 51 | NamedExpression argument = arguments.named[i]; 52 | var variable = new VariableDeclaration.forValue(argument.value); 53 | arguments.named[i].value = new VariableGet(variable)..parent = argument; 54 | initializers[storeIndex++] = new LocalInitializer(variable)..parent = node; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /testcases/strong-mode/optional.baseline.txt: -------------------------------------------------------------------------------- 1 | // #lib1::InvalidListener is not a subtype of #lib1::Listener (optional.dart:42:20) 2 | // Too few positional arguments (optional.dart:44:21) 3 | // Too many positional arguments (optional.dart:45:21) 4 | // Too few positional arguments (optional.dart:46:24) 5 | // Too many positional arguments (optional.dart:47:24) 6 | library; 7 | import self as self; 8 | import "dart:core" as core; 9 | 10 | class Foo extends core::Object { 11 | constructor •() → void 12 | : super core::Object::•() 13 | ; 14 | method method(dynamic x, [dynamic y, dynamic z]) → dynamic { 15 | return "string"; 16 | } 17 | } 18 | abstract class External extends core::Object { 19 | constructor •() → void 20 | : super core::Object::•() 21 | ; 22 | abstract method externalMethod(core::int x, [core::int y, core::int z]) → core::String; 23 | abstract method listen(self::Listener listener) → void; 24 | } 25 | abstract class Listener extends core::Object { 26 | constructor •() → void 27 | : super core::Object::•() 28 | ; 29 | abstract method event(core::String input, [core::int x, core::int y]) → void; 30 | } 31 | class TestListener extends self::Listener { 32 | constructor •() → void 33 | : super self::Listener::•() 34 | ; 35 | method event(core::String input, [core::int x, core::int y]) → void {} 36 | } 37 | class ExtendedListener extends self::Listener { 38 | constructor •() → void 39 | : super self::Listener::•() 40 | ; 41 | method event(core::String input, [core::int x, core::int y, dynamic z]) → void {} 42 | } 43 | class InvalidListener extends core::Object { 44 | constructor •() → void 45 | : super core::Object::•() 46 | ; 47 | method event(dynamic input, [dynamic x]) → void {} 48 | } 49 | external static method createExternal() → self::External; 50 | static method main() → dynamic { 51 | self::Foo foo = new self::Foo::•(); 52 | dynamic string1 = foo.{self::Foo::method}(1); 53 | dynamic string2 = foo.{self::Foo::method}(1, 2); 54 | dynamic string3 = foo.{self::Foo::method}(1, 2, 3); 55 | self::External extern = self::createExternal(); 56 | core::String string4 = extern.{self::External::externalMethod}(1); 57 | core::String string5 = extern.{self::External::externalMethod}(1, 2); 58 | core::String string6 = extern.{self::External::externalMethod}(1, 2, 3); 59 | extern.{self::External::listen}(new self::TestListener::•()); 60 | extern.{self::External::listen}(new self::ExtendedListener::•()); 61 | extern.{self::External::listen}(new self::InvalidListener::•()); 62 | dynamic nothing1 = foo.{self::Foo::method}(); 63 | dynamic nothing2 = foo.{self::Foo::method}(1, 2, 3, 4); 64 | core::String nothing3 = extern.{self::External::externalMethod}(); 65 | core::String nothing4 = extern.{self::External::externalMethod}(1, 2, 3, 4); 66 | } 67 | -------------------------------------------------------------------------------- /lib/repository.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.repository; 5 | 6 | import 'dart:io'; 7 | 8 | import 'package:path/path.dart' as pathlib; 9 | 10 | import 'ast.dart'; 11 | 12 | /// Keeps track of which [Library] objects have been created for a given URI. 13 | /// 14 | /// To load different files into the same IR, pass in the same repository 15 | /// object to the loaders. 16 | class Repository { 17 | final String workingDirectory; 18 | final Map _uriToLibrary = {}; 19 | final List libraries = []; 20 | 21 | Repository({String workingDirectory}) 22 | : this.workingDirectory = workingDirectory ?? Directory.current.path; 23 | 24 | /// Get the [Library] object for the library addresesd by [path]; possibly 25 | /// as an external library. 26 | /// 27 | /// The [path] may be a relative or absolute file path, or a URI string with a 28 | /// `dart:`, `package:` or `file:` scheme. 29 | /// 30 | /// Note that this method does not check if the library can be loaded at all. 31 | Library getLibrary(String path) { 32 | return getLibraryReference(normalizePath(path)); 33 | } 34 | 35 | String normalizeFileExtension(String path) { 36 | if (path.endsWith('.dill')) { 37 | return path.substring(0, path.length - '.dill'.length) + '.dart'; 38 | } else { 39 | return path; 40 | } 41 | } 42 | 43 | /// Get the canonical URI for the library addressed by the given [path]. 44 | /// 45 | /// The [path] may be a relative or absolute file path, or a URI string with a 46 | /// `dart:`, `package:` or `file:` scheme. 47 | Uri normalizePath(String path) { 48 | var uri = Uri.parse(path); 49 | if (!uri.hasScheme) { 50 | if (!pathlib.isAbsolute(path)) { 51 | path = pathlib.join(workingDirectory, path); 52 | } 53 | uri = new Uri(scheme: 'file', path: normalizeFileExtension(path)); 54 | } else if (uri.scheme == 'file') { 55 | var path = normalizeFileExtension(uri.path); 56 | if (!uri.hasAbsolutePath) { 57 | uri = uri.replace(path: pathlib.join(workingDirectory, path)); 58 | } else { 59 | uri = uri.replace(path: path); 60 | } 61 | } 62 | return uri; 63 | } 64 | 65 | Library getLibraryReference(Uri uri) { 66 | assert(uri.hasScheme); 67 | assert(uri.scheme != 'file' || uri.hasAbsolutePath); 68 | return _uriToLibrary.putIfAbsent(uri, () => _buildLibraryReference(uri)); 69 | } 70 | 71 | Library _buildLibraryReference(Uri uri) { 72 | var library = new Library(uri, isExternal: true); 73 | libraries.add(library); 74 | return library; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /testcases/strong-mode/micro.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | method instanceMethod() → dynamic { 10 | return 123; 11 | } 12 | } 13 | abstract class ExternalValue extends core::Object { 14 | constructor •() → void 15 | : super core::Object::•() 16 | ; 17 | } 18 | abstract class Bar extends core::Object { 19 | constructor •() → void 20 | : super core::Object::•() 21 | ; 22 | abstract method externalInstanceMethod() → self::ExternalValue; 23 | } 24 | class Box extends core::Object { 25 | field dynamic field = null; 26 | constructor •() → void 27 | : super core::Object::•() 28 | ; 29 | } 30 | class FinalBox extends core::Object { 31 | final field dynamic finalField; 32 | constructor •(dynamic finalField) → void 33 | : self::FinalBox::finalField = finalField, super core::Object::•() 34 | ; 35 | } 36 | class SubFinalBox extends self::FinalBox { 37 | constructor •(dynamic value) → void 38 | : super self::FinalBox::•(value) 39 | ; 40 | } 41 | class DynamicReceiver1 extends core::Object { 42 | constructor •() → void 43 | : super core::Object::•() 44 | ; 45 | method dynamicallyCalled(dynamic x) → dynamic {} 46 | } 47 | class DynamicReceiver2 extends core::Object { 48 | constructor •() → void 49 | : super core::Object::•() 50 | ; 51 | method dynamicallyCalled(dynamic x) → dynamic {} 52 | } 53 | static method staticMethod() → dynamic { 54 | return "sdfg"; 55 | } 56 | external static method externalStatic() → core::bool; 57 | external static method createBar() → self::Bar; 58 | static method stringArgument(dynamic x) → dynamic {} 59 | static method intArgument(dynamic x) → dynamic {} 60 | static method makeDynamicCall(dynamic receiver) → void { 61 | receiver.dynamicallyCalled("sdfg"); 62 | } 63 | static method main() → dynamic { 64 | dynamic x = self::staticMethod(); 65 | dynamic y = new self::Foo::•().{self::Foo::instanceMethod}(); 66 | core::bool z = self::externalStatic(); 67 | self::ExternalValue w = self::createBar().{self::Bar::externalInstanceMethod}(); 68 | self::stringArgument("sdfg"); 69 | self::intArgument(42); 70 | self::Box box = new self::Box::•(); 71 | box.{self::Box::field} = "sdfg"; 72 | dynamic a = box.{self::Box::field}; 73 | self::FinalBox finalBox = new self::FinalBox::•("dfg"); 74 | dynamic b = finalBox.{self::FinalBox::finalField}; 75 | self::SubFinalBox subBox = new self::SubFinalBox::•("dfg"); 76 | dynamic c = subBox.{self::FinalBox::finalField}; 77 | self::makeDynamicCall(new self::DynamicReceiver1::•()); 78 | self::makeDynamicCall(new self::DynamicReceiver2::•()); 79 | core::List list = ["string"]; 80 | core::String d = list.{core::List::[]}(0); 81 | } 82 | -------------------------------------------------------------------------------- /testcases/type-propagation/optional.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | method method(dynamic/core::int* {int} x, [dynamic/core::int* {null,int} y, dynamic/core::int* {null,int} z]) → dynamic/core::String* {string} { 10 | return "string"; 11 | } 12 | } 13 | abstract class External extends core::Object { 14 | constructor •() → void 15 | : super core::Object::•() 16 | ; 17 | abstract method externalMethod(core::int/ x, [core::int/ y, core::int/ z]) → core::String/; 18 | abstract method listen(self::Listener/ listener) → void/; 19 | } 20 | abstract class Listener extends core::Object { 21 | constructor •() → void 22 | : super core::Object::•() 23 | ; 24 | abstract method event(core::String/ input, [core::int/ x, core::int/ y]) → void/; 25 | } 26 | class TestListener extends self::Listener { 27 | constructor •() → void 28 | : super self::Listener::•() 29 | ; 30 | method event(dynamic/core::String* {string} input, [dynamic/core::int* {null,int} x, dynamic/core::int* {null,int} y]) → void/Null {} 31 | } 32 | class ExtendedListener extends self::Listener { 33 | constructor •() → void 34 | : super self::Listener::•() 35 | ; 36 | method event(dynamic/core::String* {string} input, [dynamic/core::int* {null,int} x, dynamic/core::int* {null,int} y, dynamic/Null z]) → void/Null {} 37 | } 38 | class InvalidListener extends core::Object { 39 | constructor •() → void 40 | : super core::Object::•() 41 | ; 42 | method event(dynamic/core::String* {string} input, [dynamic/core::int* {null,int} x]) → void/Null {} 43 | } 44 | external static method createExternal() → self::External/self::External* {other}; 45 | static method main() → dynamic/Null { 46 | dynamic/self::Foo! {other} foo = new self::Foo::•(); 47 | dynamic/core::String* {string} string1 = foo.method(1); 48 | dynamic/core::String* {string} string2 = foo.method(1, 2); 49 | dynamic/core::String* {string} string3 = foo.method(1, 2, 3); 50 | dynamic/self::External* {other} extern = self::createExternal(); 51 | dynamic/core::String* {string} string4 = extern.externalMethod(1); 52 | dynamic/core::String* {string} string5 = extern.externalMethod(1, 2); 53 | dynamic/core::String* {string} string6 = extern.externalMethod(1, 2, 3); 54 | extern.listen(new self::TestListener::•()); 55 | extern.listen(new self::ExtendedListener::•()); 56 | extern.listen(new self::InvalidListener::•()); 57 | dynamic/Nothing nothing1 = foo.method(); 58 | dynamic/Nothing nothing2 = foo.method(1, 2, 3, 4); 59 | dynamic/Nothing nothing3 = extern.externalMethod(); 60 | dynamic/Nothing nothing4 = extern.externalMethod(1, 2, 3, 4); 61 | } 62 | -------------------------------------------------------------------------------- /test/batch_consistency.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.batch_consistency; 5 | 6 | import 'dart:async'; 7 | import 'dart:io'; 8 | import '../bin/dartk.dart' as dartk; 9 | import '../bin/batch_util.dart'; 10 | import 'package:path/path.dart' as pathlib; 11 | import 'package:test/test.dart'; 12 | 13 | String usage = """ 14 | Usage: batch_consistency [options] -- files... 15 | 16 | Run dartk on the given files, both separately and in a batch, and check that 17 | the output is identical for the two modes. 18 | """; 19 | 20 | const String outputDir = 'out/batch-consistency'; 21 | 22 | main(List args) async { 23 | int separator = args.indexOf('--'); 24 | if (separator == -1) { 25 | print(usage); 26 | exit(1); 27 | } 28 | 29 | List options = args.sublist(0, separator); 30 | List files = args.sublist(separator + 1); 31 | 32 | await new Directory(outputDir).create(recursive: true); 33 | 34 | testBatchModeConsistency(options, files); 35 | } 36 | 37 | Future areFilesEqual(String first, String second) async { 38 | List> bytes = await Future.wait([ 39 | new File(first).readAsBytes(), 40 | new File(second).readAsBytes() 41 | ]); 42 | if (bytes[0].length != bytes[1].length) return false; 43 | for (int i = 0; i < bytes[0].length; ++i) { 44 | if (bytes[0][i] != bytes[1][i]) return false; 45 | } 46 | return true; 47 | } 48 | 49 | testBatchModeConsistency(List options, List files) { 50 | var sharedState = new dartk.BatchModeState(); 51 | for (String file in files) { 52 | test(file, () async { 53 | var name = pathlib.basename(file); 54 | List outputFiles = [ 55 | '$outputDir/$name.batch.dill', 56 | '$outputDir/$name.unbatch.dill' 57 | ]; 58 | List results = [null, null]; 59 | bool failed = false; 60 | for (int i = 0; i < 2; ++i) { 61 | var args = []..addAll(options)..addAll(['--out', outputFiles[i], file]); 62 | var state = (i == 0) ? sharedState : new dartk.BatchModeState(); 63 | try { 64 | // We run the two executions in a loop to ensure any stack traces 65 | // are identical in case they both crash at the same place. 66 | // Crashing at the same place is acceptable for the purpose of 67 | // this test, there are other tests that check for crashes. 68 | results[i] = await dartk.batchMain(args, state); 69 | } catch (e) { 70 | results[i] = '$e'; 71 | failed = true; 72 | } 73 | } 74 | if (results[0] != results[1]) { 75 | fail('Batch mode returned ${results[0]}, expected ${results[1]}'); 76 | return; 77 | } 78 | if (results[0] == CompilerOutcome.Fail) { 79 | failed = true; 80 | } 81 | if (!failed && !await areFilesEqual(outputFiles[0], outputFiles[1])) { 82 | fail('Batch mode output differs for $file'); 83 | } 84 | }); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /testcases/type-propagation/micro.baseline.txt: -------------------------------------------------------------------------------- 1 | library; 2 | import self as self; 3 | import "dart:core" as core; 4 | 5 | class Foo extends core::Object { 6 | constructor •() → void 7 | : super core::Object::•() 8 | ; 9 | method instanceMethod() → dynamic/core::int* {int} { 10 | return 123; 11 | } 12 | } 13 | abstract class ExternalValue extends core::Object { 14 | constructor •() → void 15 | : super core::Object::•() 16 | ; 17 | } 18 | abstract class Bar extends core::Object { 19 | constructor •() → void 20 | : super core::Object::•() 21 | ; 22 | abstract method externalInstanceMethod() → self::ExternalValue/; 23 | } 24 | class Box extends core::Object { 25 | field dynamic/core::String* {null,string} field = null; 26 | constructor •() → void 27 | : super core::Object::•() 28 | ; 29 | } 30 | class FinalBox extends core::Object { 31 | final field dynamic/core::String* {string} finalField; 32 | constructor •(dynamic/core::String* {string} finalField) → void 33 | : self::FinalBox::finalField = finalField, super core::Object::•() 34 | ; 35 | } 36 | class SubFinalBox extends self::FinalBox { 37 | constructor •(dynamic/core::String* {string} value) → void 38 | : super self::FinalBox::•(value) 39 | ; 40 | } 41 | class DynamicReceiver1 extends core::Object { 42 | constructor •() → void 43 | : super core::Object::•() 44 | ; 45 | method dynamicallyCalled(dynamic/core::String* {string} x) → dynamic/Null {} 46 | } 47 | class DynamicReceiver2 extends core::Object { 48 | constructor •() → void 49 | : super core::Object::•() 50 | ; 51 | method dynamicallyCalled(dynamic/core::String* {string} x) → dynamic/Null {} 52 | } 53 | static method staticMethod() → dynamic/core::String* {string} { 54 | return "sdfg"; 55 | } 56 | external static method externalStatic() → core::bool/core::bool* {other}; 57 | external static method createBar() → self::Bar/self::Bar* {other}; 58 | static method stringArgument(dynamic/core::String* {string} x) → dynamic/Null {} 59 | static method intArgument(dynamic/core::int* {int} x) → dynamic/Null {} 60 | static method makeDynamicCall(dynamic/core::Object+ {other} receiver) → void/Null { 61 | receiver.dynamicallyCalled("sdfg"); 62 | } 63 | static method main() → dynamic/Null { 64 | dynamic/core::String* {string} x = self::staticMethod(); 65 | dynamic/core::int* {int} y = new self::Foo::•().instanceMethod(); 66 | dynamic/core::bool* {other} z = self::externalStatic(); 67 | dynamic/self::ExternalValue* {other} w = self::createBar().externalInstanceMethod(); 68 | self::stringArgument("sdfg"); 69 | self::intArgument(42); 70 | dynamic/self::Box! {other} box = new self::Box::•(); 71 | box.field = "sdfg"; 72 | dynamic/core::String* {null,string} a = box.field; 73 | dynamic/self::FinalBox! {other} finalBox = new self::FinalBox::•("dfg"); 74 | dynamic/core::String* {string} b = finalBox.finalField; 75 | dynamic/self::SubFinalBox! {other} subBox = new self::SubFinalBox::•("dfg"); 76 | dynamic/core::String* {string} c = subBox.finalField; 77 | self::makeDynamicCall(new self::DynamicReceiver1::•()); 78 | self::makeDynamicCall(new self::DynamicReceiver2::•()); 79 | dynamic/core::List* {other} list = ["string"]; 80 | dynamic/core::Object+ {*} d = list.[](0); 81 | } 82 | -------------------------------------------------------------------------------- /test/treeshaker_bench.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.treeshaker_bench; 5 | 6 | import 'dart:io'; 7 | 8 | import 'package:args/args.dart'; 9 | import 'package:kernel/class_hierarchy.dart'; 10 | import 'package:kernel/core_types.dart'; 11 | import 'package:kernel/kernel.dart'; 12 | import 'package:kernel/transformations/treeshaker.dart'; 13 | 14 | import 'class_hierarchy_basic.dart'; 15 | 16 | ArgParser argParser = new ArgParser() 17 | ..addFlag('basic', 18 | help: 'Use the basic class hierarchy implementation', negatable: false) 19 | ..addFlag('from-scratch', 20 | help: 'Rebuild class hierarchy for each tree shaking', negatable: false) 21 | ..addFlag('diagnose', 22 | abbr: 'd', help: 'Print internal diagnostics', negatable: false); 23 | 24 | String usage = ''' 25 | Usage: treeshaker_bench [options] FILE.dart 26 | 27 | Benchmark the tree shaker and the class hierarchy it depends on. 28 | 29 | Options: 30 | ${argParser.usage} 31 | '''; 32 | 33 | void main(List args) { 34 | if (args.length == 0) { 35 | print(usage); 36 | exit(1); 37 | } 38 | ArgResults options = argParser.parse(args); 39 | if (options.rest.length != 1) { 40 | print('Exactly one file must be given'); 41 | exit(1); 42 | } 43 | String filename = options.rest.single; 44 | 45 | Program program = loadProgramFromBinary(filename); 46 | 47 | ClassHierarchy buildClassHierarchy() { 48 | return options['basic'] 49 | ? new BasicClassHierarchy(program) 50 | : new ClassHierarchy(program); 51 | } 52 | 53 | CoreTypes coreTypes = new CoreTypes(program); 54 | 55 | var watch = new Stopwatch()..start(); 56 | ClassHierarchy sharedClassHierarchy = buildClassHierarchy(); 57 | int coldHierarchyTime = watch.elapsedMicroseconds; 58 | var shaker = new TreeShaker(program, 59 | hierarchy: sharedClassHierarchy, coreTypes: coreTypes); 60 | if (options['diagnose']) { 61 | print(shaker.getDiagnosticString()); 62 | } 63 | shaker = null; 64 | int coldTreeShakingTime = watch.elapsedMicroseconds; 65 | 66 | ClassHierarchy getClassHierarchy() { 67 | return options['from-scratch'] 68 | ? buildClassHierarchy() 69 | : sharedClassHierarchy; 70 | } 71 | 72 | const int numberOfTrials = 50; 73 | int hotHierarchyTime = 0; 74 | int hotTreeShakingTime = 0; 75 | watch.reset(); 76 | for (int i = 0; i < numberOfTrials; i++) { 77 | watch.reset(); 78 | var hierarchy = getClassHierarchy(); 79 | hotHierarchyTime += watch.elapsedMicroseconds; 80 | new TreeShaker(program, hierarchy: hierarchy, coreTypes: coreTypes); 81 | hotTreeShakingTime += watch.elapsedMicroseconds; 82 | } 83 | hotHierarchyTime ~/= numberOfTrials; 84 | hotTreeShakingTime ~/= numberOfTrials; 85 | 86 | var coldShakingMs = coldTreeShakingTime ~/ 1000; 87 | var coldHierarchyMs = coldHierarchyTime ~/ 1000; 88 | var hotShakingMs = hotTreeShakingTime ~/ 1000; 89 | var hotHierarchyMs = hotHierarchyTime ~/ 1000; 90 | 91 | print(''' 92 | build.cold $coldShakingMs ms ($coldHierarchyMs ms from hierarchy) 93 | build.hot $hotShakingMs ms ($hotHierarchyMs ms from hierarchy)'''); 94 | } 95 | -------------------------------------------------------------------------------- /tool/regenerate_dill_files.dart: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env dart 2 | // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 3 | // for details. All rights reserved. Use of this source code is governed by a 4 | // BSD-style license that can be found in the LICENSE file. 5 | import 'dart:io'; 6 | import 'package:args/args.dart'; 7 | import 'package:path/path.dart' as path; 8 | import 'package:kernel/kernel.dart'; 9 | import 'package:kernel/analyzer/loader.dart'; 10 | import 'dart:async'; 11 | 12 | ArgParser parser = new ArgParser() 13 | ..addOption('sdk', help: 'Path to the SDK checkout'); 14 | 15 | final String usage = """ 16 | Usage: regenerate_dill_files --sdk 17 | 18 | Recompiles all the .dill files that are under version control. 19 | """; 20 | 21 | DartLoaderBatch batch = new DartLoaderBatch(); 22 | 23 | Future compile({String dartFile, 24 | String sdk, 25 | String packageRoot, 26 | String output, 27 | bool strongMode: false}) async { 28 | var settings = new DartOptions(strongMode: strongMode, 29 | sdk: sdk, 30 | packagePath: packageRoot); 31 | String strongMessage = strongMode ? '(strong mode)' : ''; 32 | if (!new Directory(settings.sdk).existsSync()) { 33 | print('SDK not found: ${settings.sdk}'); 34 | exit(1); 35 | } 36 | print('Compiling $dartFile $strongMessage'); 37 | var repo = new Repository(); 38 | var loader = await batch.getLoader(repo, settings); 39 | var program = loader.loadProgram(dartFile); 40 | writeProgramToBinary(program, output); 41 | } 42 | 43 | final List buildDirs = [ 44 | 'DebugX64', 45 | 'DebugIA32', 46 | 'ReleaseX64', 47 | 'ReleaseIA32' 48 | ]; 49 | 50 | String getNewestBuildDir(String sdk) { 51 | var dirs = buildDirs 52 | .map((name) => new Directory('$sdk/out/$name')) 53 | .where((dir) => dir.existsSync()) 54 | .toList() 55 | ..sort((Directory dir1, Directory dir2) => 56 | dir1.statSync().modified.compareTo(dir2.statSync().modified)); 57 | if (dirs.isEmpty) { 58 | print('Could not find a build directory in $sdk/out.\n' 59 | 'Please compile the SDK first.'); 60 | exit(1); 61 | } 62 | return dirs.last.path; 63 | } 64 | 65 | main(List args) async { 66 | ArgResults options = parser.parse(args); 67 | String sdk = options['sdk']; 68 | if (sdk == null || options.rest.isNotEmpty) { 69 | print(usage); 70 | exit(1); 71 | } 72 | if (!new Directory(sdk).existsSync()) { 73 | print('SDK not found: $sdk'); 74 | exit(1); 75 | } 76 | String baseDir = path.dirname(path.dirname(Platform.script.toFilePath())); 77 | Directory.current = baseDir; 78 | 79 | // Compile files in test/data 80 | String sdkRoot = getNewestBuildDir(sdk) + '/obj/gen/patched_sdk'; 81 | String packageRoot = getNewestBuildDir(sdk) + '/packages'; 82 | String dart2js = '$sdk/pkg/compiler/lib/src/dart2js.dart'; 83 | await compile( 84 | sdk: sdkRoot, 85 | dartFile: dart2js, 86 | packageRoot: packageRoot, 87 | output: 'test/data/dart2js.dill'); 88 | await compile( 89 | sdk: sdkRoot, 90 | strongMode: true, 91 | dartFile: dart2js, 92 | packageRoot: packageRoot, 93 | output: 'test/data/dart2js-strong.dill'); 94 | await compile( 95 | sdk: sdkRoot, 96 | dartFile: 'test/data/boms.dart', 97 | output: 'test/data/boms.dill'); 98 | } 99 | -------------------------------------------------------------------------------- /test/baseline_tester.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 'dart:io'; 5 | 6 | import 'package:kernel/analyzer/loader.dart'; 7 | import 'package:kernel/kernel.dart'; 8 | import 'package:kernel/target/targets.dart'; 9 | import 'package:kernel/text/ast_to_text.dart'; 10 | import 'package:path/path.dart' as pathlib; 11 | import 'package:test/test.dart'; 12 | import 'package:kernel/checks.dart'; 13 | 14 | final String inputDirectory = 'testcases/input'; 15 | 16 | /// A target to be used for testing. 17 | /// 18 | /// To simplify testing dependencies, we avoid transformations that rely on 19 | /// a patched SDK or any SDK changes that have not landed in the main SDK. 20 | abstract class TestTarget extends Target { 21 | /// Annotations to apply on the textual output. 22 | Annotator get annotator => null; 23 | 24 | List transformProgram(Program program); 25 | } 26 | 27 | void runBaselineTests(String folderName, TestTarget target) { 28 | String outputDirectory = 'testcases/$folderName'; 29 | String sdk = pathlib.dirname(pathlib.dirname(Platform.resolvedExecutable)); 30 | var batch = new DartLoaderBatch(); 31 | Directory directory = new Directory(inputDirectory); 32 | for (FileSystemEntity file in directory.listSync()) { 33 | if (file is File && file.path.endsWith('.dart')) { 34 | String name = pathlib.basename(file.path); 35 | test(name, () async { 36 | String dartPath = file.path; 37 | String shortName = pathlib.withoutExtension(name); 38 | String filenameOfBaseline = '$outputDirectory/$shortName.baseline.txt'; 39 | String filenameOfCurrent = '$outputDirectory/$shortName.current.txt'; 40 | 41 | var repository = new Repository(); 42 | var loader = await batch.getLoader( 43 | repository, 44 | new DartOptions( 45 | strongMode: target.strongMode, 46 | sdk: sdk, 47 | declaredVariables: target.extraDeclaredVariables)); 48 | var program = loader.loadProgram(dartPath, target: target); 49 | runSanityChecks(program); 50 | var errors = target.transformProgram(program); 51 | runSanityChecks(program); 52 | 53 | var buffer = new StringBuffer(); 54 | for (var error in errors) { 55 | buffer.writeln('// $error'); 56 | } 57 | new Printer(buffer, annotator: target.annotator) 58 | .writeLibraryFile(program.mainMethod.enclosingLibrary); 59 | String current = '$buffer'; 60 | new File(filenameOfCurrent).writeAsStringSync(current); 61 | 62 | var baselineFile = new File(filenameOfBaseline); 63 | if (!baselineFile.existsSync()) { 64 | new File(filenameOfBaseline).writeAsStringSync(current); 65 | } else { 66 | var baseline = baselineFile.readAsStringSync(); 67 | if (baseline != current) { 68 | fail('Output of `$name` changed for $folderName.\n' 69 | 'Command to reset the baseline:\n' 70 | ' rm $filenameOfBaseline\n' 71 | 'Command to see the diff:\n' 72 | ' diff -cd $outputDirectory/$shortName.{baseline,current}.txt' 73 | '\n'); 74 | } 75 | } 76 | }); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/core_types.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.class_table; 5 | 6 | import 'ast.dart'; 7 | 8 | /// Provides access to the classes and libraries in the core libraries. 9 | class CoreTypes { 10 | final Map _dartLibraries = {}; 11 | Class objectClass; 12 | Class nullClass; 13 | Class boolClass; 14 | Class intClass; 15 | Class numClass; 16 | Class doubleClass; 17 | Class stringClass; 18 | Class listClass; 19 | Class mapClass; 20 | Class iterableClass; 21 | Class iteratorClass; 22 | Class futureClass; 23 | Class streamClass; 24 | Class symbolClass; 25 | Class internalSymbolClass; 26 | Class typeClass; 27 | Class functionClass; 28 | 29 | Library getCoreLibrary(String uri) => _dartLibraries[uri].library; 30 | 31 | Class getCoreClass(String libraryUri, String className) { 32 | return _dartLibraries[libraryUri].require(className); 33 | } 34 | 35 | Procedure getCoreProcedure(String libraryUri, String topLevelMemberName) { 36 | Library library = getCoreLibrary(libraryUri); 37 | for (Procedure procedure in library.procedures) { 38 | if (procedure.name.name == topLevelMemberName) return procedure; 39 | } 40 | throw 'Missing procedure ${topLevelMemberName} from $libraryUri'; 41 | } 42 | 43 | CoreTypes(Program program) { 44 | for (var library in program.libraries) { 45 | if (library.importUri.scheme == 'dart') { 46 | _dartLibraries['${library.importUri}'] = new _LibraryIndex(library); 47 | } 48 | } 49 | _LibraryIndex dartCore = _dartLibraries['dart:core']; 50 | _LibraryIndex dartAsync = _dartLibraries['dart:async']; 51 | _LibraryIndex dartInternal = _dartLibraries['dart:_internal']; 52 | objectClass = dartCore.require('Object'); 53 | nullClass = dartCore.require('Null'); 54 | boolClass = dartCore.require('bool'); 55 | intClass = dartCore.require('int'); 56 | numClass = dartCore.require('num'); 57 | doubleClass = dartCore.require('double'); 58 | stringClass = dartCore.require('String'); 59 | listClass = dartCore.require('List'); 60 | mapClass = dartCore.require('Map'); 61 | iterableClass = dartCore.require('Iterable'); 62 | iteratorClass = dartCore.require('Iterator'); 63 | symbolClass = dartCore.require('Symbol'); 64 | typeClass = dartCore.require('Type'); 65 | functionClass = dartCore.require('Function'); 66 | futureClass = dartAsync.require('Future'); 67 | streamClass = dartAsync.require('Stream'); 68 | internalSymbolClass = dartInternal.require('Symbol'); 69 | } 70 | } 71 | 72 | /// Provides by-name lookup of classes in a library. 73 | class _LibraryIndex { 74 | final Library library; 75 | final Map classes = {}; 76 | 77 | _LibraryIndex(this.library) { 78 | for (Class classNode in library.classes) { 79 | if (classNode.name != null) { 80 | classes[classNode.name] = classNode; 81 | } 82 | } 83 | } 84 | 85 | Class require(String name) { 86 | Class result = classes[name]; 87 | if (result == null) { 88 | if (library.isExternal) { 89 | throw 'Missing class $name from external library ${library.name}'; 90 | } else { 91 | throw 'Missing class $name from ${library.name}'; 92 | } 93 | } 94 | return result; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /bin/transform.dart: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env dart 2 | // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 3 | // for details. All rights reserved. Use of this source code is governed by a 4 | // BSD-style license that can be found in the LICENSE file. 5 | 6 | import 'dart:async'; 7 | import 'dart:io'; 8 | 9 | import 'package:args/args.dart'; 10 | import 'package:kernel/kernel.dart'; 11 | import 'package:kernel/checks.dart' as checks; 12 | import 'package:kernel/transformations/continuation.dart' as cont; 13 | import 'package:kernel/transformations/infer_values.dart' as infer_values; 14 | import 'package:kernel/transformations/mixin_full_resolution.dart' as mix; 15 | import 'package:kernel/transformations/closure_conversion.dart' as closures; 16 | import 'package:kernel/transformations/treeshaker.dart' as treeshaker; 17 | 18 | import 'batch_util.dart'; 19 | 20 | ArgParser parser = new ArgParser() 21 | ..addOption('format', 22 | abbr: 'f', 23 | allowed: ['text', 'bin'], 24 | defaultsTo: 'bin', 25 | help: 'Output format.') 26 | ..addOption('out', 27 | abbr: 'o', 28 | help: 'Output file.', 29 | defaultsTo: null) 30 | ..addFlag('verbose', 31 | abbr: 'v', 32 | negatable: false, 33 | help: 'Be verbose (e.g. prints transformed main library).', 34 | defaultsTo: false) 35 | ..addOption('transformation', 36 | abbr: 't', 37 | help: 'The transformation to apply.', 38 | defaultsTo: 'continuation'); 39 | 40 | main(List arguments) async { 41 | if (arguments.isNotEmpty && arguments[0] == '--batch') { 42 | if (arguments.length != 1) { 43 | throw '--batch cannot be used with other arguments'; 44 | } 45 | await runBatch((arguments) => runTransformation(arguments)); 46 | } else { 47 | CompilerOutcome outcome = await runTransformation(arguments); 48 | exit(outcome == CompilerOutcome.Ok ? 0 : 1); 49 | } 50 | } 51 | 52 | Future runTransformation(List arguments) async { 53 | ArgResults options = parser.parse(arguments); 54 | 55 | if (options.rest.length != 1) { 56 | throw 'Usage:\n${parser.usage}'; 57 | } 58 | 59 | var input = options.rest.first; 60 | var output = options['out']; 61 | var format = options['format']; 62 | var verbose = options['verbose']; 63 | 64 | if (output == null) { 65 | output = '${input.substring(0, input.lastIndexOf('.'))}.transformed.dill'; 66 | } 67 | 68 | var program = loadProgramFromBinary(input); 69 | switch (options['transformation']) { 70 | case 'continuation': 71 | program = cont.transformProgram(program); 72 | break; 73 | case 'infervalues': 74 | program = infer_values.transformProgram(program); 75 | break; 76 | case 'resolve-mixins': 77 | program = mix.transformProgram(program); 78 | break; 79 | case 'closures': 80 | program = closures.transformProgram(program); 81 | break; 82 | case 'treeshake': 83 | program = treeshaker.transformProgram(program); 84 | break; 85 | default: throw 'Unknown transformation'; 86 | } 87 | 88 | program.accept(new checks.CheckParentPointers()); 89 | 90 | if (format == 'text') { 91 | writeProgramToText(program, path: output); 92 | } else { 93 | assert(format == 'bin'); 94 | await writeProgramToBinary(program, output); 95 | } 96 | 97 | if (verbose) { 98 | writeLibraryToText(program.mainMethod.parent as Library); 99 | } 100 | 101 | return CompilerOutcome.Ok; 102 | } 103 | -------------------------------------------------------------------------------- /lib/type_propagation/canonicalizer.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.type_propagation.canonicalizer; 5 | 6 | import 'dart:collection'; 7 | 8 | /// Generates unique consecutive integer IDs for tuples of variable length. 9 | class TupleCanonicalizer { 10 | final HashMap, int> _table = new HashMap, int>( 11 | equals: _contentEquals, hashCode: _contentHashCode); 12 | final List> _canonicalList = >[]; 13 | List _buffer = []; 14 | 15 | void _push(Object value) { 16 | _buffer.add(value); 17 | } 18 | 19 | int _finish() { 20 | int index = _table[_buffer]; 21 | if (index == null) { 22 | index = _canonicalList.length; 23 | _canonicalList.add(_buffer); 24 | _table[_buffer] = index; 25 | _buffer = []; 26 | } else { 27 | // The item already existed. Reuse the buffer object for the next query. 28 | _buffer.clear(); 29 | } 30 | return index; 31 | } 32 | 33 | /// Generate or get the ID for a "unary tuple". 34 | int get1(Object first) { 35 | _push(first); 36 | return _finish(); 37 | } 38 | 39 | /// Generate or get the ID for a pair. 40 | int get2(Object first, Object second) { 41 | _push(first); 42 | _push(second); 43 | return _finish(); 44 | } 45 | 46 | /// Generate or get the ID for a triple. 47 | int get3(Object first, Object second, Object third) { 48 | _push(first); 49 | _push(second); 50 | _push(third); 51 | return _finish(); 52 | } 53 | 54 | List getFromIndex(int index) { 55 | return _canonicalList[index]; 56 | } 57 | 58 | int get length => _canonicalList.length; 59 | 60 | static bool _contentEquals(List first, List second) { 61 | if (first.length != second.length) return false; 62 | for (int i = 0; i < first.length; ++i) { 63 | if (first[i] != second[i]) return false; 64 | } 65 | return true; 66 | } 67 | 68 | static int _contentHashCode(List list) { 69 | int hash = 0; 70 | for (int i = 0; i < list.length; ++i) { 71 | hash = (hash * 31 + hash ^ list[i].hashCode) & 0x3fffffff; 72 | } 73 | return hash; 74 | } 75 | } 76 | 77 | /// Maps uint31 pairs to values of type [T]. 78 | class Uint31PairMap { 79 | final HashMap _table = new HashMap(hashCode: _bigintHash); 80 | int _key; 81 | 82 | /// Returns the value associated with the given pair, or `null` if no value 83 | /// is associated with the pair. 84 | /// 85 | /// This association can be changed using a subsequent call to [put]. 86 | T lookup(int x, int y) { 87 | assert(x >= 0 && x >> 31 == 0); 88 | assert(y >= 0 && y >> 31 == 0); 89 | int key = (x << 31) + y; 90 | _key = key; 91 | return _table[key]; 92 | } 93 | 94 | /// Associates [value] with the pair previously queried using [lookup]. 95 | void put(T value) { 96 | _table[_key] = value; 97 | } 98 | 99 | Iterable get values => _table.values; 100 | 101 | static int _bigintHash(int bigint) { 102 | int x = 0x3fffffff & (bigint >> 31); 103 | int y = 0x3fffffff & bigint; 104 | int hash = 0x3fffffff & (x * 1367); 105 | hash = 0x3fffffff & (y * 31 + hash ^ y); 106 | hash = 0x3fffffff & ((x ^ y) * 31 + hash ^ y); 107 | return hash; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /test/type_substitute_bounds_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.type_substitute_bounds_test; 5 | 6 | import 'package:kernel/kernel.dart'; 7 | import 'package:kernel/type_algebra.dart'; 8 | import 'package:test/test.dart'; 9 | import 'type_parser.dart'; 10 | 11 | final List testCases = [ 12 | testCase('T', {'T': bound('_', 'String')}, 'String'), 13 | testCase('List', {'T': bound('_', 'String')}, 'List'), 14 | testCase('List>', {'T': bound('_', 'String')}, 'List>'), 15 | testCase('(T) => T', {'T': bound('_', 'String')}, '(_) => String'), 16 | testCase('(G,T) => T', {'T': bound('_', 'String')}, '(G,_) => String'), 17 | testCase( 18 | '(G,x:T) => T', {'T': bound('_', 'String')}, '(G,x:_) => String'), 19 | testCase('(G) => G', {'T': bound('_', 'String')}, '(G) => G'), 20 | testCase('(G) => G', {'T': bound('int', 'num')}, '(G) => G'), 21 | testCase('(T,G) => void', {'T': bound('_', 'String')}, '(_,G) => void'), 22 | testCase('(T) => void', {'T': bound('_', 'String')}, '(_) => void'), 23 | testCase('(int) => T', {'T': bound('_', 'String')}, '(int) => String'), 24 | testCase('(int) => int', {'T': bound('_', 'String')}, '(int) => int'), 25 | testCase('((T) => int) => int', {'T': bound('_', 'String')}, 26 | '((String) => int) => int'), 27 | testCase('((T) => int) => int', {'T': bound('_', 'String')}, 28 | '((String) => int) => int'), 29 | testCase('((T) => int) => int', {'T': bound('_', 'String')}, 30 | '((String) => int) => int'), 31 | testCase('((T) => int) => int', {'T': bound('_', 'String')}, 32 | '((String) => int) => int'), 33 | ]; 34 | 35 | class TestCase { 36 | final String type; 37 | final Map bounds; 38 | final String expected; 39 | 40 | TestCase(this.type, this.bounds, this.expected); 41 | 42 | String toString() { 43 | var substitution = bounds.keys.map((key) { 44 | var bound = bounds[key]; 45 | return '${bound.lower} <: $key <: ${bound.upper}'; 46 | }).join(','); 47 | return '$type [$substitution] <: $expected'; 48 | } 49 | } 50 | 51 | class TypeBound { 52 | final String lower, upper; 53 | 54 | TypeBound(this.lower, this.upper); 55 | } 56 | 57 | TypeBound bound(String lower, String upper) => new TypeBound(lower, upper); 58 | 59 | TestCase testCase(String type, Map bounds, String expected) { 60 | return new TestCase(type, bounds, expected); 61 | } 62 | 63 | main() { 64 | for (var testCase in testCases) { 65 | test('$testCase', () { 66 | var environment = new LazyTypeEnvironment(); 67 | var type = environment.parse(testCase.type); 68 | var upperBounds = {}; 69 | var lowerBounds = {}; 70 | testCase.bounds.forEach((String name, TypeBound bounds) { 71 | var parameter = environment.getTypeParameter(name); 72 | upperBounds[parameter] = environment.parse(bounds.upper); 73 | lowerBounds[parameter] = environment.parse(bounds.lower); 74 | }); 75 | var substituted = Substitution 76 | .fromUpperAndLowerBounds(upperBounds, lowerBounds) 77 | .substituteType(type); 78 | var expected = environment.parse(testCase.expected); 79 | if (substituted != expected) { 80 | fail('Expected `$expected` but got `$substituted`'); 81 | } 82 | }); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/import_table.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.import_table; 5 | 6 | import 'ast.dart'; 7 | import 'package:path/path.dart' as path; 8 | 9 | abstract class ImportTable { 10 | int getImportIndex(Library library); 11 | } 12 | 13 | class ProgramImportTable implements ImportTable { 14 | final Map _libraryIndex = {}; 15 | 16 | ProgramImportTable(Program program) { 17 | for (int i = 0; i < program.libraries.length; ++i) { 18 | _libraryIndex[program.libraries[i]] = i; 19 | } 20 | } 21 | 22 | int getImportIndex(Library library) => _libraryIndex[library] ?? -1; 23 | } 24 | 25 | class LibraryImportTable implements ImportTable { 26 | final List _importPaths = []; 27 | final List _importedLibraries = []; 28 | final Map _libraryIndex = {}; 29 | 30 | factory LibraryImportTable(Library lib) { 31 | return new _ImportTableBuilder(lib).build(); 32 | } 33 | 34 | LibraryImportTable.empty(); 35 | 36 | /// The list of imports. 37 | /// 38 | /// Should not be modified directly, as the index map would go out of sync. 39 | List get importPaths => _importPaths; 40 | 41 | List get importedLibraries => _importedLibraries; 42 | 43 | int addImport(Library target, String importPath) { 44 | int index = _libraryIndex[target]; 45 | if (index != null) return index; 46 | index = _importPaths.length; 47 | _importPaths.add(importPath); 48 | _importedLibraries.add(target); 49 | _libraryIndex[target] = index; 50 | return index; 51 | } 52 | 53 | /// Returns the index of the given import, or -1 if not found. 54 | int getImportIndex(Library library) { 55 | return _libraryIndex[library] ?? -1; 56 | } 57 | 58 | String getImportPath(Library library) { 59 | return _importPaths[getImportIndex(library)]; 60 | } 61 | } 62 | 63 | /// Builds the import table for a given library. 64 | class _ImportTableBuilder extends RecursiveVisitor { 65 | final LibraryImportTable table = new LibraryImportTable.empty(); 66 | final Library referenceLibrary; 67 | 68 | LibraryImportTable build() { 69 | referenceLibrary.accept(this); 70 | return table; 71 | } 72 | 73 | _ImportTableBuilder(this.referenceLibrary) { 74 | table.addImport(referenceLibrary, ''); 75 | } 76 | 77 | void addLibraryImport(Library target) { 78 | if (target == referenceLibrary) return; // Self-reference is special. 79 | var referenceUri = referenceLibrary.importUri; 80 | var targetUri = target.importUri; 81 | if (targetUri == null) { 82 | throw '$referenceUri cannot refer to library without an import URI'; 83 | } 84 | if (targetUri.scheme == 'file' && referenceUri.scheme == 'file') { 85 | var targetDirectory = path.dirname(targetUri.path); 86 | var currentDirectory = path.dirname(referenceUri.path); 87 | var relativeDirectory = 88 | path.relative(targetDirectory, from: currentDirectory); 89 | var filename = path.basename(targetUri.path); 90 | table.addImport(target, '$relativeDirectory/$filename'); 91 | } else if (targetUri.scheme == 'file') { 92 | // Cannot import a file:URI from a dart:URI or package:URI. 93 | // We may want to remove this restriction, but for now it's just a sanity 94 | // check. 95 | throw '$referenceUri cannot refer to application library $targetUri'; 96 | } else { 97 | table.addImport(target, target.importUri.toString()); 98 | } 99 | } 100 | 101 | visitClassReference(Class node) { 102 | addLibraryImport(node.enclosingLibrary); 103 | } 104 | 105 | defaultMemberReference(Member node) { 106 | addLibraryImport(node.enclosingLibrary); 107 | } 108 | 109 | visitName(Name name) { 110 | if (name.library != null) { 111 | addLibraryImport(name.library); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /lib/binary/loader.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.binary.loader; 5 | 6 | import '../repository.dart'; 7 | import '../ast.dart'; 8 | import 'tag.dart'; 9 | import 'dart:io'; 10 | import 'ast_from_binary.dart'; 11 | 12 | abstract class BinaryReferenceLoader { 13 | Library getLibraryReference(Library from, String relativePath); 14 | Class getClassReference(Library library, int tag, int index); 15 | Member getMemberReference(TreeNode classOrLibrary, int tag, int index); 16 | Member getLibraryMemberReference(Library library, int tag, int index); 17 | Member getClassMemberReference(Class classNode, int tag, int index); 18 | } 19 | 20 | class BinaryLoader implements BinaryReferenceLoader { 21 | final Repository repository; 22 | 23 | BinaryLoader(this.repository); 24 | 25 | Library getLibraryReference(Library from, String relativePath) { 26 | var fullUri = from.importUri.resolve(relativePath); 27 | return repository.getLibraryReference(fullUri); 28 | } 29 | 30 | static int _pow2roundup(int x) { 31 | --x; 32 | x |= x >> 1; 33 | x |= x >> 2; 34 | x |= x >> 4; 35 | x |= x >> 8; 36 | x |= x >> 16; 37 | return x + 1; 38 | } 39 | 40 | TreeNode _extendList( 41 | TreeNode parent, List items, int index, TreeNode build()) { 42 | if (items.length <= index) { 43 | // Avoid excessive resizing by growing the list in steps. 44 | items.length = _pow2roundup(index + 1); 45 | } 46 | return items[index] ??= build()..parent = parent; 47 | } 48 | 49 | Class getClassReference(Library library, int tag, int index) { 50 | return _extendList( 51 | library, library.classes, index, () => _buildClassReference(tag)); 52 | } 53 | 54 | Class _buildClassReference(int tag) { 55 | return new Class(); 56 | } 57 | 58 | Field _buildFieldReference() { 59 | return new Field(null); 60 | } 61 | 62 | Constructor _buildConstructorReference() { 63 | return new Constructor(null); 64 | } 65 | 66 | Procedure _buildProcedureReference() { 67 | return new Procedure(null, null, null); 68 | } 69 | 70 | Member getMemberReference(TreeNode classOrLibrary, int tag, int index) { 71 | if (classOrLibrary is Class) { 72 | return getClassMemberReference(classOrLibrary, tag, index); 73 | } else { 74 | return getLibraryMemberReference(classOrLibrary, tag, index); 75 | } 76 | } 77 | 78 | Member getLibraryMemberReference(Library library, int tag, int index) { 79 | switch (tag) { 80 | case Tag.LibraryFieldReference: 81 | case Tag.Field: 82 | return _extendList( 83 | library, library.fields, index, _buildFieldReference); 84 | case Tag.LibraryProcedureReference: 85 | case Tag.Procedure: 86 | return _extendList( 87 | library, library.procedures, index, _buildProcedureReference); 88 | default: 89 | throw 'Invalid library member reference tag: $tag'; 90 | } 91 | } 92 | 93 | Member getClassMemberReference(Class classNode, int tag, int index) { 94 | switch (tag) { 95 | case Tag.ClassFieldReference: 96 | case Tag.Field: 97 | return _extendList( 98 | classNode, classNode.fields, index, _buildFieldReference); 99 | case Tag.ClassConstructorReference: 100 | case Tag.Constructor: 101 | return _extendList(classNode, classNode.constructors, index, 102 | _buildConstructorReference); 103 | case Tag.ClassProcedureReference: 104 | case Tag.Procedure: 105 | return _extendList( 106 | classNode, classNode.procedures, index, _buildProcedureReference); 107 | default: 108 | throw 'Invalid library member reference tag: $tag'; 109 | } 110 | } 111 | 112 | Program loadProgram(String filename) { 113 | var bytes = new File(filename).readAsBytesSync(); 114 | return new BinaryBuilder(this, bytes, filename).readProgramFile(); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /test/treeshaker_stacktracer.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.treeshaker.stacktracer; 5 | 6 | import 'package:kernel/kernel.dart'; 7 | import 'package:kernel/transformations/treeshaker.dart'; 8 | import 'dart:io'; 9 | import 'package:ansicolor/ansicolor.dart'; 10 | 11 | String usage = ''' 12 | USAGE: treeshaker_stacktracer FILE.dill STACKTRACE.txt 13 | 14 | Given a program and a stack trace from it, highlight the stack trace entries 15 | that the tree shaker marked as unreachable. These are indicative of bugs 16 | in the tree shaker since their presence in the stack trace proves them reachable. 17 | 18 | Example usage: 19 | ${comment("# Not shown: insert a 'throw' in testcase.dart")} 20 | dart testcase.dart > error.txt ${comment("# Get the stack trace")} 21 | dartk testcase.dart -l -otestcase.dill ${comment("# Compile binary")} 22 | dart test/treeshaker_stacktracer.dart testcase.dill error.txt ${comment("# Analyze")} 23 | '''; 24 | 25 | String legend = ''' 26 | Legend: 27 | ${reachable('reachable member')} or ${reachable('instantiated class')} 28 | ${unreachable('unreachable member')} or ${unreachable('uninstantiated class')} 29 | ${unknown('name unrecognized')} 30 | '''; 31 | 32 | // TODO: Also support the stack trace format from stack_trace. 33 | RegExp stackTraceEntry = new RegExp(r'(#[0-9]+\s+)([a-zA-Z0-9_$.&<> ]+) \((.*)\)'); 34 | 35 | AnsiPen reachable = new AnsiPen()..green(); 36 | AnsiPen unreachable = new AnsiPen()..red(); 37 | AnsiPen unknown = new AnsiPen()..gray(level: 0.5); 38 | AnsiPen filecolor = new AnsiPen()..gray(level: 0.5); 39 | AnsiPen comment = new AnsiPen()..gray(level: 0.5); 40 | 41 | String stackTraceName(Member member) { 42 | String name = member.name?.name; 43 | String className = member.enclosingClass?.name; 44 | if (member is Constructor && name != null) { 45 | return '$className.$className'; 46 | } else if (className != null) { 47 | return '$className.$name'; 48 | } else { 49 | return name; 50 | } 51 | } 52 | 53 | int findReachablePrefix(String name, Set strings) { 54 | for (int index = name.length; 55 | index > 0; 56 | index = name.lastIndexOf('.', index - 1)) { 57 | if (strings.contains(name.substring(0, index))) { 58 | return index; 59 | } 60 | } 61 | return 0; 62 | } 63 | 64 | String shortenFilename(String filename) { 65 | if (filename.startsWith('file:')) { 66 | int libIndex = filename.lastIndexOf('lib/'); 67 | if (libIndex != -1) { 68 | return filename.substring(libIndex + 'lib/'.length); 69 | } 70 | } 71 | return filename; 72 | } 73 | 74 | main(List args) { 75 | if (args.length != 2) { 76 | print(usage); 77 | exit(1); 78 | } 79 | List stackTrace = new File(args[1]).readAsLinesSync(); 80 | Program program = loadProgramFromBinary(args[0]); 81 | TreeShaker shaker = new TreeShaker(program); 82 | Set reachablePatterns = new Set(); 83 | Set allMembers = new Set(); 84 | Set instantiatedClasses = new Set(); 85 | void visitMember(Member member) { 86 | allMembers.add(stackTraceName(member)); 87 | if (shaker.isMemberUsed(member)) { 88 | reachablePatterns.add(stackTraceName(member)); 89 | } 90 | } 91 | for (var library in program.libraries) { 92 | for (var classNode in library.classes) { 93 | if (shaker.isInstantiated(classNode)) { 94 | instantiatedClasses.add(classNode.name); 95 | } 96 | classNode.members.forEach(visitMember); 97 | } 98 | library.members.forEach(visitMember); 99 | } 100 | for (String line in stackTrace) { 101 | var match = stackTraceEntry.matchAsPrefix(line); 102 | if (match == null) continue; 103 | String entry = match.group(2); 104 | int reachableIndex = findReachablePrefix(entry, reachablePatterns); 105 | int knownIndex = findReachablePrefix(entry, allMembers); 106 | int classIndex = findReachablePrefix(entry, instantiatedClasses); 107 | if (reachableIndex == 0) { 108 | reachableIndex = classIndex; 109 | if (reachableIndex > knownIndex) { 110 | knownIndex = reachableIndex; 111 | } 112 | } 113 | String numberPart = match.group(1); 114 | String reachablePart = reachable(entry.substring(0, reachableIndex)); 115 | String knownPart = unreachable(entry.substring(reachableIndex, knownIndex)); 116 | String unknownPart = unknown(entry.substring(knownIndex)); 117 | String filePart = filecolor(shortenFilename(match.group(3))); 118 | String string = '$numberPart$reachablePart$knownPart$unknownPart'; 119 | print(string.padRight(110) + filePart); 120 | } 121 | print(legend); 122 | } 123 | -------------------------------------------------------------------------------- /lib/transformations/erasure.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.transformations.erasure; 5 | 6 | import '../ast.dart'; 7 | import '../type_algebra.dart'; 8 | 9 | /// This pass is a temporary measure to run strong mode code in the VM, which 10 | /// does not yet have the necessary runtime support. 11 | /// 12 | /// Function type parameter lists are cleared and all uses of a function type 13 | /// parameter are replaced by its upper bound. 14 | /// 15 | /// All uses of type parameters in constants are replaced by 'dynamic'. 16 | /// 17 | /// This does not preserve dynamic type safety. 18 | class Erasure extends Transformer { 19 | final Map substitution = {}; 20 | final Map constantSubstitution = 21 | {}; 22 | 23 | int constantContexts = 0; 24 | 25 | void transform(Program program) { 26 | program.accept(this); 27 | } 28 | 29 | void pushConstantContext() { 30 | ++constantContexts; 31 | } 32 | 33 | void popConstantContext() { 34 | --constantContexts; 35 | } 36 | 37 | bool get isInConstantContext => constantContexts > 0; 38 | 39 | @override 40 | visitDartType(DartType type) { 41 | type = substitute(type, substitution); 42 | if (isInConstantContext) { 43 | type = substitute(type, constantSubstitution); 44 | } 45 | return type; 46 | } 47 | 48 | @override 49 | visitClass(Class node) { 50 | for (var parameter in node.typeParameters) { 51 | constantSubstitution[parameter] = const DynamicType(); 52 | } 53 | node.transformChildren(this); 54 | constantSubstitution.clear(); 55 | return node; 56 | } 57 | 58 | @override 59 | visitProcedure(Procedure node) { 60 | if (node.kind == ProcedureKind.Factory) { 61 | assert(node.enclosingClass != null); 62 | assert(node.enclosingClass.typeParameters.length == 63 | node.function.typeParameters.length); 64 | // Factories can have function type parameters as long as they correspond 65 | // exactly to those on the enclosing class. However, these type parameters 66 | // may still not be in a constant. 67 | for (var parameter in node.function.typeParameters) { 68 | constantSubstitution[parameter] = const DynamicType(); 69 | } 70 | // Skip the visitFunctionNode but traverse body. 71 | node.function.transformChildren(this); 72 | node.function.typeParameters.forEach(constantSubstitution.remove); 73 | } else { 74 | node.transformChildren(this); 75 | } 76 | return node; 77 | } 78 | 79 | bool isObject(DartType type) { 80 | return type is InterfaceType && type.classNode.supertype == null; 81 | } 82 | 83 | @override 84 | visitFunctionNode(FunctionNode node) { 85 | for (var parameter in node.typeParameters) { 86 | substitution[parameter] = const DynamicType(); 87 | } 88 | for (var parameter in node.typeParameters) { 89 | if (!isObject(parameter.bound)) { 90 | substitution[parameter] = substitute(parameter.bound, substitution); 91 | } 92 | } 93 | node.transformChildren(this); 94 | node.typeParameters.forEach(substitution.remove); 95 | node.typeParameters.clear(); 96 | return node; 97 | } 98 | 99 | @override 100 | visitStaticInvocation(StaticInvocation node) { 101 | if (node.target.kind != ProcedureKind.Factory) { 102 | node.arguments.types.clear(); 103 | } 104 | if (node.isConst) pushConstantContext(); 105 | node.transformChildren(this); 106 | if (node.isConst) popConstantContext(); 107 | return node; 108 | } 109 | 110 | @override 111 | visitMethodInvocation(MethodInvocation node) { 112 | node.arguments.types.clear(); 113 | node.transformChildren(this); 114 | return node; 115 | } 116 | 117 | @override 118 | visitDirectMethodInvocation(DirectMethodInvocation node) { 119 | node.arguments.types.clear(); 120 | node.transformChildren(this); 121 | return node; 122 | } 123 | 124 | @override 125 | visitConstructorInvocation(ConstructorInvocation node) { 126 | if (node.isConst) pushConstantContext(); 127 | node.transformChildren(this); 128 | if (node.isConst) popConstantContext(); 129 | return node; 130 | } 131 | 132 | @override 133 | visitListLiteral(ListLiteral node) { 134 | if (node.isConst) pushConstantContext(); 135 | node.transformChildren(this); 136 | if (node.isConst) popConstantContext(); 137 | return node; 138 | } 139 | 140 | @override 141 | visitMapLiteral(MapLiteral node) { 142 | if (node.isConst) pushConstantContext(); 143 | node.transformChildren(this); 144 | if (node.isConst) popConstantContext(); 145 | return node; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /lib/binary/tag.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.binary.tag; 5 | 6 | class Tag { 7 | static const int Nothing = 0; 8 | static const int Something = 1; 9 | 10 | static const int NormalClass = 2; 11 | static const int MixinClass = 3; 12 | 13 | static const int Field = 4; 14 | static const int Constructor = 5; 15 | static const int Procedure = 6; 16 | 17 | static const int InvalidInitializer = 7; 18 | static const int FieldInitializer = 8; 19 | static const int SuperInitializer = 9; 20 | static const int RedirectingInitializer = 10; 21 | static const int LocalInitializer = 11; 22 | 23 | static const int DirectPropertyGet = 15; 24 | static const int DirectPropertySet = 16; 25 | static const int DirectMethodInvocation = 17; 26 | static const int ConstStaticInvocation = 18; 27 | static const int InvalidExpression = 19; 28 | static const int VariableGet = 20; 29 | static const int VariableSet = 21; 30 | static const int PropertyGet = 22; 31 | static const int PropertySet = 23; 32 | static const int SuperPropertyGet = 24; 33 | static const int SuperPropertySet = 25; 34 | static const int StaticGet = 26; 35 | static const int StaticSet = 27; 36 | static const int MethodInvocation = 28; 37 | static const int SuperMethodInvocation = 29; 38 | static const int StaticInvocation = 30; 39 | static const int ConstructorInvocation = 31; 40 | static const int ConstConstructorInvocation = 32; 41 | static const int Not = 33; 42 | static const int LogicalExpression = 34; 43 | static const int ConditionalExpression = 35; 44 | static const int StringConcatenation = 36; 45 | static const int IsExpression = 37; 46 | static const int AsExpression = 38; 47 | static const int StringLiteral = 39; 48 | static const int DoubleLiteral = 40; 49 | static const int TrueLiteral = 41; 50 | static const int FalseLiteral = 42; 51 | static const int NullLiteral = 43; 52 | static const int SymbolLiteral = 44; 53 | static const int TypeLiteral = 45; 54 | static const int ThisExpression = 46; 55 | static const int Rethrow = 47; 56 | static const int Throw = 48; 57 | static const int ListLiteral = 49; 58 | static const int MapLiteral = 50; 59 | static const int AwaitExpression = 51; 60 | static const int FunctionExpression = 52; 61 | static const int Let = 53; 62 | static const int PositiveIntLiteral = 55; 63 | static const int NegativeIntLiteral = 56; 64 | static const int BigIntLiteral = 57; 65 | static const int ConstListLiteral = 58; 66 | static const int ConstMapLiteral = 59; 67 | 68 | static const int InvalidStatement = 60; 69 | static const int ExpressionStatement = 61; 70 | static const int Block = 62; 71 | static const int EmptyStatement = 63; 72 | static const int AssertStatement = 64; 73 | static const int LabeledStatement = 65; 74 | static const int BreakStatement = 66; 75 | static const int WhileStatement = 67; 76 | static const int DoStatement = 68; 77 | static const int ForStatement = 69; 78 | static const int ForInStatement = 70; 79 | static const int SwitchStatement = 71; 80 | static const int ContinueSwitchStatement = 72; 81 | static const int IfStatement = 73; 82 | static const int ReturnStatement = 74; 83 | static const int TryCatch = 75; 84 | static const int TryFinally = 76; 85 | static const int YieldStatement = 77; 86 | static const int VariableDeclaration = 78; 87 | static const int FunctionDeclaration = 79; 88 | static const int AsyncForInStatement = 80; 89 | 90 | static const int BottomType = 89; 91 | static const int InvalidType = 90; 92 | static const int DynamicType = 91; 93 | static const int VoidType = 92; 94 | static const int InterfaceType = 93; 95 | static const int FunctionType = 94; 96 | static const int TypeParameterType = 95; 97 | static const int SimpleInterfaceType = 96; 98 | static const int SimpleFunctionType = 97; 99 | 100 | static const int NullReference = 99; 101 | static const int NormalClassReference = 100; 102 | static const int MixinClassReference = 101; 103 | 104 | static const int LibraryFieldReference = 102; 105 | static const int ClassFieldReference = 103; 106 | static const int ClassConstructorReference = 104; 107 | static const int LibraryProcedureReference = 105; 108 | static const int ClassProcedureReference = 106; 109 | 110 | static const int SpecializedTagHighBit = 0x80; // 10000000 111 | static const int SpecializedTagMask = 0xF8; // 11111000 112 | static const int SpecializedPayloadMask = 0x7; // 00000111 113 | 114 | static const int SpecializedVariableGet = 128; 115 | static const int SpecializedVariableSet = 136; 116 | static const int SpecializedIntLiteral = 144; 117 | 118 | static const int SpecializedIntLiteralBias = 3; 119 | 120 | static const int ProgramFile = 0x90ABCDEF; 121 | } 122 | -------------------------------------------------------------------------------- /lib/checks.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.checks; 5 | 6 | import 'ast.dart'; 7 | 8 | void runSanityChecks(Program program) { 9 | CheckParentPointers.check(program); 10 | CheckReferences.check(program); 11 | } 12 | 13 | class CheckParentPointers extends Visitor { 14 | static void check(TreeNode node) { 15 | node.accept(new CheckParentPointers(node.parent)); 16 | } 17 | 18 | TreeNode parent; 19 | 20 | CheckParentPointers([this.parent]); 21 | 22 | defaultTreeNode(TreeNode node) { 23 | if (node.parent != parent) { 24 | throw 'Parent pointer on ${node.runtimeType} ' 25 | 'is ${node.parent.runtimeType} ' 26 | 'but should be ${parent.runtimeType}'; 27 | } 28 | var oldParent = parent; 29 | parent = node; 30 | node.visitChildren(this); 31 | parent = oldParent; 32 | } 33 | } 34 | 35 | /// Checks that references refer to something in scope. 36 | /// 37 | /// Currently only checks member, class, and type parameter references. 38 | class CheckReferences extends RecursiveVisitor { 39 | final Set members = new Set(); 40 | final Set classes = new Set(); 41 | final Set typeParameters = new Set(); 42 | 43 | Member currentMember; 44 | Class currentClass; 45 | 46 | TreeNode get context => currentMember ?? currentClass; 47 | 48 | static void check(Program program) { 49 | program.accept(new CheckReferences()); 50 | } 51 | 52 | visitProgram(Program program) { 53 | for (var library in program.libraries) { 54 | classes.addAll(library.classes); 55 | members.addAll(library.members); 56 | for (var class_ in library.classes) { 57 | members.addAll(class_.members); 58 | } 59 | } 60 | program.visitChildren(this); 61 | } 62 | 63 | defaultMember(Member node) { 64 | currentMember = node; 65 | node.visitChildren(this); 66 | currentMember = null; 67 | } 68 | 69 | visitClass(Class node) { 70 | currentClass = node; 71 | typeParameters.addAll(node.typeParameters); 72 | node.visitChildren(this); 73 | typeParameters.removeAll(node.typeParameters); 74 | currentClass = null; 75 | } 76 | 77 | visitFunctionNode(FunctionNode node) { 78 | for (int i = 1; i < node.namedParameters.length; ++i) { 79 | if (node.namedParameters[i - 1].compareTo(node.namedParameters[i]) >= 0) { 80 | throw 'Named parameters are not sorted on function found in $context'; 81 | } 82 | } 83 | typeParameters.addAll(node.typeParameters); 84 | node.visitChildren(this); 85 | typeParameters.removeAll(node.typeParameters); 86 | } 87 | 88 | visitFunctionType(FunctionType node) { 89 | for (int i = 1; i < node.namedParameters.length; ++i) { 90 | if (node.namedParameters[i - 1].compareTo(node.namedParameters[i]) >= 0) { 91 | throw 'Named parameters are not sorted on function type found in ' 92 | '$context'; 93 | } 94 | } 95 | node.visitChildren(this); 96 | } 97 | 98 | @override 99 | defaultMemberReference(Member node) { 100 | if (!members.contains(node)) { 101 | throw 'Dangling reference to $node found in $context.\n' 102 | 'Parent pointer is set to ${node.parent}'; 103 | } 104 | } 105 | 106 | @override 107 | visitClassReference(Class node) { 108 | if (!classes.contains(node)) { 109 | throw 'Dangling reference to $node found in $context.\n' 110 | 'Parent pointer is set to ${node.parent}'; 111 | } 112 | } 113 | 114 | @override 115 | visitTypeParameterType(TypeParameterType node) { 116 | if (!typeParameters.contains(node.parameter)) { 117 | throw 'Type parameter ${node.parameter} referenced out of scope ' 118 | 'in $context.\n' 119 | 'Parent pointer is set to ${node.parameter.parent}'; 120 | } 121 | } 122 | 123 | @override 124 | visitInterfaceType(InterfaceType node) { 125 | node.visitChildren(this); 126 | if (node.typeArguments.length != node.classNode.typeParameters.length) { 127 | throw 'Type $node provides ${node.typeArguments.length} type arguments ' 128 | 'but the class declares ${node.classNode.typeParameters.length} ' 129 | 'parameters. Found in $context.'; 130 | } 131 | } 132 | } 133 | 134 | class SizeCounter extends RecursiveVisitor { 135 | int size = 0; 136 | int emptyArguments = 0; 137 | 138 | void visit(TreeNode node) => node.accept(this); 139 | 140 | visitArguments(Arguments node) { 141 | super.visitArguments(node); 142 | if (node.positional.isEmpty && 143 | node.positional.isEmpty && 144 | node.types.isEmpty) { 145 | ++emptyArguments; 146 | } 147 | } 148 | 149 | defaultNode(Node node) { 150 | ++size; 151 | node.visitChildren(this); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /test/treeshaker_dump.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library kernel.treeshaker_dump; 5 | 6 | import 'dart:io'; 7 | import 'package:kernel/kernel.dart'; 8 | import 'package:kernel/transformations/treeshaker.dart'; 9 | import 'package:args/args.dart'; 10 | import 'package:path/path.dart' as pathlib; 11 | import 'package:kernel/text/ast_to_text.dart'; 12 | 13 | ArgParser parser = new ArgParser(allowTrailingOptions: true) 14 | ..addFlag('used', help: 'Print used members', negatable: false) 15 | ..addFlag('unused', help: 'Print unused members', negatable: false) 16 | ..addFlag('instantiated', 17 | help: 'Print instantiated classes', negatable: false) 18 | ..addFlag('types', help: 'Print classes used as a type', negatable: false) 19 | ..addFlag('summary', 20 | help: 'Print short summary of tree shaking results', defaultsTo: true) 21 | ..addFlag('diff', 22 | help: 'Print textual output before and after tree shaking.\n' 23 | 'Files are written to FILE.before.txt and FILE.after.txt', 24 | negatable: false) 25 | ..addOption('output', 26 | help: 'The --diff files are written to the given directory instead of ' 27 | 'the working directory'); 28 | 29 | String usage = ''' 30 | Usage: treeshaker_dump [options] FILE.dill 31 | 32 | Runs tree shaking on the given program and prints information about the results. 33 | 34 | Example: 35 | treeshaker_dump --instantiated foo.dill 36 | 37 | Example: 38 | treeshaker_dump --diff foo.dill 39 | diff -cd foo.{before,after}.txt > diff.txt 40 | # open diff.txt in an editor 41 | 42 | Options: 43 | ${parser.usage} 44 | '''; 45 | 46 | main(List args) { 47 | if (args.isEmpty) { 48 | print(usage); 49 | exit(1); 50 | } 51 | ArgResults options = parser.parse(args); 52 | if (options.rest.length != 1) { 53 | print('Exactly one file should be given.'); 54 | exit(1); 55 | } 56 | String filename = options.rest.single; 57 | 58 | if (options['output'] != null && !options['diff']) { 59 | print('--output must be used with --diff'); 60 | exit(1); 61 | } 62 | 63 | Program program = loadProgramFromBinary(filename); 64 | TreeShaker shaker = new TreeShaker(program); 65 | int totalClasses = 0; 66 | int totalInstantiationCandidates = 0; 67 | int totalMembers = 0; 68 | int usedClasses = 0; 69 | int instantiatedClasses = 0; 70 | int usedMembers = 0; 71 | 72 | void visitMember(Member member) { 73 | if (member.isAbstract) return; // Abstract members are not relevant. 74 | ++totalMembers; 75 | bool isUsed = shaker.isMemberUsed(member); 76 | if (isUsed) { 77 | ++usedMembers; 78 | } 79 | if (isUsed && options['used'] || !isUsed && options['unused']) { 80 | String prefix = (options['used'] && options['unused']) 81 | ? (isUsed ? 'USED ' : 'UNUSED ') 82 | : ''; 83 | print('$prefix$member'); 84 | } 85 | } 86 | 87 | for (var library in program.libraries) { 88 | library.members.forEach(visitMember); 89 | for (Class classNode in library.classes) { 90 | ++totalClasses; 91 | if (shaker.isInstantiated(classNode)) { 92 | ++instantiatedClasses; 93 | ++totalInstantiationCandidates; 94 | } else if (!classNode.isAbstract && 95 | classNode.members.any((m) => m.isInstanceMember)) { 96 | ++totalInstantiationCandidates; 97 | } 98 | if (shaker.isHierarchyUsed(classNode)) { 99 | ++usedClasses; 100 | } 101 | classNode.members.forEach(visitMember); 102 | if (options['instantiated'] && shaker.isInstantiated(classNode)) { 103 | print(classNode); 104 | } 105 | if (options['types'] && shaker.isHierarchyUsed(classNode)) { 106 | print(classNode); 107 | } 108 | } 109 | } 110 | 111 | if (options['summary']) { 112 | print('Classes used: ${ratio(usedClasses, totalClasses)}'); 113 | print('Classes instantiated: ' 114 | '${ratio(instantiatedClasses, totalInstantiationCandidates)}'); 115 | print('Members used: ${ratio(usedMembers, totalMembers)}'); 116 | } 117 | 118 | if (options['diff']) { 119 | String name = pathlib.basenameWithoutExtension(filename); 120 | String outputDir = options['output'] ?? ''; 121 | String beforeFile = pathlib.join(outputDir, '$name.before.txt'); 122 | String afterFile = pathlib.join(outputDir, '$name.after.txt'); 123 | NameSystem names = new NameSystem(); 124 | StringBuffer before = new StringBuffer(); 125 | new Printer(before, syntheticNames: names).writeProgramFile(program); 126 | new File(beforeFile).writeAsStringSync('$before'); 127 | new TreeShaker(program).transform(program); 128 | StringBuffer after = new StringBuffer(); 129 | new Printer(after, syntheticNames: names).writeProgramFile(program); 130 | new File(afterFile).writeAsStringSync('$after'); 131 | print('Text written to $beforeFile and $afterFile'); 132 | } 133 | } 134 | 135 | String ratio(num x, num total) { 136 | return '$x / $total (${percent(x, total)})'; 137 | } 138 | 139 | String percent(num x, num total) { 140 | return total == 0 ? '0%' : ((100 * x / total).toStringAsFixed(0) + '%'); 141 | } 142 | --------------------------------------------------------------------------------