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..3e4e80889f0740f8a6ea6fcac4a8682b07a731e2 100644 |
--- a/compiler/java/com/google/dart/compiler/backend/js/RuntimeTypeInjector.java |
+++ b/compiler/java/com/google/dart/compiler/backend/js/RuntimeTypeInjector.java |
@@ -46,12 +46,16 @@ 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.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.JsBinaryOperation; |
import com.google.dart.compiler.backend.js.ast.JsBlock; |
import com.google.dart.compiler.backend.js.ast.JsExpression; |
import com.google.dart.compiler.backend.js.ast.JsFunction; |
@@ -66,16 +70,25 @@ 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.Element; |
import com.google.dart.compiler.resolver.ElementKind; |
+import com.google.dart.compiler.resolver.Elements; |
+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.resolver.TypeVariableElement; |
+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 +146,20 @@ public class RuntimeTypeInjector { |
} |
} |
+ /** |
+ * Generate the code necessary to allow for runtime type checks |
+ */ |
+ void generateRuntimeTypeInfo(DartFunctionTypeAlias x) { |
+ generateRuntimeTypeInfoMethods(x); |
+ } |
+ |
+ /** |
+ * Generate the code necessary to allow for runtime type checks |
+ */ |
+ void generateRuntimeTypeInfo(DartMethodDefinition x) { |
+ generateRuntimeTypeInfoMethods(x); |
+ } |
+ |
private void injectInterfaceMarkers(ClassElement classElement, SourceInfo srcRef) { |
JsProgram program = translationContext.getProgram(); |
JsName classJsName = translationContext.getNames().getName(classElement); |
@@ -190,6 +217,30 @@ public class RuntimeTypeInjector { |
generateRTTAddToMethod(x); |
} |
+ /** |
+ * Insert the function or method necessary to implement runtime type information |
+ * for the provided class. |
+ */ |
+ private void generateRuntimeTypeInfoMethods(DartFunctionTypeAlias x) { |
+ // 1) create static type information lookup function |
+ generateRTTLookupMethod(x); |
+ |
+ // 3) create "addTo" method for use by classes or interfaces that inherit from this class |
+// generateRTTAddToMethod(x); |
+ } |
+ |
+ /** |
+ * Insert the function or method necessary to implement runtime type information |
+ * for the provided class. |
+ */ |
+ private void generateRuntimeTypeInfoMethods(DartMethodDefinition x) { |
+ // 1) create static type information lookup function |
+ generateRTTLookupMethod(x); |
+ |
+ // 3) create "addTo" method for use by classes or interfaces that inherit from this class |
+// generateRTTAddToMethod(x); |
+ } |
+ |
private void generateRTTLookupMethod(DartClass x) { |
ClassElement classElement = x.getSymbol(); |
boolean hasTypeParams = hasTypeParameters(classElement); |
zundel
2011/11/08 15:28:42
looks like you aren't using hasTypeParams() anymor
codefu
2011/11/14 19:33:40
For now, yes. I need to look into a generic rtt c
|
@@ -217,11 +268,17 @@ public class RuntimeTypeInjector { |
callArgs.add(program.getNullLiteral()); |
} |
- if (hasTypeParams) { |
- JsName typeArgs = scope.declareName("typeArgs"); |
- lookupFn.getParameters().add(new JsParameter(typeArgs)); |
- callArgs.add(typeArgs.makeRef()); |
- } |
+ JsName typeArgs = scope.declareName("typeArgs"); |
+ lookupFn.getParameters().add(new JsParameter(typeArgs)); |
+ callArgs.add(typeArgs.makeRef()); |
+ |
+ JsName returnType = scope.declareName("returnType"); |
+ lookupFn.getParameters().add(new JsParameter(returnType)); |
+ callArgs.add(returnType.makeRef()); |
+ |
+ JsName functionType = scope.declareName("functionType"); |
+ lookupFn.getParameters().add(new JsParameter(functionType)); |
+ callArgs.add(functionType.makeRef()); |
body.add(new JsReturn(invokeCreate)); |
@@ -373,6 +430,217 @@ public class RuntimeTypeInjector { |
globalBlock.getStatements().add(fnDecl.makeStmt()); |
} |
+//todo: was generateRTTGetToMethod, dumb |
+ private void generateRTTLookupMethod(DartMethodDefinition x) { |
+ MethodElement methodElement = x.getSymbol(); |
+ if (Elements.isTopLevel(methodElement)) { |
+ return; /* top level methods can't have type parameters */ |
+ } |
+ ClassElement classElement = (ClassElement)methodElement.getEnclosingElement(); |
+ |
+ JsProgram program = translationContext.getProgram(); |
+ |
+ // Create function looking up RTT parameters and return type for method x |
+ // return jtm86182b$A$Dart.$lookupRTT(null,Collection$Dart.$lookupRTT([RTT.getTypeArg(RTT.getTypeArgsFor(this, $cls('jtm86182b$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 = newInvocation( |
+ getRTTLookupMethodName(classElement)); |
+ |
+ JsArrayLiteral arr = new JsArrayLiteral(); |
+ for (VariableElement element : methodElement.getParameters()) { |
+ Type elementType = element.getType(); |
+ ClassElement cElement = null; |
+ switch(TypeKind.of(elementType)) { |
+ case VARIABLE: |
+ cElement = (ClassElement) ((TypeVariableElement)elementType.getElement()).getDeclaringElement(); |
+ break; |
+ default: |
+ cElement = (ClassElement) elementType.getElement(); |
+ break; |
+ } |
+ JsExpression elementExpr; |
+ switch (TypeKind.of(elementType)) { |
+ case INTERFACE: |
+ elementExpr = generateRTTLookup((ClassElement) elementType.getElement(), (InterfaceType) elementType, classElement); |
zundel
2011/11/08 15:28:42
this and other lines > 100chars
codefu
2011/11/14 19:33:40
Done.
|
+ break; |
+ |
+ case FUNCTION: |
+ case FUNCTION_ALIAS: |
+ // TODO(johnlenz): implement this |
+ //elementExpr = null; //newQualifiedNameRef("RTT.placeholderType"); |
+ return; // F'em |
+ case VARIABLE: |
+ elementExpr = buildTypeLookupExpression( |
+ elementType, classElement.getTypeParameters(), typeArgContextExpr ); |
+ break; |
+ default: |
+ //throw new AssertionError("unexpected type kind:" + elementType.getKind()); |
+ return; /* f'em, they don't get a lookup */ |
+ } |
+ arr.getExpressions().add(elementExpr); |
+ } |
+ Type returnType = methodElement.getReturnType(); |
+ JsExpression returnExpr; |
+ if( returnType.getElement() instanceof ClassElement ) { |
+ returnExpr = generateRTTLookup((ClassElement) returnType.getElement(), (InterfaceType) returnType, classElement); |
+ } else { |
+ switch( TypeKind.of(returnType) ) { |
+ case VOID: |
+ case NONE: |
+ returnExpr = program.getNullLiteral(); |
+ break; |
+ default: |
+ returnExpr = buildTypeLookupExpression( |
+ returnType, classElement.getTypeParameters(), typeArgContextExpr ); |
+ break; |
+ } |
+ } |
+ |
+ callLookup.getArguments().add(0, arr.getExpressions().isEmpty() ? program.getNullLiteral() : arr); |
+ callLookup.getArguments().add(1, returnExpr); |
+ callLookup.getArguments().add(2, program.getBooleanLiteral(true)); |
+ body.add(new JsReturn(callLookup)); |
+ |
+ // Finally, Add the function |
+ JsExpression fnDecl; |
+ if (methodElement.getEnclosingElement().getKind().equals(ElementKind.CLASS)) { |
+ //JsName name = new JsName(); |
+ JsNameRef prop = makeMethodJsReference(methodElement); |
+ fnDecl = assign(null, prop, lookupFn); |
+ } else { |
+ fnDecl = assign(null, getRTTLookupMethodName(classElement), lookupFn); |
+ } |
+ globalBlock.getStatements().add(fnDecl.makeStmt()); |
+ } |
+ |
+ 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 blah = AstUtil.nameref(null, new JsNameRef(element.getName()) + "$lookupRTT"); //nameref(null, element.getName(), "$lookupRTT"); |
+ JsNameRef asdf = newNameRef(qualifier, blah.toString()); |
+ |
+ // TODO(johnlenz): This should be the name node reference |
+ asdf.setSourceRef(element.getNode()); |
+ return asdf; |
+ } |
+ |
+ private void generateRTTLookupMethod(DartFunctionTypeAlias x) { |
+ FunctionAliasElementImplementation classElement = (FunctionAliasElementImplementation) x.getSymbol(); |
+ FunctionType funcType = classElement.getFunctionType(); |
+ boolean hasTypeParams = hasTypeParameters(classElement); |
+ |
+ // 1) create static type information construction function |
+ // function Foo$lookupOrCreateRTT(typeargs) { |
+ // return $createRTT(name, Foo$RTTimplements, typeargs) ; |
+ // } |
+ |
+ // 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.create"), getRTTClassId(classElement)); |
+ List<JsExpression> callArgs = invokeCreate.getArguments(); |
+ |
+ JsName typeArgs = scope.declareName("typeArgs"); |
+ JsExpression typeArgsExpr = new JsNameRef("typeArgs"); |
+ lookupFn.getParameters().add(new JsParameter(typeArgs)); |
+ |
+ // There is no implementing... just saying. |
+ callArgs.add(program.getNullLiteral()); |
+ |
+ JsArrayLiteral arr = new JsArrayLiteral(); |
+ for (DartParameter param : x.getParameters()) { |
+ if( param.getTypeNode() == null ) { |
+ return; //F'em |
+ } |
+ Type elementType = param.getTypeNode().getType(); |
+ ClassElement cElement; |
+ switch(TypeKind.of(elementType)) { |
+ case VARIABLE: |
+ cElement = (ClassElement) ((TypeVariableElement)elementType.getElement()).getDeclaringElement(); |
+ break; |
+ default: |
+ cElement = (ClassElement) elementType.getElement(); |
+ break; |
+ } |
+ JsExpression elementExpr; |
+ switch (TypeKind.of(elementType)) { |
+ case INTERFACE: |
+ elementExpr = generateRTTLookup((ClassElement) elementType.getElement(), (InterfaceType) elementType, classElement); |
+ break; |
+ |
+ case FUNCTION: |
+ case FUNCTION_ALIAS: |
+ // TODO(johnlenz): implement this |
+ //elementExpr = null; //newQualifiedNameRef("RTT.placeholderType"); |
+ return; // F'em |
+ case VARIABLE: |
+ elementExpr = buildTypeLookupExpression( |
+ elementType, classElement.getTypeParameters(), typeArgsExpr ); |
+ break; |
+ default: |
+ //throw new AssertionError("unexpected type kind:" + elementType.getKind()); |
+ return; /* f'em, they don't get a lookup */ |
+ } |
+ arr.getExpressions().add(elementExpr); |
+ } |
+ callArgs.add(arr.getExpressions().isEmpty() ? program.getNullLiteral() : arr); |
+ |
+ Type returnType = funcType.getReturnType(); |
+ JsExpression returnExpr; |
+ if( returnType.getElement() instanceof ClassElement ) { |
+ returnExpr = generateRTTLookup((ClassElement) returnType.getElement(), (InterfaceType) returnType, classElement); |
+ } else { |
+ switch( TypeKind.of(returnType) ) { |
+ case VOID: |
+ case NONE: |
+ returnExpr = program.getNullLiteral(); |
+ break; |
+ default: |
+ returnExpr = buildTypeLookupExpression( |
+ returnType, classElement.getTypeParameters(), typeArgsExpr ); |
+ break; |
+ } |
+ } |
+ callArgs.add(returnExpr); |
+ callArgs.add(program.getBooleanLiteral(true)); |
+ |
+ 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); |
@@ -385,7 +653,7 @@ public class RuntimeTypeInjector { |
return getRTTClassId(translationContext, classElement); |
} |
- private JsNameRef getRTTLookupMethodName(ClassElement classElement) { |
+ private JsNameRef getRTTLookupMethodName(Symbol classElement) { |
return nameref(null, translationContext.getNames().getName(classElement), "$lookupRTT"); |
} |
@@ -495,6 +763,22 @@ public class RuntimeTypeInjector { |
return invokeLookup; |
} |
+// private JsExpression generateRTTLookup( |
+// FunctionAliasType aliasType, ClassElement contextClassElement) { |
+// return generateRTTLookup(aliasType.getElement(), aliasType, contextClassElement); |
+// } |
+// |
+// private JsExpression generateRTTLookup( |
+// ClassElement classElement, FunctionAliasType aliasType, ClassElement contextClassElement) { |
+// JsInvocation invokeLookup = call(null, getRTTLookupMethodName(classElement)); |
+// if (hasTypeParameters(aliasType.getElement()) && !aliasType.hasDynamicTypeArgs()) { |
+// JsExpression typeArgs = generateTypeArgsArray(aliasType, contextClassElement); |
+// assert typeArgs != null; |
+// invokeLookup.getArguments().add(typeArgs); |
+// } |
+// return invokeLookup; |
+// } |
+ |
private JsExpression generateTypeArgsArray( |
InterfaceType instanceType, ClassElement contextClassElement) { |
JsExpression typeArgs; |
@@ -510,7 +794,12 @@ public class RuntimeTypeInjector { |
((FunctionType)contextElement.getType()).getTypeVariables(), |
buildFactoryTypeInfoReference()); |
} else { |
- typeArgs = buildTypeArgs(instanceType, null, null); |
+ if( contextClassElement instanceof FunctionAliasElementImplementation) { |
+ JsExpression blah = new JsNameRef("typeArgs"); |
+ typeArgs = buildTypeArgs(instanceType, contextClassElement.getTypeParameters(), blah); |
+ } else { |
+ typeArgs = buildTypeArgs(instanceType, null, null); |
+ } |
} |
} else { |
// Build type args in a class context: |
@@ -748,6 +1037,16 @@ 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(johnlenz): special case "is Object"? |
+ return generateRefiedInterfaceTypeComparison(lhs, aliasType, currentClass, src); |
+ } |
+ |
default: |
throw new IllegalStateException("unexpected"); |
} |