Index: tests/compiler/dart2js/interop_anonymous_unreachable_test.dart |
diff --git a/tests/compiler/dart2js/interop_anonymous_unreachable_test.dart b/tests/compiler/dart2js/interop_anonymous_unreachable_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3f382059772247abb9abeab45eef227cbe4ece3d |
--- /dev/null |
+++ b/tests/compiler/dart2js/interop_anonymous_unreachable_test.dart |
@@ -0,0 +1,177 @@ |
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+library tests.dart2js.interop_anonymous_unreachable_test; |
+ |
+import 'dart:async'; |
+ |
+import 'package:test/test.dart'; |
+import 'compiler_helper.dart'; |
+ |
+ |
+main() { |
+ test("unreachable code doesn't crash the compiler", () async { |
+ // This test is a regression for Issue #24974 |
+ String generated = await compile(""" |
+ import 'package:js/js.dart'; |
+ |
+ @JS() @anonymous |
+ class UniqueLongNameForTesting_A { |
+ external factory UniqueLongNameForTesting_A(); |
+ } |
+ main() {} |
+ """, returnAll: true); |
+ |
+ // the code should not be included in the output either. |
+ expect(generated, isNot(contains("UniqueLongNameForTesting_A"))); |
+ }); |
+ |
+ group('tree-shaking interop types', () { |
+ String program = """ |
+ import 'package:js/js.dart'; |
+ |
+ // reachable and allocated |
+ @JS() @anonymous |
+ class UniqueLongNameForTesting_A { |
+ external bool get x; |
+ external UniqueLongNameForTesting_D get d; |
+ external UniqueLongNameForTesting_E get e; |
+ external factory UniqueLongNameForTesting_A( |
+ {UniqueLongNameForTesting_B arg0}); |
+ } |
+ |
+ // visible through the parameter above, but not used. |
+ @JS() @anonymous |
+ class UniqueLongNameForTesting_B { |
+ external factory UniqueLongNameForTesting_B(); |
+ } |
+ |
+ // unreachable |
+ @JS() @anonymous |
+ class UniqueLongNameForTesting_C { |
+ external factory UniqueLongNameForTesting_C(); |
+ } |
+ |
+ // visible and reached through `d`. |
+ @JS() @anonymous |
+ class UniqueLongNameForTesting_D { |
+ external factory UniqueLongNameForTesting_D(); |
+ } |
+ |
+ // visible through `e`, but not reached. |
+ @JS() @anonymous |
+ class UniqueLongNameForTesting_E { |
+ external factory UniqueLongNameForTesting_E(); |
+ } |
+ |
+ main() { |
+ print(new UniqueLongNameForTesting_A().x); |
+ print(new UniqueLongNameForTesting_A().d); |
+ } |
+ """; |
+ |
+ test('no tree-shaking by default', () async { |
+ String generated = await compile(program, returnAll: true); |
+ expect(generated.contains("UniqueLongNameForTesting_A"), isTrue); |
+ expect(generated.contains("UniqueLongNameForTesting_D"), isTrue); |
+ |
+ expect(generated.contains("UniqueLongNameForTesting_B"), isTrue); |
+ expect(generated.contains("UniqueLongNameForTesting_C"), isTrue); |
+ expect(generated.contains("UniqueLongNameForTesting_E"), isTrue); |
+ }); |
+ |
+ test('tree-shake when using flag', () async { |
+ String generated = await compile(program, |
+ trustJSInteropTypeAnnotations: true, |
+ returnAll: true); |
+ expect(generated.contains("UniqueLongNameForTesting_A"), isTrue); |
+ expect(generated.contains("UniqueLongNameForTesting_D"), isTrue); |
+ |
+ expect(generated.contains("UniqueLongNameForTesting_B"), isFalse); |
+ expect(generated.contains("UniqueLongNameForTesting_C"), isFalse); |
+ expect(generated.contains("UniqueLongNameForTesting_E"), isFalse); |
+ }); |
+ }); |
+ |
+ group('tree-shaking other native types', () { |
+ String program = """ |
+ import 'dart:html'; |
+ import 'package:js/js.dart'; |
+ |
+ @JS() @anonymous |
+ class UniqueLongNameForTesting_A { |
+ external dynamic get x; |
+ } |
+ |
+ @JS() @anonymous |
+ class UniqueLongNameForTesting_B { |
+ external dynamic get y; |
+ } |
+ |
+ main() { |
+ print(new UniqueLongNameForTesting_A().x); |
+ } |
+ """; |
+ |
+ test('allocation effect of dynamic excludes native types', () async { |
+ String generated = await compile(program, returnAll: true); |
+ expect(generated.contains("UniqueLongNameForTesting_A"), isTrue); |
+ // any js-interop type could be allocated by `get x` |
+ expect(generated.contains("UniqueLongNameForTesting_B"), isTrue); |
+ // but we exclude other native types like HTMLAudioElement |
+ expect(generated.contains("HTMLAudioElement"), isFalse); |
+ }); |
+ |
+ test('allocation effect of dynamic excludes native types [flag]', () async { |
+ // Trusting types doesn't make a difference. |
+ String generated = await compile(program, |
+ trustJSInteropTypeAnnotations: true, |
+ returnAll: true); |
+ expect(generated.contains("UniqueLongNameForTesting_A"), isTrue); |
+ expect(generated.contains("UniqueLongNameForTesting_B"), isTrue); |
+ expect(generated.contains("HTMLAudioElement"), isFalse); |
+ }); |
+ |
+ test('declared native types are included in allocation effect', () async { |
+ String program2 = """ |
+ import 'dart:html'; |
+ import 'package:js/js.dart'; |
+ |
+ @JS() @anonymous |
+ class UniqueLongNameForTesting_A { |
+ external AudioElement get x; |
+ } |
+ |
+ main() { |
+ print(new UniqueLongNameForTesting_A().x is AudioElement); |
+ } |
+ """; |
+ |
+ String generated = await compile(program2, returnAll: true); |
+ expect(generated.contains("UniqueLongNameForTesting_A"), isTrue); |
+ expect(generated.contains("HTMLAudioElement"), isTrue); |
+ |
+ program2 = """ |
+ import 'dart:html'; |
+ import 'package:js/js.dart'; |
+ |
+ @JS() @anonymous |
+ class UniqueLongNameForTesting_A { |
+ external dynamic get x; |
+ } |
+ |
+ main() { |
+ print(new UniqueLongNameForTesting_A().x is AudioElement); |
+ } |
+ """; |
+ |
+ generated = await compile(program2, returnAll: true); |
+ expect(generated.contains("UniqueLongNameForTesting_A"), isTrue); |
+ // This extra check is to make sure that we don't include HTMLAudioElement |
+ // just because of the is-check. It is optimized away in this case because |
+ // we believe it was never instantiated. |
+ expect(generated.contains("HTMLAudioElement"), isFalse); |
+ }); |
+ }); |
+} |