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 b238df675acd8f619b59dfa13fac8e256c34415f..922eb5f207f8ad32875f802092cd43c8083f1d3b 100644 |
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart |
@@ -94,6 +94,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]. |
@@ -114,7 +125,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 supertype of a class that uses |
ngeoffray
2013/02/18 09:27:58
supertype -> subtype?
karlklose
2013/02/18 16:02:01
Done.
|
+ // 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; |
ngeoffray
2013/02/18 09:27:58
Shouldn't that be in codegenWorld as well?
karlklose
2013/02/18 16:02:01
This is in the shared world. I am not sure it is w
ngeoffray
2013/02/19 09:00:41
Why not? The codegen world will have less or equal
karlklose
2013/02/19 12:39:28
Moved to the backend.
|
+ !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) { |
@@ -789,7 +837,7 @@ $lazyInitializerLogic |
void generateIsTest(Element other) { |
js.Expression code; |
- if (compiler.objectClass == other) return; |
+ if (other == compiler.objectClass && classElement != other) return; |
ngeoffray
2013/02/18 09:27:58
Why this change? It looks like you're getting rid
karlklose
2013/02/18 16:02:01
We may need the $isObject flag on objects now, whe
ngeoffray
2013/02/19 09:00:41
So why did you remove it in the new version of the
|
if (nativeEmitter.requiresNativeIsCheck(other)) { |
code = js.fun([], js.block1(js.return_(new js.LiteralBool(true)))); |
} else { |
@@ -871,8 +919,7 @@ $lazyInitializerLogic |
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 |
@@ -893,6 +940,16 @@ $lazyInitializerLogic |
} |
}; |
} |
+ |
+ // 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) { |
+ js.Expression nativeCheck = rti.getNativeCheck(cls); |
+ String holder = namer.isolateAccess(cls); |
+ buffer.add('$holder.${rti.getNativeCheckName()}$_=$_'); |
+ buffer.addBuffer(js.prettyPrint(nativeCheck, compiler)); |
+ buffer.add('$N'); |
+ }); |
} |
void visitNativeMixins(ClassElement classElement, |