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

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

Issue 8845002: Function type checking: Part Deux (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Nits checked Created 9 years 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 b18d6040d9a793b20fd7d114de87b0dbce0e8318..58206bddc6f5488a9f4183fc32d192355d8d90d0 100644
--- a/compiler/java/com/google/dart/compiler/backend/js/RuntimeTypeInjector.java
+++ b/compiler/java/com/google/dart/compiler/backend/js/RuntimeTypeInjector.java
@@ -46,9 +46,12 @@ 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.backend.js.ast.JsArrayAccess;
import com.google.dart.compiler.backend.js.ast.JsArrayLiteral;
@@ -66,16 +69,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.EnclosingElement;
+import com.google.dart.compiler.resolver.FunctionAliasElementImplementation;
+import com.google.dart.compiler.resolver.LibraryElement;
+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;
@@ -96,11 +109,15 @@ public class RuntimeTypeInjector {
private CoreTypeProvider typeProvider;
private final TranslationContext translationContext;
private final Types types;
+ private final DartMangler mangler;
+ private final LibraryElement unitLibrary;
RuntimeTypeInjector(
TraversalContextProvider context,
CoreTypeProvider typeProvider,
- TranslationContext translationContext, boolean emitTypeChecks) {
+ TranslationContext translationContext,
+ boolean emitTypeChecks, DartMangler mangler,
+ LibraryElement unitLibrary) {
this.context = context;
this.translationContext = translationContext;
JsProgram program = translationContext.getProgram();
@@ -109,6 +126,8 @@ public class RuntimeTypeInjector {
this.builtInTypeChecks = makeBuiltinTypes(typeProvider);
this.typeProvider = typeProvider;
this.emitTypeChecks = emitTypeChecks;
+ this.mangler = mangler;
+ this.unitLibrary = unitLibrary;
types = Types.getInstance(typeProvider);
}
@@ -133,6 +152,27 @@ public class RuntimeTypeInjector {
}
}
+ /**
+ * Generate the code necessary to allow for runtime type checks of dart typedefs
+ */
+ void generateRuntimeTypeInfo(DartFunctionTypeAlias x) {
+ generateRTTLookupMethod(x);
+ }
+
+ /**
+ * Generate the code necessary to allow for runtime type checks of dart class methods
+ */
+ void generateRuntimeTypeInfo(DartMethodDefinition x) {
+ generateRTTLookupMethod(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);
@@ -351,6 +391,12 @@ public class RuntimeTypeInjector {
for (InterfaceType interfaceType : classElement.getInterfaces() ) {
ClassElement interfaceElement = interfaceType.getElement();
+ // Codefu: Random addition to keep language/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) {
+ continue;
+ }
JsInvocation callAddTo = call(null,
getRTTAddToMethodName(interfaceElement), targetType.makeRef());
if (hasTypeParameters(interfaceElement) && !interfaceType.hasDynamicTypeArgs()) {
@@ -372,6 +418,270 @@ public class RuntimeTypeInjector {
globalBlock.getStatements().add(fnDecl.makeStmt());
}
+ private void generateRTTLookupMethod(DartMethodDefinition x) {
+ generateRTTLookupMethod(x.getSymbol(), null);
+ }
+
+ private void generateRTTLookupMethod(DartFunctionExpression x, String overrideName) {
+ generateRTTLookupMethod(x.getSymbol(), overrideName);
+ }
+
+ private ClassElement getEnclosingClassElement(EnclosingElement enclosingElement) {
+ while(enclosingElement != null) {
+ if (enclosingElement.getKind().equals(ElementKind.CLASS)) {
+ return (ClassElement)enclosingElement;
+ }
+ enclosingElement = enclosingElement.getEnclosingElement();
+ }
+ return null;
+ }
+
+ /*
+ * This function will create a lookup function that indirectly calls RTT.createFunction with
+ * and array of parameter types and the return type as arguments. Example:
+ * Dart:
+ * typedef List<J> TestAliasType<K,J>(int x, K k);
+ * JS:
+ * <libraryname>$<TestAliasType>$Dart.$lookupRTT = function(typeArgs){
+ * return RTT.createFunction(
+ * [int$Dart.$lookupRTT(), RTT.getTypeArg(typeArgs, 0)],
+ * List$Dart.$lookupRTT([RTT.getTypeArg(typeArgs, 1)]));
+ * }
+ */
+ private void generateRTTLookupMethod(MethodElement methodElement, String overrideName) {
+ boolean hasTypeArguments = false;
+
+ if (ElementKind.of(methodElement).equals(ElementKind.CONSTRUCTOR)
+ || methodElement.getModifiers().isNative()) {
+ // No type lookups for constructors or natives
+ return;
+ }
+ ClassElement classElement = getEnclosingClassElement(methodElement.getEnclosingElement());
+ hasTypeArguments = classElement != null ? hasTypeParameters(classElement) : false;
+
+ JsProgram program = translationContext.getProgram();
+ JsExpression typeArgContextExpr = hasTypeArguments ? 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);
+
+ JsExpression returnExpr = generateRTTLookupForType(methodElement,
+ 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 lookup function to the global block.
+ JsExpression fnDecl;
+ if (overrideName == null) {
+ if (methodElement.getEnclosingElement().getKind().equals(ElementKind.CLASS)) {
+ JsNameRef classJsNameRef = getJsName(methodElement.getEnclosingElement()).makeRef();
+ String getterName = mangler.createGetterSyntax(methodElement, unitLibrary);
+ String methodName = methodElement.getName();
+ JsName getterJsName = globalScope.declareName(getterName, getterName, methodName);
+ String mangledMethodName = mangler.mangleNamedMethod(methodElement, unitLibrary)
+ + "_$lookupRTT";
+ JsNameRef methodToCall;
+ JsNameRef getterJsNameRef;
+ if (methodElement.getModifiers().isStatic()) {
+ getterJsNameRef = AstUtil.newNameRef(classJsNameRef, getterJsName);
+ methodToCall = AstUtil.newNameRef(classJsNameRef, mangledMethodName);
+ } else {
+ JsNameRef prototypeRef = AstUtil.newPrototypeNameRef(classJsNameRef);
+ getterJsNameRef = AstUtil.newNameRef(prototypeRef, getterJsName);
+ methodToCall = AstUtil.newNameRef(prototypeRef, mangledMethodName);
+ }
+ fnDecl = assign(null, methodToCall, lookupFn);
+ } else {
+ // Top level method
+ String mangledMethodName = mangler.mangleNamedMethod(methodElement, unitLibrary)
+ + "_$lookupRTT";
+ lookupFn.setName(scope.declareName(mangledMethodName));
+ fnDecl = lookupFn;
+ }
+ } else {
+ // Special care for hoisted functions.
+ lookupFn.setName(scope.declareName(overrideName));
+ fnDecl = lookupFn;
+ }
+ globalBlock.getStatements().add(fnDecl.makeStmt());
+ }
+
+ /*
+ * Create a direct lookup of types for the given element. Useful for in-line function types, as
+ * in the example:
+ * int foo( int bar(double x) );
+ * No lookup method exists for the type "int bar(double x)", hence the in-line creation of:
+ * RTT.createFunction([RTT Parameter Types],RTT ReturnType))
+ */
+ private JsExpression generateRTTCreate(VariableElement element, ClassElement classElement) {
+ boolean hasTypes = false;
+ FunctionType type = (FunctionType) element.getType();
+
+ if (ElementKind.of(element).equals(ElementKind.CONSTRUCTOR)
+ || element.getModifiers().isNative()) {
+ // No type lookups for constructors or natives
+ return AstUtil.newQualifiedNameRef("RTT.dynamicType");
+ }
+ hasTypes = classElement != null ? hasTypeParameters(classElement) : false;
+
+ JsProgram program = translationContext.getProgram();
+ JsExpression typeArgContextExpr = hasTypes ? buildTypeArgsReference(classElement) : null;
+ JsInvocation callLookup;
+ callLookup = newInvocation(newQualifiedNameRef("RTT.createFunction"));
+
+ JsArrayLiteral arr = generateTypeArrayFromTypes(type.getParameterTypes(), classElement,
+ typeArgContextExpr);
+ if (arr == null) {
+ return AstUtil.newQualifiedNameRef("RTT.dynamicType");
+ }
+
+ JsExpression returnExpr = generateRTTLookupForType(element, type.getReturnType(), classElement,
+ typeArgContextExpr);
+
+ callLookup.getArguments().add(arr.getExpressions().isEmpty() ? program.getNullLiteral() : arr);
+ callLookup.getArguments().add(returnExpr);
+ return callLookup;
+ }
+
+ private JsArrayLiteral generateTypeArrayFromTypes(List<? extends Type> parameterTypes,
+ ClassElement classElement, JsExpression typeArgContextExpr) {
+ JsArrayLiteral jsTypeArray = new JsArrayLiteral();
+ for (Type param : parameterTypes) {
+ JsExpression elementExpr;
+ elementExpr = generateRTTLookupForType(param.getElement(), param, classElement,
+ typeArgContextExpr);
+ if (elementExpr == null) {
+ return null;
+ }
+ jsTypeArray.getExpressions().add(elementExpr);
+ }
+ return jsTypeArray;
+ }
+
+ 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.newQualifiedNameRef("RTT.dynamicType");
+ } else {
+ elementExpr = generateRTTLookupForType(param.getSymbol(), param.getTypeNode().getType(),
+ classElement, typeArgContextExpr);
+ }
+ 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, element.getType(),
+ classElement, typeArgContextExpr);
+ jsTypeArray.getExpressions().add(rttTypeExpression);
+ }
+ return jsTypeArray;
+ }
+
+ private JsExpression generateRTTLookupForType(Element element, 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:
+ elementExpr = generateRTTCreate((VariableElement) element, classElement);
+ break;
+ case FUNCTION_ALIAS:
+ elementExpr = buildTypeLookupExpression(elementType,
+ classElement != null ? classElement.getTypeParameters() : null, typeArgContextExpr);
+ break;
+ case DYNAMIC:
+ elementExpr = AstUtil.newQualifiedNameRef("RTT.dynamicType");
+ break;
+ case VOID:
+ case NONE:
+ elementExpr = translationContext.getProgram().getNullLiteral();
+ break;
+ default:
+ elementExpr = buildTypeLookupExpression(elementType, classElement.getTypeParameters(),
+ typeArgContextExpr);
+ break;
+ }
+ return elementExpr;
+ }
+
+ private JsName getJsName(Symbol symbol) {
+ return translationContext.getNames().getName(symbol);
+ }
+
+ /*
+ * This function will create a lookup function that indirectly calls RTT.createFunction with
+ * and array of parameter types and the return type as arguments. Example:
+ * Dart:
+ * typedef List<K> TestAliasType<K>(int x, K k);
+ * JS:
+ * <libraryname>$<TestAliasType>$Dart.$lookupRTT = function(typeArgs){
+ * return RTT.createFunction(
+ * [int$Dart.$lookupRTT(), RTT.getTypeArg(typeArgs, 0)],
+ * List$Dart.$lookupRTT([RTT.getTypeArg(typeArgs, 0)]));
+ * }
+ */
+ private void generateRTTLookupMethod(DartFunctionTypeAlias x) {
+ 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);
+ callArgs.add(arr.getExpressions().isEmpty() ? program.getNullLiteral() : arr);
+
+ JsExpression returnExpr = generateRTTLookupForType(funcType.getElement(),
+ funcType.getReturnType(), classElement, typeArgsExpr);
+ callArgs.add(returnExpr);
+
+ body.add(new JsReturn(invokeCreate));
+
+ // Finally, Add the function to the global block of statements.
+ 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);
@@ -509,7 +819,13 @@ public class RuntimeTypeInjector {
((FunctionType)contextElement.getType()).getTypeVariables(),
buildFactoryTypeInfoReference());
} else {
- typeArgs = buildTypeArgs(instanceType, null, null);
+ if( ElementKind.of(contextClassElement) == ElementKind.FUNCTION_TYPE_ALIAS) {
+ // Special case for FunctionAlias as they can have generic types.
+ typeArgs = buildTypeArgs(instanceType, contextClassElement.getTypeParameters(),
+ new JsNameRef("typeArgs"));
+ } else {
+ typeArgs = buildTypeArgs(instanceType, null, null);
+ }
}
} else {
// Build type args in a class context:
@@ -577,6 +893,7 @@ public class RuntimeTypeInjector {
Type type, List<? extends Type> list, JsExpression contextTypeArgs) {
switch (TypeKind.of(type)) {
case INTERFACE:
+ case FUNCTION_ALIAS:
InterfaceType interfaceType = (InterfaceType) type;
JsInvocation callLookup = call(null,
getRTTLookupMethodName(interfaceType.getElement()));
@@ -589,9 +906,18 @@ public class RuntimeTypeInjector {
}
return callLookup;
- case FUNCTION_ALIAS:
- // TODO(johnlenz): implement this
- return newQualifiedNameRef("RTT.placeholderType");
+ case FUNCTION:
+ FunctionType functionType = (FunctionType) type;
+ JsInvocation functionTypeCallLookup = call(null,
+ getRTTLookupMethodName(functionType.getElement()));
+ if (hasTypeParameters(functionType.getElement())) {
+ JsArrayLiteral typeArgs = new JsArrayLiteral();
+ for (Type arg : functionType.getTypeVariables()) {
+ typeArgs.getExpressions().add(buildTypeLookupExpression(arg, list, contextTypeArgs));
+ }
+ functionTypeCallLookup.getArguments().add(typeArgs);
+ }
+ return functionTypeCallLookup;
case VARIABLE:
TypeVariable var = (TypeVariable)type;
@@ -747,6 +1073,9 @@ public class RuntimeTypeInjector {
case DYNAMIC:
JsProgram program = translationContext.getProgram();
return program.getTrueLiteral();
+ case FUNCTION_ALIAS:
+ FunctionAliasType aliasType = (FunctionAliasType) type;
+ return generateRefiedInterfaceTypeComparison(lhs, aliasType, currentClass, src);
default:
throw new IllegalStateException("unexpected");
}

Powered by Google App Engine
This is Rietveld 408576698