Fix bug in RTI optimization
Change-Id: Iec3026f0a79ac54dd125e15f00e4beb21e9a371c
Reviewed-on: https://dart-review.googlesource.com/58020
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 743ef5c..c94a5f2 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -789,7 +789,7 @@
/// }
/// main() => new B<int>().m(0);
///
- Iterable<ClassEntity> get classTests =>
+ Iterable<ClassEntity> get classTestsForTesting =>
_classes.values.where((n) => n.hasTest).map((n) => n.cls).toSet();
/// Classes that explicitly use their type variables in is-tests.
@@ -801,7 +801,7 @@
/// }
/// main() => new A<int>().m(0);
///
- Iterable<ClassEntity> get directClassTests =>
+ Iterable<ClassEntity> get directClassTestsForTesting =>
_classes.values.where((n) => n.hasDirectTest).map((n) => n.cls).toSet();
/// Methods that explicitly or implicitly use their type variables in
@@ -813,7 +813,7 @@
/// m2<S>(o) => m1<S>(o);
/// main() => m2<int>(0);
///
- Iterable<Entity> get methodTests =>
+ Iterable<Entity> get methodTestsForTesting =>
_methods.values.where((n) => n.hasTest).map((n) => n.function).toSet();
/// Methods that explicitly use their type variables in is-tests.
@@ -823,7 +823,7 @@
/// m<T>(o) => o is T;
/// main() => m<int>(0);
///
- Iterable<Entity> get directMethodTests => _methods.values
+ Iterable<Entity> get directMethodTestsForTesting => _methods.values
.where((n) => n.hasDirectTest)
.map((n) => n.function)
.toSet();
@@ -1022,20 +1022,25 @@
void _propagateTests(CommonElements commonElements,
ElementEnvironment elementEnvironment, WorldBuilder worldBuilder) {
+ void processTypeVariableType(TypeVariableType type, {bool direct: true}) {
+ TypeVariableEntity variable = type.element;
+ if (variable.typeDeclaration is ClassEntity) {
+ _getClassNode(variable.typeDeclaration).markTest(direct: direct);
+ } else {
+ _getMethodNode(
+ elementEnvironment, worldBuilder, variable.typeDeclaration)
+ .markTest(direct: direct);
+ }
+ }
+
void processType(DartType type, {bool direct: true}) {
- if (type.isTypeVariable) {
- TypeVariableType typeVariableType = type;
- TypeVariableEntity variable = typeVariableType.element;
- if (variable.typeDeclaration is ClassEntity) {
- _getClassNode(variable.typeDeclaration).markTest(direct: direct);
- } else {
- _getMethodNode(
- elementEnvironment, worldBuilder, variable.typeDeclaration)
- .markTest(direct: direct);
- }
- } else if (type is FutureOrType) {
+ if (type is FutureOrType) {
_getClassNode(commonElements.futureClass).markIndirectTest();
processType(type.typeArgument, direct: false);
+ } else {
+ type.forEachTypeVariable((TypeVariableType type) {
+ processTypeVariableType(type, direct: direct);
+ });
}
}
diff --git a/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart b/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart
index 58f7e1d..3545b57 100644
--- a/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart
+++ b/tests/compiler/dart2js/equivalence/id_equivalence_helper.dart
@@ -692,7 +692,7 @@
'UNEXPECTED $mode DATA for ${id.descriptor}: '
'Object: ${actualData.objectText}\n '
'expected: ${colorizeExpected('$expected')}\n '
- 'actual: ${colorizeActual('$actual')}');
+ 'actual : ${colorizeActual('$actual')}');
if (filterActualData == null ||
filterActualData(expected, actualData)) {
hasLocalFailure = true;
diff --git a/tests/compiler/dart2js/rti/data/function_subtype_local5.dart b/tests/compiler/dart2js/rti/data/function_subtype_local5.dart
index 6fb64c6..7119670 100644
--- a/tests/compiler/dart2js/rti/data/function_subtype_local5.dart
+++ b/tests/compiler/dart2js/rti/data/function_subtype_local5.dart
@@ -14,7 +14,7 @@
typedef int Boz<T>(T a);
typedef int Biz<T>(T a, int b);
-/*class: C:explicit=[int Function(C.T),int Function(C.T,[String]),int Function(C.T,int),int Function(C.T,{,b:String})],needsArgs*/
+/*class: C:direct,explicit=[int Function(C.T),int Function(C.T,[String]),int Function(C.T,int),int Function(C.T,{,b:String})],needsArgs*/
class C<T> {
void test(String nameOfT, bool expectedResult) {
// TODO(johnniwinther): Optimize local function type signature need.
diff --git a/tests/compiler/dart2js/rti/data/generic_methods_dynamic_05_strong.dart b/tests/compiler/dart2js/rti/data/generic_methods_dynamic_05_strong.dart
index 6208ec6..f438d3f 100644
--- a/tests/compiler/dart2js/rti/data/generic_methods_dynamic_05_strong.dart
+++ b/tests/compiler/dart2js/rti/data/generic_methods_dynamic_05_strong.dart
@@ -20,7 +20,7 @@
class C {
/*!strong.element: C.bar:needsArgs,selectors=[Selector(call, bar, arity=1, types=1)]*/
- /*strong.element: C.bar:explicit=[Iterable<bar.T>],implicit=[bar.T],indirect,needsArgs,selectors=[Selector(call, bar, arity=1, types=1)]*/
+ /*strong.element: C.bar:direct,explicit=[Iterable<bar.T>],implicit=[bar.T],needsArgs,selectors=[Selector(call, bar, arity=1, types=1)]*/
List<T> bar<T>(Iterable<T> t) => <T>[t.first];
}
diff --git a/tests/compiler/dart2js/rti/data/indirect_through_static.dart b/tests/compiler/dart2js/rti/data/indirect_through_static.dart
new file mode 100644
index 0000000..6359003
--- /dev/null
+++ b/tests/compiler/dart2js/rti/data/indirect_through_static.dart
@@ -0,0 +1,50 @@
+// Copyright (c) 2018, 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.
+
+/*kernel.class: A:*/
+/*!kernel.class: A:implicit=[A]*/
+abstract class A {}
+
+class B implements A {}
+
+/*kernel.class: C:
+ deps=[lookup],
+ explicit=[C<lookup.T>]
+*/
+/*strong.class: C:
+ deps=[lookup],
+ explicit=[C<lookup.T>,Map<String,C>],
+ implicit=[C],
+ needsArgs
+*/
+/*omit.class: C:
+ deps=[lookup],explicit=[C<lookup.T>],
+ needsArgs
+*/
+class C<T> {}
+
+final Map<String, C> map = {};
+
+void setup() {
+ map['x'] = new C<B>();
+}
+
+/*kernel.element: lookup:direct,explicit=[C<lookup.T>]*/
+/*!kernel.element: lookup:direct,explicit=[C<lookup.T>],needsArgs*/
+C<T> lookup<T>(String key) {
+ final value = map[key];
+ if (value != null && value is C<T>) {
+ return value;
+ }
+ throw 'Invalid C value for $key: ${value}';
+}
+
+void lookupA() {
+ lookup<A>('x');
+}
+
+main() {
+ setup();
+ lookupA();
+}
diff --git a/tests/compiler/dart2js/rti/data/local_function_map_literal_strong.dart b/tests/compiler/dart2js/rti/data/local_function_map_literal_strong.dart
index 30702fe..ebdd352 100644
--- a/tests/compiler/dart2js/rti/data/local_function_map_literal_strong.dart
+++ b/tests/compiler/dart2js/rti/data/local_function_map_literal_strong.dart
@@ -4,7 +4,7 @@
import 'package:expect/expect.dart';
-/*strong.class: global#LinkedHashMap:deps=[Map],explicit=[LinkedHashMap<LinkedHashMap.K,LinkedHashMap.V>],implicit=[LinkedHashMap.K,LinkedHashMap.V],indirect,needsArgs*/
+/*strong.class: global#LinkedHashMap:deps=[Map],direct,explicit=[LinkedHashMap<LinkedHashMap.K,LinkedHashMap.V>],implicit=[LinkedHashMap.K,LinkedHashMap.V],needsArgs*/
/*omit.class: global#LinkedHashMap:deps=[Map],needsArgs*/
/*strong.element: method:implicit=[method.T],indirect,needsArgs*/
diff --git a/tests/compiler/dart2js/rti/data/map_literal.dart b/tests/compiler/dart2js/rti/data/map_literal.dart
index 2f04d3b..8376333 100644
--- a/tests/compiler/dart2js/rti/data/map_literal.dart
+++ b/tests/compiler/dart2js/rti/data/map_literal.dart
@@ -6,7 +6,7 @@
/*strong.class: global#Map:explicit=[Map],indirect,needsArgs*/
/*!strong.class: global#LinkedHashMap:deps=[Map]*/
-/*strong.class: global#LinkedHashMap:deps=[Map],explicit=[LinkedHashMap<LinkedHashMap.K,LinkedHashMap.V>],implicit=[LinkedHashMap.K,LinkedHashMap.V],indirect,needsArgs*/
+/*strong.class: global#LinkedHashMap:deps=[Map],direct,explicit=[LinkedHashMap<LinkedHashMap.K,LinkedHashMap.V>],implicit=[LinkedHashMap.K,LinkedHashMap.V],needsArgs*/
/*!strong.class: global#JsLinkedHashMap:deps=[LinkedHashMap]*/
/*strong.class: global#JsLinkedHashMap:deps=[LinkedHashMap],direct,explicit=[JsLinkedHashMap.K,JsLinkedHashMap.V,void Function(JsLinkedHashMap.K,JsLinkedHashMap.V)],implicit=[JsLinkedHashMap.K,JsLinkedHashMap.V],needsArgs*/
diff --git a/tests/compiler/dart2js/rti/data/map_literal_checked.dart b/tests/compiler/dart2js/rti/data/map_literal_checked.dart
index 9c6733f..d48447a 100644
--- a/tests/compiler/dart2js/rti/data/map_literal_checked.dart
+++ b/tests/compiler/dart2js/rti/data/map_literal_checked.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
/*class: global#Map:explicit=[Map],indirect,needsArgs*/
-/*class: global#LinkedHashMap:deps=[Map],explicit=[LinkedHashMap<LinkedHashMap.K,LinkedHashMap.V>],implicit=[LinkedHashMap.K,LinkedHashMap.V],indirect,needsArgs*/
+/*class: global#LinkedHashMap:deps=[Map],direct,explicit=[LinkedHashMap<LinkedHashMap.K,LinkedHashMap.V>],implicit=[LinkedHashMap.K,LinkedHashMap.V],needsArgs*/
/*class: global#JsLinkedHashMap:deps=[LinkedHashMap],direct,explicit=[Iterable<JsLinkedHashMap.K>,JsLinkedHashMap.K,JsLinkedHashMap.V,JsLinkedHashMap<JsLinkedHashMap.K,JsLinkedHashMap.V>,void Function(JsLinkedHashMap.K,JsLinkedHashMap.V)],implicit=[JsLinkedHashMap.K,JsLinkedHashMap.V],needsArgs*/
/*class: global#double:explicit=[double],implicit=[double]*/
/*class: global#JSDouble:*/
diff --git a/tests/compiler/dart2js/rti/data/map_literal_strong.dart b/tests/compiler/dart2js/rti/data/map_literal_strong.dart
index 4c0bf5f..92bb292 100644
--- a/tests/compiler/dart2js/rti/data/map_literal_strong.dart
+++ b/tests/compiler/dart2js/rti/data/map_literal_strong.dart
@@ -5,7 +5,7 @@
/*strong.class: global#Map:explicit=[Map],indirect,needsArgs*/
/*omit.class: global#Map:*/
-/*strong.class: global#LinkedHashMap:deps=[Map],explicit=[LinkedHashMap<LinkedHashMap.K,LinkedHashMap.V>],implicit=[LinkedHashMap.K,LinkedHashMap.V],indirect,needsArgs*/
+/*strong.class: global#LinkedHashMap:deps=[Map],direct,explicit=[LinkedHashMap<LinkedHashMap.K,LinkedHashMap.V>],implicit=[LinkedHashMap.K,LinkedHashMap.V],needsArgs*/
/*omit.class: global#LinkedHashMap:deps=[Map]*/
/*strong.class: global#JsLinkedHashMap:deps=[LinkedHashMap],direct,explicit=[JsLinkedHashMap.K,JsLinkedHashMap.V,void Function(JsLinkedHashMap.K,JsLinkedHashMap.V)],implicit=[JsLinkedHashMap.K,JsLinkedHashMap.V],needsArgs*/
diff --git a/tests/compiler/dart2js/rti/data/map_to_set.dart b/tests/compiler/dart2js/rti/data/map_to_set.dart
index 06d337a..073f358 100644
--- a/tests/compiler/dart2js/rti/data/map_to_set.dart
+++ b/tests/compiler/dart2js/rti/data/map_to_set.dart
@@ -6,7 +6,7 @@
/*strong.class: global#Map:deps=[Class,JsLinkedHashMap,MapMixin],explicit=[Map,Map<JsLinkedHashMap.K,JsLinkedHashMap.V>,Map<MapMixin.K,MapMixin.V>],indirect,needsArgs*/
/*!strong.class: global#LinkedHashMap:deps=[Map],needsArgs*/
-/*strong.class: global#LinkedHashMap:deps=[Map],explicit=[LinkedHashMap<LinkedHashMap.K,LinkedHashMap.V>],implicit=[LinkedHashMap.K,LinkedHashMap.V],indirect,needsArgs*/
+/*strong.class: global#LinkedHashMap:deps=[Map],direct,explicit=[LinkedHashMap<LinkedHashMap.K,LinkedHashMap.V>],implicit=[LinkedHashMap.K,LinkedHashMap.V],needsArgs*/
/*!strong.class: global#JsLinkedHashMap:deps=[LinkedHashMap],implicit=[JsLinkedHashMap.K],needsArgs*/
/*strong.class: global#JsLinkedHashMap:deps=[LinkedHashMap],explicit=[JsLinkedHashMap.K,JsLinkedHashMap.V,Map<JsLinkedHashMap.K,JsLinkedHashMap.V>,void Function(JsLinkedHashMap.K,JsLinkedHashMap.V)],implicit=[JsLinkedHashMap.K,JsLinkedHashMap.V],indirect,needsArgs*/
diff --git a/tests/compiler/dart2js/rti/data/map_to_set_strong.dart b/tests/compiler/dart2js/rti/data/map_to_set_strong.dart
index 641baca..89dfbbe 100644
--- a/tests/compiler/dart2js/rti/data/map_to_set_strong.dart
+++ b/tests/compiler/dart2js/rti/data/map_to_set_strong.dart
@@ -5,7 +5,7 @@
/*strong.class: global#Map:deps=[Class,JsLinkedHashMap,MapMixin],explicit=[Map,Map<JsLinkedHashMap.K,JsLinkedHashMap.V>,Map<MapMixin.K,MapMixin.V>],indirect,needsArgs*/
/*omit.class: global#Map:deps=[Class],needsArgs*/
-/*strong.class: global#LinkedHashMap:deps=[Map],explicit=[LinkedHashMap<LinkedHashMap.K,LinkedHashMap.V>],implicit=[LinkedHashMap.K,LinkedHashMap.V],indirect,needsArgs*/
+/*strong.class: global#LinkedHashMap:deps=[Map],direct,explicit=[LinkedHashMap<LinkedHashMap.K,LinkedHashMap.V>],implicit=[LinkedHashMap.K,LinkedHashMap.V],needsArgs*/
/*omit.class: global#LinkedHashMap:deps=[Map],needsArgs*/
/*strong.class: global#JsLinkedHashMap:deps=[LinkedHashMap],explicit=[JsLinkedHashMap.K,JsLinkedHashMap.V,Map<JsLinkedHashMap.K,JsLinkedHashMap.V>,void Function(JsLinkedHashMap.K,JsLinkedHashMap.V)],implicit=[JsLinkedHashMap.K,JsLinkedHashMap.V],indirect,needsArgs*/
diff --git a/tests/compiler/dart2js/rti/data/type_variable_function_type.dart b/tests/compiler/dart2js/rti/data/type_variable_function_type.dart
index 53e53f3..b4a7f70 100644
--- a/tests/compiler/dart2js/rti/data/type_variable_function_type.dart
+++ b/tests/compiler/dart2js/rti/data/type_variable_function_type.dart
@@ -8,7 +8,7 @@
typedef T Func<T>();
-/*class: Foo:explicit=[Foo.S Function()],needsArgs*/
+/*class: Foo:direct,explicit=[Foo.S Function()],needsArgs*/
class Foo<S> {
m(x) => x is Func<S>;
}
diff --git a/tests/compiler/dart2js/rti/emission/indirect_through_static.dart b/tests/compiler/dart2js/rti/emission/indirect_through_static.dart
new file mode 100644
index 0000000..a80da25
--- /dev/null
+++ b/tests/compiler/dart2js/rti/emission/indirect_through_static.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2018, 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.
+
+/*kernel.class: A:*/
+/*!kernel.class: A:checkedInstance,checks=[],typeArgument*/
+abstract class A {}
+
+/*kernel.class: B:checks=[],typeArgument*/
+/*!kernel.class: B:checks=[$isA],typeArgument*/
+class B implements A {}
+
+/*kernel.class: C:checks=[],instance*/
+/*!kernel.class: C:checkedInstance,checks=[],instance,typeArgument*/
+class C<T> {}
+
+final Map<String, C> map = {};
+
+void setup() {
+ map['x'] = new C<B>();
+}
+
+C<T> lookup<T>(String key) {
+ final value = map[key];
+ if (value != null && value is C<T>) {
+ return value;
+ }
+ throw 'Invalid C value for $key: ${value}';
+}
+
+void lookupA() {
+ lookup<A>('x');
+}
+
+main() {
+ setup();
+ lookupA();
+}
diff --git a/tests/compiler/dart2js/rti/rti_need_test_helper.dart b/tests/compiler/dart2js/rti/rti_need_test_helper.dart
index d7a44f5..7386d6a 100644
--- a/tests/compiler/dart2js/rti/rti_need_test_helper.dart
+++ b/tests/compiler/dart2js/rti/rti_need_test_helper.dart
@@ -113,10 +113,10 @@
.contains(frontendClass)) {
features.add(Tags.typeLiteral);
}
- if (rtiNeedBuilder.typeVariableTestsForTesting.directClassTests
+ if (rtiNeedBuilder.typeVariableTestsForTesting.directClassTestsForTesting
.contains(frontendClass)) {
features.add(Tags.directTypeArgumentTest);
- } else if (rtiNeedBuilder.typeVariableTestsForTesting.classTests
+ } else if (rtiNeedBuilder.typeVariableTestsForTesting.classTestsForTesting
.contains(frontendClass)) {
features.add(Tags.indirectTypeArgumentTest);
}
@@ -143,10 +143,12 @@
void addFrontendData(Entity entity) {
findDependencies(features, entity);
- if (rtiNeedBuilder.typeVariableTestsForTesting.directMethodTests
+ if (rtiNeedBuilder
+ .typeVariableTestsForTesting.directMethodTestsForTesting
.contains(entity)) {
features.add(Tags.directTypeArgumentTest);
- } else if (rtiNeedBuilder.typeVariableTestsForTesting.methodTests
+ } else if (rtiNeedBuilder
+ .typeVariableTestsForTesting.methodTestsForTesting
.contains(entity)) {
features.add(Tags.indirectTypeArgumentTest);
}