Index: compiler/java/com/google/dart/compiler/backend/js/RuntimeTypeInjector.java |
diff --git a/compiler/java/com/google/dart/compiler/backend/js/RuntimeTypeInjector.java b/compiler/java/com/google/dart/compiler/backend/js/RuntimeTypeInjector.java |
index 44ae3c5c99322b3cd85fc5fd95fda8417479ab7c..81f28cb1cde9c0a1d23fbfbd2e40aa1f0192ce63 100644 |
--- a/compiler/java/com/google/dart/compiler/backend/js/RuntimeTypeInjector.java |
+++ b/compiler/java/com/google/dart/compiler/backend/js/RuntimeTypeInjector.java |
@@ -46,10 +46,14 @@ import com.google.dart.compiler.InternalCompilerException; |
import com.google.dart.compiler.ast.DartArrayLiteral; |
import com.google.dart.compiler.ast.DartClass; |
import com.google.dart.compiler.ast.DartClassMember; |
+import com.google.dart.compiler.ast.DartFunctionExpression; |
+import com.google.dart.compiler.ast.DartFunctionTypeAlias; |
import com.google.dart.compiler.ast.DartMapLiteral; |
import com.google.dart.compiler.ast.DartMethodDefinition; |
import com.google.dart.compiler.ast.DartNewExpression; |
+import com.google.dart.compiler.ast.DartParameter; |
import com.google.dart.compiler.ast.DartTypeNode; |
+import com.google.dart.compiler.ast.Modifiers; |
import com.google.dart.compiler.backend.js.ast.JsArrayAccess; |
import com.google.dart.compiler.backend.js.ast.JsArrayLiteral; |
import com.google.dart.compiler.backend.js.ast.JsBlock; |
@@ -66,16 +70,26 @@ import com.google.dart.compiler.backend.js.ast.JsStatement; |
import com.google.dart.compiler.backend.js.ast.JsStringLiteral; |
import com.google.dart.compiler.backend.js.ast.JsThisRef; |
import com.google.dart.compiler.common.SourceInfo; |
+import com.google.dart.compiler.common.Symbol; |
import com.google.dart.compiler.resolver.ClassElement; |
import com.google.dart.compiler.resolver.ConstructorElement; |
import com.google.dart.compiler.resolver.CoreTypeProvider; |
+import com.google.dart.compiler.resolver.DynamicElement; |
+import com.google.dart.compiler.resolver.Element; |
import com.google.dart.compiler.resolver.ElementKind; |
+import com.google.dart.compiler.resolver.Elements; |
+import com.google.dart.compiler.resolver.EnclosingElement; |
+import com.google.dart.compiler.resolver.FunctionAliasElementImplementation; |
+import com.google.dart.compiler.resolver.MethodElement; |
+import com.google.dart.compiler.resolver.VariableElement; |
+import com.google.dart.compiler.type.FunctionAliasType; |
import com.google.dart.compiler.type.FunctionType; |
import com.google.dart.compiler.type.InterfaceType; |
import com.google.dart.compiler.type.Type; |
import com.google.dart.compiler.type.TypeKind; |
import com.google.dart.compiler.type.TypeVariable; |
import com.google.dart.compiler.type.Types; |
+import com.google.dart.compiler.util.AstUtil; |
import java.util.List; |
import java.util.Map; |
@@ -133,6 +147,27 @@ public class RuntimeTypeInjector { |
} |
} |
+ /** |
+ * Generate the code necessary to allow for runtime type checks of dart typedefs |
+ */ |
+ void generateRuntimeTypeInfo(DartFunctionTypeAlias x) { |
+ generateRuntimeTypeInfoMethods(x); |
+ } |
+ |
+ /** |
+ * Generate the code necessary to allow for runtime type checks of dart class methods |
+ */ |
+ void generateRuntimeTypeInfo(DartMethodDefinition x) { |
+ generateRuntimeTypeInfoMethods(x); |
+ } |
+ |
+ /** |
+ * Generate the code necessary to allow for runtime type checks of dart function expressions |
+ */ |
+ void generateRuntimeTypeInfo(DartFunctionExpression x, String lookupName) { |
+ generateRTTLookupMethod(x, lookupName); |
+ } |
+ |
private void injectInterfaceMarkers(ClassElement classElement, SourceInfo srcRef) { |
JsProgram program = translationContext.getProgram(); |
JsName classJsName = translationContext.getNames().getName(classElement); |
@@ -190,6 +225,24 @@ public class RuntimeTypeInjector { |
generateRTTAddToMethod(x); |
} |
+ /** |
+ * Insert the function or method necessary to implement runtime type information for the provided |
+ * dart function alias. |
+ */ |
+ private void generateRuntimeTypeInfoMethods(DartFunctionTypeAlias x) { |
+ // 1) create static type information lookup function |
+ generateRTTLookupMethod(x); |
+ } |
+ |
+ /** |
+ * Insert the function or method necessary to implement runtime type information for the provided |
+ * dart class method. |
+ */ |
+ private void generateRuntimeTypeInfoMethods(DartMethodDefinition x) { |
+ // 1) create static type information lookup function |
+ generateRTTLookupMethod(x); |
+ } |
+ |
private void generateRTTLookupMethod(DartClass x) { |
ClassElement classElement = x.getSymbol(); |
boolean hasTypeParams = hasTypeParameters(classElement); |
@@ -352,6 +405,12 @@ public class RuntimeTypeInjector { |
for (InterfaceType interfaceType : classElement.getInterfaces() ) { |
ClassElement interfaceElement = interfaceType.getElement(); |
+ // Codefu: Random addition to keep BlackListed13 tests failing. |
+ // RTT.dynamic could define $addTo(), but this should be treated as a |
+ // a compile time error, not a run time error. |
+ if(interfaceElement instanceof DynamicElement) { |
zundel
2011/11/16 22:17:15
style: space between if and (
codefu
2011/11/16 22:39:55
Done.
|
+ continue; |
+ } |
JsInvocation callAddTo = call(null, |
getRTTAddToMethodName(interfaceElement), targetType.makeRef()); |
if (hasTypeParameters(interfaceElement) && !interfaceType.hasDynamicTypeArgs()) { |
@@ -373,6 +432,245 @@ public class RuntimeTypeInjector { |
globalBlock.getStatements().add(fnDecl.makeStmt()); |
} |
+ private void generateRTTLookupMethod(DartMethodDefinition x) { |
zundel
2011/11/16 22:17:15
is it just me, or dos this duplicate a lot of code
codefu
2011/11/16 22:39:55
There are now 4 generateRTTLookupMethod(). One ex
|
+ MethodElement methodElement = x.getSymbol(); |
+ if (Elements.isTopLevel(methodElement)) { |
+ return; /* TODO(codefu): Handle these top levels. They just don't have generic types */ |
+ } |
+ if (methodElement instanceof ConstructorElement |
zundel
2011/11/16 22:17:15
ElementKind.of(methodElement).equals(CONSTRUCTOR)
codefu
2011/11/16 22:39:55
Borrowed code. Will look into it.
|
+ || Elements.isNonFactoryConstructor(methodElement) |
+ || methodElement.getModifiers().isFactory() || methodElement.getModifiers().isNative()) { |
+ /* No type lookups for factories or constructors */ |
+ return; |
+ } |
+ ClassElement classElement = (ClassElement) methodElement.getEnclosingElement(); |
+ JsProgram program = translationContext.getProgram(); |
+ |
+ // Create function looking up RTT parameters and return type for method x |
+ // return codefu86182b$A$Dart.$lookupRTT(null,Collection$Dart.$lookupRTT([RTT.getTypeArg(RTT.getTypeArgsFor(this, $cls('codefu86182b$A$Dart')), 0)])); |
+ |
+ JsExpression typeArgContextExpr = buildTypeArgsReference(classElement); |
+ |
+ // Build the function |
+ JsFunction lookupFn = new JsFunction(globalScope); |
+ lookupFn.setBody(new JsBlock()); |
+ JsScope scope = new JsScope(globalScope, "temp"); |
+ |
+ List<JsStatement> body = lookupFn.getBody().getStatements(); |
+ JsInvocation callLookup = call(null,newQualifiedNameRef("RTT.createFunction")); |
zundel
2011/11/16 22:17:15
style nit: space after ,
codefu
2011/11/16 22:39:55
Done.
|
+ |
+ JsArrayLiteral arr = generateTypeArrayFromElements(methodElement.getParameters(), classElement, |
+ typeArgContextExpr); |
+ if (arr == null) { |
+ return; // Do not generate a lookup function |
+ } |
+ |
+ JsExpression returnExpr = generateRTTLookupForType(methodElement.getReturnType(), |
+ classElement, typeArgContextExpr); |
+ |
+ callLookup.getArguments().add(arr.getExpressions().isEmpty() ? program.getNullLiteral() : arr); |
+ callLookup.getArguments().add(returnExpr); |
+ body.add(new JsReturn(callLookup)); |
+ |
+ // Finally, Add the function |
+ JsExpression fnDecl; |
+ if (methodElement.getEnclosingElement().getKind().equals(ElementKind.CLASS)) { |
+ JsNameRef prop = makeMethodJsReference(methodElement); |
+ fnDecl = assign(null, prop, lookupFn); |
+ } else { |
+ fnDecl = assign(null, getRTTLookupMethodName(classElement), lookupFn); |
+ } |
+ |
+ globalBlock.getStatements().add(fnDecl.makeStmt()); |
+ } |
+ |
+ private void generateRTTLookupMethod(DartFunctionExpression x, String overrideName) { |
+ MethodElement methodElement = x.getSymbol(); |
+ if (Elements.isTopLevel(methodElement)) { |
+ /* TODO(codefu): Handle top level methods. */ |
+ return; |
+ } |
+ boolean hasTypes = false; |
+ |
+ if (methodElement instanceof ConstructorElement |
zundel
2011/11/16 22:17:15
again, ElementKind.of(...).equals(CONSTRUCTOR) mig
|
+ || Elements.isNonFactoryConstructor(methodElement) |
+ || methodElement.getModifiers().isFactory() || methodElement.getModifiers().isNative()) { |
+ /* No type lookups for factories or constructors */ |
+ return; |
+ } |
+ EnclosingElement methodMethodElement = methodElement.getEnclosingElement(); |
+ ClassElement classElement = null; |
+ if (methodMethodElement.getEnclosingElement() instanceof ClassElement) { |
+ classElement = (ClassElement) methodMethodElement.getEnclosingElement(); |
+ hasTypes = hasTypeParameters(classElement); |
+ } else { |
+ hasTypes = false; |
+ } |
+ JsProgram program = translationContext.getProgram(); |
+ |
+ // Create function looking up RTT parameters and return type for method x |
+ // return codefu86182b$A$Dart.$lookupRTT(null,Collection$Dart.$lookupRTT([RTT.getTypeArg(RTT.getTypeArgsFor(this, $cls('codefu86182b$A$Dart')), 0)])); |
+ JsExpression typeArgContextExpr = hasTypes ? buildTypeArgsReference(classElement) : null; |
+ |
+ // Build the function |
+ JsFunction lookupFn = new JsFunction(globalScope); |
+ lookupFn.setBody(new JsBlock()); |
+ JsScope scope = new JsScope(globalScope, "temp"); |
+ |
+ List<JsStatement> body = lookupFn.getBody().getStatements(); |
+ JsInvocation callLookup; |
+ |
+ callLookup = newInvocation(newQualifiedNameRef("RTT.createFunction")); |
+ |
+ JsArrayLiteral arr = generateTypeArrayFromElements(methodElement.getParameters(), classElement, |
+ typeArgContextExpr); |
+ if (arr == null) { |
+ return; // Do not generate a lookup function |
+ } |
+ |
+ JsExpression returnExpr = generateRTTLookupForType(methodElement.getReturnType(), |
+ classElement, typeArgContextExpr); |
+ |
+ callLookup.getArguments().add(arr.getExpressions().isEmpty() ? program.getNullLiteral() : arr); |
+ callLookup.getArguments().add(returnExpr); |
+ body.add(new JsReturn(callLookup)); |
+ |
+ // Finally, Add the function |
+ JsNameRef funcName = new JsNameRef(overrideName + "$lookupRTT"); |
+ JsExpression fnDecl = assign(null, funcName, lookupFn); |
+ globalBlock.getStatements().add(fnDecl.makeStmt()); |
+ } |
+ |
+ private JsArrayLiteral generateTypeArrayFromParameters(List<DartParameter> params, |
+ ClassElement classElement, JsExpression typeArgContextExpr) { |
+ JsArrayLiteral jsTypeArray = new JsArrayLiteral(); |
+ for (DartParameter param : params) { |
+ JsExpression elementExpr; |
+ if (param.getTypeNode() == null) { |
+ elementExpr = AstUtil.newNameRef(null, "RTT.dynamicType"); |
+ } else { |
+ elementExpr = generateRTTLookupForType(param.getTypeNode().getType(), classElement, |
+ typeArgContextExpr); |
+ if (elementExpr == null) { |
+ return null; |
+ } |
+ } |
+ jsTypeArray.getExpressions().add(elementExpr); |
+ } |
+ return jsTypeArray; |
+ } |
+ |
+ private JsArrayLiteral generateTypeArrayFromElements(List<VariableElement> elements, |
+ ClassElement classElement, JsExpression typeArgContextExpr) { |
+ JsArrayLiteral jsTypeArray = new JsArrayLiteral(); |
+ for (VariableElement element : elements) { |
+ JsExpression rttTypeExpression = generateRTTLookupForType(element.getType(), classElement, |
+ typeArgContextExpr); |
+ if (rttTypeExpression == null) { |
+ return null; |
+ } |
+ jsTypeArray.getExpressions().add(rttTypeExpression); |
+ } |
+ return jsTypeArray; |
+ } |
+ |
+ private JsExpression generateRTTLookupForType(Type elementType, ClassElement classElement, |
+ JsExpression typeArgContextExpr) { |
+ JsExpression elementExpr = null; |
+ switch (TypeKind.of(elementType)) { |
+ case VARIABLE: |
+ elementExpr = buildTypeLookupExpression(elementType, classElement.getTypeParameters(), |
+ typeArgContextExpr); |
+ break; |
+ case INTERFACE: |
+ elementExpr = generateRTTLookup((ClassElement) elementType.getElement(), |
+ (InterfaceType) elementType, classElement); |
+ break; |
+ case FUNCTION: |
+ case FUNCTION_ALIAS: |
+ // TODO(codefu): implement this. |
+ elementExpr = AstUtil.newNameRef(null, "RTT.dynamicType"); |
+// elementExpr = buildTypeLookupExpression(elementType, classElement.getTypeParameters(), |
+// typeArgContextExpr); |
+ break; |
+ case DYNAMIC: |
+ elementExpr = AstUtil.newNameRef(null, "RTT.dynamicType"); |
+ break; |
+ case VOID: |
+ case NONE: |
+ elementExpr = translationContext.getProgram().getNullLiteral(); |
+ break; |
+ default: |
+ // Do not generate a lookup method |
+ elementExpr = buildTypeLookupExpression(elementType, classElement.getTypeParameters(), |
+ typeArgContextExpr); |
+ break; |
+ } |
+ return elementExpr; |
+ } |
+ |
+ private JsName getJsName(Symbol symbol) { |
+ return translationContext.getNames().getName(symbol); |
+ } |
+ |
+ private JsNameRef makeMethodJsReference(Element element) { |
+ JsNameRef qualifier; |
+ boolean isNonFactoryConstructor = Elements.isNonFactoryConstructor(element); |
+ Modifiers modifiers = element.getModifiers(); |
+ |
+ JsNameRef classJsName = getJsName(element.getEnclosingElement()).makeRef(); |
+ if (modifiers.isStatic() || modifiers.isFactory() || isNonFactoryConstructor) { |
+ // Static methods hang directly from the constructor. |
+ qualifier = classJsName; |
+ } else { |
+ // Instance methods hang from the prototype. |
+ qualifier = AstUtil.newPrototypeNameRef(classJsName); |
+ } |
+ |
+ JsNameRef asdf = newNameRef(qualifier, element.getName() + "$lookupRTT"); |
+ return asdf; |
+ } |
+ |
+ private void generateRTTLookupMethod(DartFunctionTypeAlias x) { |
zundel
2011/11/16 23:54:56
Add a comment with an example of the JS this gener
codefu
2011/11/17 21:17:10
Definitely here and other places.
|
+ FunctionAliasElementImplementation classElement = (FunctionAliasElementImplementation) x.getSymbol(); |
+ FunctionType funcType = classElement.getFunctionType(); |
+ boolean hasTypeParams = hasTypeParameters(classElement); |
+ |
+ // Build the function |
+ JsFunction lookupFn = new JsFunction(globalScope); |
+ lookupFn.setBody(new JsBlock()); |
+ List<JsStatement> body = lookupFn.getBody().getStatements(); |
+ JsScope scope = new JsScope(globalScope, "temp"); |
+ |
+ JsProgram program = translationContext.getProgram(); |
+ |
+ JsInvocation invokeCreate = call(null, newQualifiedNameRef("RTT.createFunction")); |
+ List<JsExpression> callArgs = invokeCreate.getArguments(); |
+ |
+ JsName typeArgs = scope.declareName("typeArgs"); |
+ JsExpression typeArgsExpr = new JsNameRef("typeArgs"); |
+ lookupFn.getParameters().add(new JsParameter(typeArgs)); |
+ |
+ JsArrayLiteral arr = generateTypeArrayFromParameters(x.getParameters(), classElement, |
+ typeArgsExpr); |
+ if (arr == null) { |
+ return; // Do not generate a lookup function |
+ } |
+ callArgs.add(arr.getExpressions().isEmpty() ? program.getNullLiteral() : arr); |
+ |
+ //generateRTTLookupForType |
+ //generateRTTLookupForReturnType |
zundel
2011/11/16 23:54:56
not sure what these comments mean
codefu
2011/11/17 21:17:10
Left-over cruft from when I was first writing this
|
+ JsExpression returnExpr = generateRTTLookupForType(funcType.getReturnType(), |
+ classElement, typeArgsExpr); |
+ callArgs.add(returnExpr); |
+ |
+ body.add(new JsReturn(invokeCreate)); |
+ |
+ // Finally, Add the function |
+ JsExpression fnDecl = assign(null, getRTTLookupMethodName(classElement), lookupFn); |
+ globalBlock.getStatements().add(fnDecl.makeStmt()); |
+ } |
+ |
static JsExpression getRTTClassId(TranslationContext translationContext, |
ClassElement classElement) { |
JsName classJsName = translationContext.getNames().getName(classElement); |
@@ -510,7 +808,12 @@ public class RuntimeTypeInjector { |
((FunctionType)contextElement.getType()).getTypeVariables(), |
buildFactoryTypeInfoReference()); |
} else { |
- typeArgs = buildTypeArgs(instanceType, null, null); |
+ if( contextClassElement instanceof FunctionAliasElementImplementation) { |
+ typeArgs = buildTypeArgs(instanceType, contextClassElement.getTypeParameters(), |
+ new JsNameRef("typeArgs")); |
+ } else { |
+ typeArgs = buildTypeArgs(instanceType, null, null); |
+ } |
} |
} else { |
// Build type args in a class context: |
@@ -748,6 +1051,14 @@ public class RuntimeTypeInjector { |
case DYNAMIC: |
JsProgram program = translationContext.getProgram(); |
return program.getTrueLiteral(); |
+ case FUNCTION_ALIAS: |
+ FunctionAliasType aliasType = (FunctionAliasType) type; |
+ if (hasTypeParameters(aliasType.getElement()) && !aliasType.hasDynamicTypeArgs()) { |
+ return generateRefiedInterfaceTypeComparison(lhs, aliasType, currentClass, src); |
+ } else { |
+ // TODO(?cp from above): special case "is Object"? |
+ return generateRefiedInterfaceTypeComparison(lhs, aliasType, currentClass, src); |
zundel
2011/11/16 23:54:56
this code as is just looks redundant. I can't mak
codefu
2011/11/17 21:17:10
This is redundant. The comment is left over from w
|
+ } |
default: |
throw new IllegalStateException("unexpected"); |
} |