From 78fca5b2fa043f906a74ed4d550fa307cd178bcc Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Wed, 3 Apr 2019 10:23:53 +0000 Subject: [PATCH] Include liveness of type argument in supertypes in RTI needed checks computation Change-Id: Ifdde3e8694f8d39ccf10cac0d5dc2cb3cb9225bd Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/98560 Reviewed-by: Johnni Winther Commit-Queue: Johnni Winther --- .../lib/src/js_backend/runtime_types.dart | 26 +++++++++++++++++ .../rti/emission/fixed_type_argument.dart | 29 +++++++++++++++++++ .../fixed_type_argument_test.dart | 22 ++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 tests/compiler/dart2js/rti/emission/fixed_type_argument.dart create mode 100644 tests/compiler/dart2js_extra/fixed_type_argument_test.dart diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart index e5132c64898..ba4143ad2f4 100644 --- a/pkg/compiler/lib/src/js_backend/runtime_types.dart +++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart @@ -2073,6 +2073,7 @@ class RuntimeTypesImpl extends _RuntimeTypesBase classUse.instance = true; }); + Set visitedSuperClasses = {}; codegenWorldBuilder.instantiatedTypes.forEach((InterfaceType type) { liveTypeVisitor.visitType(type, TypeVisitorState.direct); ClassUse classUse = @@ -2082,6 +2083,31 @@ class RuntimeTypesImpl extends _RuntimeTypesBase if (callType != null) { liveTypeVisitor.visitType(callType, TypeVisitorState.direct); } + + // Superclass might make classes live as type arguments. For instance + // + // class A {} + // class B {} + // class C extends B {} + // main() => new C(); + // + // Here `A` is live as a type argument through the liveness of `C`. + ClassEntity superclass = _elementEnvironment.getSuperClass(type.element); + while (superclass != null) { + if (!_elementEnvironment.isGenericClass(superclass) && + visitedSuperClasses.contains(superclass)) { + // If [superclass] is not generic then a second visit cannot add more + // information that the first. In the example above, visiting `C` + // twice can only result in a second registration of `A` as live + // type argument. + break; + } + visitedSuperClasses.add(superclass); + InterfaceType supertype = + _closedWorld.dartTypes.asInstanceOf(type, superclass); + liveTypeVisitor.visitType(supertype, TypeVisitorState.direct); + superclass = _elementEnvironment.getSuperClass(superclass); + } }); for (FunctionEntity element diff --git a/tests/compiler/dart2js/rti/emission/fixed_type_argument.dart b/tests/compiler/dart2js/rti/emission/fixed_type_argument.dart new file mode 100644 index 00000000000..3db4d67aef4 --- /dev/null +++ b/tests/compiler/dart2js/rti/emission/fixed_type_argument.dart @@ -0,0 +1,29 @@ +// Copyright (c) 2019, 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. + +/*strong.class: A:checkedInstance,checkedTypeArgument,checks=[],typeArgument*/ +/*omit.class: A:checkedTypeArgument,checks=[],typeArgument*/ +class A {} + +/*strong.class: B:checkedInstance,checks=[$isA],typeArgument*/ +/*omit.class: B:checks=[$isA],typeArgument*/ +class B implements A {} + +/*class: C:checks=[],indirectInstance*/ +class C { + @pragma('dart2js:noInline') + method(void Function(T) f) {} +} + +/*strong.class: D:checks=[$asC],instance*/ +/*omit.class: D:checks=[],instance*/ +class D extends C {} + +main() { + C c = new D(); + c.method( + /*strong.checks=[$signature],instance*/ + /*omit.checks=[],instance*/ + (A a) {}); +} diff --git a/tests/compiler/dart2js_extra/fixed_type_argument_test.dart b/tests/compiler/dart2js_extra/fixed_type_argument_test.dart new file mode 100644 index 00000000000..74ac892a242 --- /dev/null +++ b/tests/compiler/dart2js_extra/fixed_type_argument_test.dart @@ -0,0 +1,22 @@ +// Copyright (c) 2019, 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. + +// Test that we emit the relation between B and A even when B is only live +// as a type argument through the superclass of D. + +class A {} + +class B implements A {} + +class C { + @pragma('dart2js:noInline') + method(void Function(T) f) {} +} + +class D extends C {} + +main() { + C c = new D(); + c.method((A a) {}); +}