Emit classes used in type variable replacements
Change-Id: Iad3bf28790172e364d83a96003fb7ef96f25747e
Reviewed-on: https://dart-review.googlesource.com/64322
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index b8fc4c1..8b87744 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -363,6 +363,7 @@
}
break;
case TypeUseKind.RTI_VALUE:
+ case TypeUseKind.TYPE_ARGUMENT:
failedAt(element, "Unexpected type use: $typeUse.");
break;
}
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index a4c49e1..3ab906a 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -381,6 +381,7 @@
}
break;
case TypeUseKind.RTI_VALUE:
+ case TypeUseKind.TYPE_ARGUMENT:
failedAt(CURRENT_ELEMENT_SPANNABLE, "Unexpected type use: $typeUse.");
break;
}
diff --git a/pkg/compiler/lib/src/js_backend/enqueuer.dart b/pkg/compiler/lib/src/js_backend/enqueuer.dart
index 7d9d0b3..3b78c2f 100644
--- a/pkg/compiler/lib/src/js_backend/enqueuer.dart
+++ b/pkg/compiler/lib/src/js_backend/enqueuer.dart
@@ -211,6 +211,9 @@
}
break;
case TypeUseKind.RTI_VALUE:
+ _worldBuilder.registerConstTypeLiteral(type);
+ break;
+ case TypeUseKind.TYPE_ARGUMENT:
_worldBuilder.registerTypeArgument(type);
break;
}
diff --git a/pkg/compiler/lib/src/js_backend/impact_transformer.dart b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
index a4fb279..46e3e2d4 100644
--- a/pkg/compiler/lib/src/js_backend/impact_transformer.dart
+++ b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
@@ -203,6 +203,7 @@
hasTypeLiteral = true;
break;
case TypeUseKind.RTI_VALUE:
+ case TypeUseKind.TYPE_ARGUMENT:
failedAt(CURRENT_ELEMENT_SPANNABLE, "Unexpected type use: $typeUse.");
break;
}
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 00dd8de..7154217 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -1998,6 +1998,9 @@
codegenWorldBuilder.forEachStaticTypeArgument(processMethodTypeArguments);
codegenWorldBuilder.forEachDynamicTypeArgument(processMethodTypeArguments);
+ codegenWorldBuilder.liveTypeArguments.forEach((DartType type) {
+ liveTypeVisitor.visitType(type, TypeVisitorState.typeArgument);
+ });
codegenWorldBuilder.constTypeLiterals.forEach((DartType type) {
liveTypeVisitor.visitType(type, TypeVisitorState.typeLiteral);
});
@@ -2944,12 +2947,10 @@
/// Whether the class is used in a constant type literal.
///
- /// For instance `A`, `B` and `C` in:
+ /// For instance `A`:
///
/// class A {}
- /// class B<T> {}
- /// class C {}
- /// main() => A == B<C>;
+ /// main() => A;
///
bool typeLiteral = false;
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 947432d..2b1adbc 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -3098,6 +3098,10 @@
void visitTypeInfoExpression(HTypeInfoExpression node) {
DartType type = node.dartType;
+ if (node.isTypeVariableReplacement) {
+ _registry.registerTypeUse(new TypeUse.typeArgument(type));
+ }
+
List<js.Expression> arguments = <js.Expression>[];
for (HInstruction input in node.inputs) {
use(input);
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 4451c74..9488821 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -3699,8 +3699,13 @@
class HTypeInfoExpression extends HInstruction {
final TypeInfoExpressionKind kind;
final DartType dartType;
+
+ /// `true` if this
+ final bool isTypeVariableReplacement;
+
HTypeInfoExpression(this.kind, this.dartType, List<HInstruction> inputs,
- AbstractValue instructionType)
+ AbstractValue instructionType,
+ {this.isTypeVariableReplacement: false})
: super(inputs, instructionType) {
setUseGvn();
}
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 17d701f..145497d 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -1404,7 +1404,8 @@
TypeInfoExpressionKind.COMPLETE,
typeArgument,
const <HInstruction>[],
- _abstractValueDomain.dynamicType);
+ _abstractValueDomain.dynamicType,
+ isTypeVariableReplacement: true);
return replacement;
}
return node;
@@ -1436,7 +1437,8 @@
TypeInfoExpressionKind.COMPLETE,
type,
arguments,
- _abstractValueDomain.dynamicType);
+ _abstractValueDomain.dynamicType,
+ isTypeVariableReplacement: true);
return replacement;
}
diff --git a/pkg/compiler/lib/src/universe/codegen_world_builder.dart b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
index cc99a9d..0e371ba 100644
--- a/pkg/compiler/lib/src/universe/codegen_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
@@ -80,6 +80,9 @@
/// Returns the types that are live as constant type literals.
Iterable<DartType> get constTypeLiterals;
+
+ /// Returns the types that are live as constant type literals.
+ Iterable<DartType> get liveTypeArguments;
}
class CodegenWorldBuilderImpl extends WorldBuilderBase
@@ -165,6 +168,7 @@
final KernelToWorldBuilder _elementMap;
final GlobalLocalsMap _globalLocalsMap;
+ final Set<DartType> _constTypeLiterals = new Set<DartType>();
final Set<DartType> _liveTypeArguments = new Set<DartType>();
CodegenWorldBuilderImpl(
@@ -692,9 +696,15 @@
});
}
+ void registerConstTypeLiteral(DartType type) {
+ _constTypeLiterals.add(type);
+ }
+
+ Iterable<DartType> get constTypeLiterals => _constTypeLiterals;
+
void registerTypeArgument(DartType type) {
_liveTypeArguments.add(type);
}
- Iterable<DartType> get constTypeLiterals => _liveTypeArguments;
+ Iterable<DartType> get liveTypeArguments => _liveTypeArguments;
}
diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart
index 9972e88..f6d00aa 100644
--- a/pkg/compiler/lib/src/universe/use.dart
+++ b/pkg/compiler/lib/src/universe/use.dart
@@ -577,6 +577,7 @@
IMPLICIT_CAST,
PARAMETER_CHECK,
RTI_VALUE,
+ TYPE_ARGUMENT,
}
/// Use of a [DartType].
@@ -625,6 +626,9 @@
sb.write('param:');
break;
case TypeUseKind.RTI_VALUE:
+ sb.write('rti:');
+ break;
+ case TypeUseKind.TYPE_ARGUMENT:
sb.write('typeArg:');
break;
}
@@ -695,6 +699,14 @@
return new TypeUse.internal(type, TypeUseKind.RTI_VALUE);
}
+ /// [type] used directly as a type argument.
+ ///
+ /// The happens during optimization where a type variable can be replaced by
+ /// an invariable type argument derived from a constant receiver.
+ factory TypeUse.typeArgument(DartType type) {
+ return new TypeUse.internal(type, TypeUseKind.TYPE_ARGUMENT);
+ }
+
bool operator ==(other) {
if (identical(this, other)) return true;
if (other is! TypeUse) return false;
diff --git a/tests/compiler/dart2js/rti/emission/event_callback.dart b/tests/compiler/dart2js/rti/emission/event_callback.dart
index a0c84dd..37da4d1 100644
--- a/tests/compiler/dart2js/rti/emission/event_callback.dart
+++ b/tests/compiler/dart2js/rti/emission/event_callback.dart
@@ -7,8 +7,13 @@
/*kernel.class: global#Event:checkedTypeArgument,checks=[$isEvent],instance,typeArgument*/
/*strong.class: global#Event:checkedInstance,checkedTypeArgument,checks=[$isEvent],instance,typeArgument*/
-/*class: global#MouseEvent:checks=[],instance*/
-/*class: global#KeyboardEvent:checks=[],instance*/
+/*kernel.class: global#MouseEvent:checks=[$isMouseEvent],instance,typeArgument*/
+/*strong.class: global#MouseEvent:checks=[$isMouseEvent],instance,typeArgument*/
+/*omit.class: global#MouseEvent:checks=[],instance*/
+
+/*kernel.class: global#KeyboardEvent:checks=[$isKeyboardEvent],instance,typeArgument*/
+/*strong.class: global#KeyboardEvent:checks=[$isKeyboardEvent],instance,typeArgument*/
+/*omit.class: global#KeyboardEvent:checks=[],instance*/
void main() {
print('InputElement');
diff --git a/tests/compiler/dart2js/rti/emission/replaced_type_variable.dart b/tests/compiler/dart2js/rti/emission/replaced_type_variable.dart
new file mode 100644
index 0000000..5b22b5f
--- /dev/null
+++ b/tests/compiler/dart2js/rti/emission/replaced_type_variable.dart
@@ -0,0 +1,23 @@
+// 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.
+
+import 'package:expect/expect.dart';
+
+// This class is inlined away.
+/*class: Class:*/
+class Class<T> {
+ const Class();
+
+ Type get type => T;
+}
+
+/*class: A:checks=[],typeArgument*/
+class A {}
+
+@NoInline()
+test(o) => Expect.notEquals('dynamic', '$o');
+
+main() {
+ test(const Class<A>().type);
+}
diff --git a/tests/compiler/dart2js_extra/replaced_type_variable_test.dart b/tests/compiler/dart2js_extra/replaced_type_variable_test.dart
new file mode 100644
index 0000000..f530000
--- /dev/null
+++ b/tests/compiler/dart2js_extra/replaced_type_variable_test.dart
@@ -0,0 +1,21 @@
+// 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.
+
+import 'package:expect/expect.dart';
+
+// This class is inlined away.
+class Class<T> {
+ const Class();
+
+ Type get type => T;
+}
+
+class A {}
+
+@NoInline()
+test(o) => Expect.notEquals('dynamic', '$o');
+
+main() {
+ test(const Class<A>().type);
+}