Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(310)

Unified Diff: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart

Issue 12210142: Implement is-checks against type variables. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Do not emit Object.isObject. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
index be37c5daea62adebfd90ddd7547fe647d576cced..7df5b916005159ce4d5ebcb7fa963ab9acb53437 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -98,6 +98,17 @@ class CodeEmitterTask extends CompilerTask {
Set<ClassElement> checkedClasses;
/**
+ * Set of JS native classes (or 'Object') that need a [:$nativeCheck:] method,
+ * because they could be used as a type argument in an is-check.
+ *
+ * For example, in the following program, the class int needs a native check
+ * to correctly match integers in the is-check:
+ * class Check<T> { foo(o) => o is T; }
+ * main() => new Check<int>().foo(3);
+ */
+ Set<ClassElement> requiredNativeChecks;
+
+ /**
* Raw Typedef symbols occuring in is-checks and type assertions. If the
* program contains `x is F<int>` and `x is F<bool>` then the TypedefElement
* `F` will occur once in [checkedTypedefs].
@@ -118,7 +129,44 @@ class CodeEmitterTask extends CompilerTask {
}
void computeRequiredTypeChecks() {
- assert(checkedClasses == null);
+ assert(checkedClasses == null &&
+ checkedTypedefs == null &&
+ requiredNativeChecks == null);
+
+ // Compute type arguments of classes that potentially use their type
+ // variables in is-checks and compute the (small) set of classes that
+ // need native check methods (consult the documentation of
+ // [requiredNativeChecks] for more information).
+ requiredNativeChecks = new Set<ClassElement>();
+ Link<ClassElement> classes = compiler.world.classesUsingTypeVariableTests;
+ if (!classes.isEmpty) {
+ // Find all instantiated types that are a subtype of a class that uses
+ // one of its type arguments in an is-check and add the arguments to the
+ // set of is-checks.
+ for (DartType type in compiler.codegenWorld.instantiatedTypes) {
+ if (type.kind != TypeKind.INTERFACE) continue;
+ InterfaceType classType = type;
+ for (classes = compiler.world.classesUsingTypeVariableTests;
+ !classes.isEmpty;
+ classes = classes.tail) {
+ // We need the type as instance of its superclass anyway, so we just
+ // try to compute the substitution; if the result is [:null:], the
+ // classes are not related.
+ InterfaceType instance = classType.asInstanceOf(classes.head);
+ if (instance == null) continue;
+ Link<DartType> typeArguments = instance.typeArguments;
+ for (DartType argument in typeArguments) {
+ Element element = argument.element;
+ JavaScriptBackend backend = compiler.backend;
+ if (backend.rti.needsNativeCheck(element)) {
+ requiredNativeChecks.add(element);
+ }
+ compiler.codegenWorld.isChecks.add(argument);
+ }
+ }
+ }
+ }
+
checkedClasses = new Set<ClassElement>();
checkedTypedefs = new Set<TypedefElement>();
compiler.codegenWorld.isChecks.forEach((DartType t) {
@@ -1074,7 +1122,7 @@ class CodeEmitterTask extends CompilerTask {
void generateIsTest(Element other) {
jsAst.Expression code;
- if (compiler.objectClass == other) return;
+ if (other == compiler.objectClass) return;
if (nativeEmitter.requiresNativeIsCheck(other)) {
code = js.fun([], [js.return_(true)]);
} else {
@@ -1135,7 +1183,7 @@ class CodeEmitterTask extends CompilerTask {
}
}
- void emitRuntimeClassesAndTests(CodeBuffer buffer) {
+ void emitRuntimeTypeSupport(CodeBuffer buffer) {
RuntimeTypeInformation rti = backend.rti;
TypeChecks typeChecks = rti.getRequiredChecks();
@@ -1154,8 +1202,7 @@ class CodeEmitterTask extends CompilerTask {
if (!needsHolder(cls)) return;
String holder = namer.isolateAccess(cls);
String name = namer.getName(cls);
- buffer.add("$holder$_=$_{builtin\$cls:$_'$name'");
- buffer.add('}$N');
+ buffer.add("$holder$_=$_{builtin\$cls:$_'$name'}$N");
}
// Create representation objects for classes that we do not have a class
@@ -1176,6 +1223,16 @@ class CodeEmitterTask extends CompilerTask {
}
};
}
+
+ // Emit native check methods for the class representations of native types
+ // that could be used in an is-check against a type variable.
+ requiredNativeChecks.forEach((ClassElement cls) {
+ jsAst.Expression nativeCheck = rti.getNativeCheck(cls);
+ String holder = namer.isolateAccess(cls);
+ buffer.add('$holder.${namer.getNativeCheckName()}$_=$_');
+ buffer.addBuffer(jsAst.prettyPrint(nativeCheck, compiler));
+ buffer.add('$N');
+ });
}
void visitNativeMixins(ClassElement classElement,
@@ -1558,6 +1615,11 @@ class CodeEmitterTask extends CompilerTask {
emitted.add(superclass);
}
for (DartType supertype in cls.allSupertypes) {
+ ClassElement superclass = supertype.element;
+ if (compiler.world.classesUsingTypeVariableTests.contains(superclass)) {
ngeoffray 2013/02/19 09:00:41 Why is this needed now? Please add a comment and/o
+ emitSubstitution(superclass, emitNull: true);
+ emitted.add(superclass);
+ }
for (ClassElement check in checkedClasses) {
if (supertype.element == check && !emitted.contains(check)) {
// Generate substitution. If no substitution is necessary, emit
@@ -2605,7 +2667,7 @@ if (typeof document !== 'undefined' && document.readyState !== 'complete') {
// We need to finish the classes before we construct compile time
// constants.
emitFinishClassesInvocationIfNecessary(mainBuffer);
- emitRuntimeClassesAndTests(mainBuffer);
+ emitRuntimeTypeSupport(mainBuffer);
emitCompileTimeConstants(mainBuffer);
// Static field initializations require the classes and compile-time
// constants to be set up.

Powered by Google App Engine
This is Rietveld 408576698