Chromium Code Reviews| 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"); |
| } |