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

Unified Diff: compiler/java/com/google/dart/compiler/backend/js/RuntimeTypeInjector.java

Issue 8566022: Function type checking (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 9 years, 1 month 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: 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");
}

Powered by Google App Engine
This is Rietveld 408576698