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 <johnniwinther@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Johnni Winther 2019-04-03 10:23:53 +00:00 committed by commit-bot@chromium.org
parent 9a2b222cba
commit 78fca5b2fa
3 changed files with 77 additions and 0 deletions

View file

@ -2073,6 +2073,7 @@ class RuntimeTypesImpl extends _RuntimeTypesBase
classUse.instance = true;
});
Set<ClassEntity> 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<T> {}
// class C extends B<A> {}
// 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

View file

@ -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<T> {
@pragma('dart2js:noInline')
method(void Function(T) f) {}
}
/*strong.class: D:checks=[$asC],instance*/
/*omit.class: D:checks=[],instance*/
class D extends C<B> {}
main() {
C<A> c = new D();
c.method(
/*strong.checks=[$signature],instance*/
/*omit.checks=[],instance*/
(A a) {});
}

View file

@ -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<T> {
@pragma('dart2js:noInline')
method(void Function(T) f) {}
}
class D extends C<B> {}
main() {
C<A> c = new D();
c.method((A a) {});
}