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

Unified Diff: compiler/java/com/google/dart/compiler/backend/js/GenerateJavascriptAST.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/GenerateJavascriptAST.java
diff --git a/compiler/java/com/google/dart/compiler/backend/js/GenerateJavascriptAST.java b/compiler/java/com/google/dart/compiler/backend/js/GenerateJavascriptAST.java
index b9971760c053b235d6fc61454a0f135618170fe6..459509401bb548d504d0d77fabdff200aa014672 100644
--- a/compiler/java/com/google/dart/compiler/backend/js/GenerateJavascriptAST.java
+++ b/compiler/java/com/google/dart/compiler/backend/js/GenerateJavascriptAST.java
@@ -148,6 +148,7 @@ import com.google.dart.compiler.resolver.MethodElement;
import com.google.dart.compiler.resolver.SuperElement;
import com.google.dart.compiler.resolver.VariableElement;
import com.google.dart.compiler.type.InterfaceType;
+import com.google.dart.compiler.type.FunctionAliasType;
import com.google.dart.compiler.type.Type;
import com.google.dart.compiler.type.TypeKind;
import com.google.dart.compiler.type.Types;
@@ -178,15 +179,34 @@ public class GenerateJavascriptAST {
private final CoreTypeProvider typeProvider;
private final boolean generateClosureCompatibleCode;
+ static class FunctionAliasDiscover extends DartNodeTraverser<Void> {
+ boolean aliasFound = false;
+
+ @Override
+ public Void visitTypeNode(DartTypeNode node) {
+ if (node.getType() instanceof FunctionAliasType) {
+ aliasFound = true;
+ return null;
+ }
+ return visitNode(node);
+ }
+ }
zundel 2011/11/16 22:17:15 style: add n/l between functions/class definitions
+ static boolean isFunctionAlias(DartExpression expr) {
+ FunctionAliasDiscover visitForAlias = new FunctionAliasDiscover();
+ expr.accept(visitForAlias);
+ return visitForAlias.aliasFound;
+ }
+
/**
* Generates the Javascript AST using the names created in {@link GenerateNamesAndScopes}.
*/
- static class GenerateJavascriptVisitor
+ class GenerateJavascriptVisitor
implements DartPlainVisitor<JsNode>, TraversalContextProvider {
- private final boolean generateClosureCompatibleCode;
+ private boolean isInBinaryExpression = false;
+ private Token binaryExpressionOperator = Token.NON_TOKEN;
- private static boolean isSuperCall(Symbol symbol) {
+ private boolean isSuperCall(Symbol symbol) {
return ElementKind.of(symbol).equals(ElementKind.SUPER);
}
@@ -194,7 +214,7 @@ public class GenerateJavascriptAST {
* Returns <code>true</code> for members that are static or should be treated
* as if the user had declared them as static.
*/
- private static boolean isDeclaredAsStaticOrImplicitlyStatic(Element element) {
+ private boolean isDeclaredAsStaticOrImplicitlyStatic(Element element) {
Modifiers modifiers = element.getModifiers();
if (modifiers.isStatic()) {
// Member was actually declared static
@@ -247,11 +267,8 @@ public class GenerateJavascriptAST {
private final RuntimeTypeInjector rtt;
private final TranslationContext translationContext;
- private final OptimizationStrategy optStrategy;
- private final DartCompilerContext context;
private final LibraryElement unitLibrary;
private final DartMangler mangler;
- private final CoreTypeProvider typeProvider;
private final Types typeUtils;
private final Deque<JsName> catchVarStack = new ArrayDeque<JsName>();
@@ -260,13 +277,9 @@ public class GenerateJavascriptAST {
TranslationContext translationContext,
OptimizationStrategy optStrategy, CoreTypeProvider typeProvider,
boolean generateClosureCompatibleCode) {
- this.context = context;
this.translationContext = translationContext;
- this.optStrategy = optStrategy;
- this.typeProvider = typeProvider;
this.typeUtils = Types.getInstance(typeProvider);
this.unitLibrary = unit.getLibrary().getElement();
- this.generateClosureCompatibleCode = generateClosureCompatibleCode;
// Cache the mangler in a field since it is used frequently
mangler = translationContext.getMangler();
@@ -590,37 +603,82 @@ public class GenerateJavascriptAST {
}
/**
- * Creates a $getter for a method of a class, returning $method as a closure
- * bound to the current instance if it is an instance method.
+ * Creates a $getter for a method of a class, returning $method as a closure bound to the
+ * current instance if it is an instance method.
*/
private void generateMethodGetter(MethodElement methodElement) {
+ generateMethodGetter(methodElement, null);
+ }
+
+ private void generateMethodGetter(MethodElement methodElement, String NameOverride) {
zundel 2011/11/16 22:17:15 style: argument name should start with lower case
// Generate a getter for method binding to a variable
JsNameRef classJsNameRef = getJsName(methodElement.getEnclosingElement()).makeRef();
- String getterName = mangler.createGetterSyntax(methodElement, unitLibrary);
+ String getterName = NameOverride == null ? mangler.createGetterSyntax(methodElement,
+ unitLibrary) : NameOverride + "$getter";
String methodName = methodElement.getName();
JsName getterJsName = globalScope.declareName(getterName, getterName, methodName);
getterJsName.setObfuscatable(false);
- String mangledMethodName = mangler.mangleNamedMethod(methodElement, unitLibrary);
+ String mangledMethodName = NameOverride == null ? mangler.mangleNamedMethod(methodElement,
+ unitLibrary) : mangler.mangleNamedMethod(NameOverride, unitLibrary);
JsFunction func = new JsFunction(globalScope);
+ JsScope scope = func.getScope();
JsNameRef getterJsNameRef;
JsExpression methodToCall;
+
+ JsBlock body = new JsBlock();
+ List<JsStatement> stmts = body.getStatements();
+
+ JsExpression bindMethodCall;
+ JsName seen = scope.declareFreshName("ret");
+
if (methodElement.getModifiers().isStatic()) {
- // function() { return <class><member>$member; }
+ // function() { var ret = $bind(<class>.prototype.<member>$member, this);
+ // ret = $bind(<class>.prototype.<member>$lookupRTT, this); return ret; }
zundel 2011/11/16 22:17:15 The commented code doesn't make any sense to me. I
codefu 2011/11/16 22:39:55 Bad comment. The second part should read "ret.look
getterJsNameRef = AstUtil.newNameRef(classJsNameRef, getterJsName);
methodToCall = AstUtil.newNameRef(classJsNameRef, mangledMethodName);
- func.setBody(AstUtil.newBlock(new JsReturn(methodToCall)));
+ stmts.add(AstUtil.newVar(null, seen, methodToCall));
+
+ JsName rttLatch = scope.declareFreshName("ret.lookupRTT");
+ String mangledLookupName = mangler.mangleLookupMethod(methodElement, unitLibrary);
+ methodToCall = AstUtil.newNameRef(classJsNameRef, mangledLookupName);
+ stmts.add(AstUtil.newAssignment(rttLatch.makeRef(), methodToCall).makeStmt());
} else {
- // function() { return $bind(<class>.prototype.<member>$member, this); }
+ // function() { var ret = $bind(<class>.prototype.<member>$member, this);
+ // ret = $bind(<class>.prototype.<member>$lookupRTT, this); return ret; }
zundel 2011/11/16 22:17:15 Same comment as above.
codefu 2011/11/16 22:39:55 Done.
JsNameRef prototypeRef = AstUtil.newPrototypeNameRef(classJsNameRef);
getterJsNameRef = AstUtil.newNameRef(prototypeRef, getterJsName);
- methodToCall = AstUtil.newNameRef(prototypeRef, mangledMethodName);
- JsExpression bindMethodCall = AstUtil.newInvocation(
- new JsNameRef("$bind"), methodToCall, new JsThisRef());
- func.setBody(AstUtil.newBlock(new JsReturn(bindMethodCall)));
+ if (NameOverride == null) {
+ methodToCall = AstUtil.newNameRef(prototypeRef, mangledMethodName);
+ bindMethodCall = AstUtil.newInvocation(new JsNameRef("$bind"), methodToCall,
+ new JsThisRef());
+ } else {
+ bindMethodCall = AstUtil.newNameRef(null, NameOverride + "$named");
+ }
+ stmts.add(AstUtil.newVar(null, seen, bindMethodCall));
+
+ String mangledLookupName;
+ if (NameOverride == null) {
+ mangledLookupName = mangler.mangleLookupMethod(methodElement, unitLibrary);
+ methodToCall = AstUtil.newNameRef(prototypeRef, mangledLookupName);
+ bindMethodCall = AstUtil.newInvocation(new JsNameRef("$bind"), methodToCall,
zundel 2011/11/16 22:17:15 IMHO, re-using the variable bindMethodCall is conf
+ new JsThisRef());
+ } else {
+ bindMethodCall = AstUtil.newNameRef(null, NameOverride + "$lookupRTT");
+ }
+ JsName rttLatch = scope.declareFreshName("ret.lookupRTT");
+ stmts.add(AstUtil.newAssignment(rttLatch.makeRef(), bindMethodCall).makeStmt());
}
- func.setName(getterJsNameRef.getName());
+ stmts.add(new JsReturn(seen.makeRef()));
+ func.setBody(body);
+
func.setSourceRef(methodElement.getNode());
- JsBinaryOperation asg = AstUtil.newAssignment(getterJsNameRef, func);
+ JsBinaryOperation asg;
+ if (NameOverride == null) {
+ asg = AstUtil.newAssignment(getterJsNameRef, func);
+ } else {
+ getterJsNameRef = AstUtil.newNameRef(null, NameOverride + "$getter");
+ asg = AstUtil.newAssignment(getterJsNameRef, func);
+ }
asg.setSourceRef(methodElement.getNode());
globalBlock.getStatements().add(asg.makeStmt());
}
@@ -1347,6 +1405,19 @@ public class GenerateJavascriptAST {
asg = assign(namedProp, tramp);
globalBlock.getStatements().add(asg.makeStmt());
+
+ // Generate a lookup method after finally writing function / named tramp
+ assert currentScopeInfo == null : "Nested methods should be impossible";
+ inFactoryOrStaticContext = element.getModifiers().isFactory()
+ || element.getModifiers().isStatic();
+ DartMethodDefinition x = (DartMethodDefinition) element.getNode();
+ currentScopeInfo = ScopeRootInfo.makeScopeInfo(x, !shouldGenerateDeveloperModeChecks());
+ rtt.generateRuntimeTypeInfo(x);
+
+ assert currentScopeInfo != null;
+ inFactoryOrStaticContext = false;
+ currentScopeInfo = null;
+
}
} else {
globalBlock.getStatements().add(func.makeStmt());
@@ -2211,59 +2282,69 @@ public class GenerateJavascriptAST {
public JsNode visitBinaryExpression(DartBinaryExpression x) {
assert x == x.getNormalizedNode();
- Token operator = x.getOperator();
+ boolean oldBinaryExpression = isInBinaryExpression;
+ Token oldBinaryExpressionOp = binaryExpressionOperator;
+ isInBinaryExpression = true;
+ binaryExpressionOperator = x.getOperator();
- if (operator == Token.IS) {
- return generateInstanceOfComparison(x);
- }
+ try {
+ Token operator = x.getOperator();
- DartExpression arg1 = x.getArg1();
- DartExpression arg2 = x.getArg2();
- JsExpression rhs = (JsExpression) generate(arg2);
- if (operator == Token.ASSIGN) {
- return arg1.accept(new Assignment(x, rhs, arg2.getType()));
- }
+ if (operator == Token.IS) {
+ return generateInstanceOfComparison(x);
+ }
- assert !operator.isUserDefinableOperator() || !operator.isAssignmentOperator() : x;
+ DartExpression arg1 = x.getArg1();
+ DartExpression arg2 = x.getArg2();
+ JsExpression rhs = (JsExpression) generate(arg2);
+ if (operator == Token.ASSIGN) {
+ return arg1.accept(new Assignment(x, rhs, arg2.getType()));
+ }
- // We can skip shims for non-user-definable operators (NE is a special case because it's not
- // user-definable, but still has to be shimmed).
- boolean skipShim = (!operator.isUserDefinableOperator() && (operator != Token.NE));
- if (!skipShim) {
- // For user-defined operators, the optimization strategy can choose to skip the shim.
- skipShim = optStrategy.canSkipOperatorShim(x);
- }
+ assert !operator.isUserDefinableOperator() || !operator.isAssignmentOperator() : x;
- JsExpression lhs = (JsExpression) generate(arg1);
- Token op = x.getOperator();
+ // We can skip shims for non-user-definable operators (NE is a special case because it's not
+ // user-definable, but still has to be shimmed).
+ boolean skipShim = (!operator.isUserDefinableOperator() && (operator != Token.NE));
+ if (!skipShim) {
+ // For user-defined operators, the optimization strategy can choose to skip the shim.
+ skipShim = optStrategy.canSkipOperatorShim(x);
+ }
- lhs = rtt.addTypeCheck(getCurrentClass(), lhs, getRequiredType(op), arg1.getType(), arg1);
- rhs = rtt.addTypeCheck(getCurrentClass(), rhs, getRequiredType(op), arg2.getType(), arg2);
-
- if (skipShim) {
- if (op.isEqualityOperator()) {
- op = mapToStrictEquals(op);
- // TODO (fabiomfv) - This optimization targets a v8 perf issue. V8 double equals
- // comparison to undefined is up to 4 times slower than == null. It seems that it was
- // fixed on v8 3.5. once we move to 3.5 and the fix confirmed, this should be revisited.
- if (arg2 instanceof DartNullLiteral) {
- op = mapToNonStrictEquals(op);
- rhs = nulle();
- }
- if (arg1 instanceof DartNullLiteral) {
- JsExpression tmp = lhs;
- lhs = rhs;
- rhs = tmp;
- op = mapToNonStrictEquals(op);
- rhs = nulle();
+ JsExpression lhs = (JsExpression) generate(arg1);
+ Token op = x.getOperator();
+
+ lhs = rtt.addTypeCheck(getCurrentClass(), lhs, getRequiredType(op), arg1.getType(), arg1);
+ rhs = rtt.addTypeCheck(getCurrentClass(), rhs, getRequiredType(op), arg2.getType(), arg2);
+
+ if (skipShim) {
+ if (op.isEqualityOperator()) {
+ op = mapToStrictEquals(op);
+ // TODO (fabiomfv) - This optimization targets a v8 perf issue. V8 double equals
+ // comparison to undefined is up to 4 times slower than == null. It seems that it was
+ // fixed on v8 3.5. once we move to 3.5 and the fix confirmed, this should be revisited.
+ if (arg2 instanceof DartNullLiteral) {
+ op = mapToNonStrictEquals(op);
+ rhs = nulle();
+ }
+ if (arg1 instanceof DartNullLiteral) {
+ JsExpression tmp = lhs;
+ lhs = rhs;
+ rhs = tmp;
+ op = mapToNonStrictEquals(op);
+ rhs = nulle();
+ }
}
+ JsExpression binOp = new JsBinaryOperation(mapBinaryOp(op), lhs, rhs);
+ binOp.setSourceRef(x);
+ return binOp;
+ } else {
+ JsNameRef ref = new JsNameRef(mangler.createOperatorSyntax(operator));
+ return AstUtil.newInvocation(ref, lhs, rhs).setSourceRef(x);
}
- JsExpression binOp = new JsBinaryOperation(mapBinaryOp(op), lhs, rhs);
- binOp.setSourceRef(x);
- return binOp;
- } else {
- JsNameRef ref = new JsNameRef(mangler.createOperatorSyntax(operator));
- return AstUtil.newInvocation(ref, lhs, rhs).setSourceRef(x);
+ } finally {
+ isInBinaryExpression = oldBinaryExpression;
+ binaryExpressionOperator = oldBinaryExpressionOp;
}
}
@@ -2958,6 +3039,11 @@ public class GenerateJavascriptAST {
ScopeRootInfo.ClosureInfo info = currentScopeInfo.getClosureInfo(x.getFunction());
List<DartScope> list = info.getSortedReferencedScopeList();
+// TODO(codefu): Properlly support hoisted function's types TAG:codefuHoistedFunctionTypes
+// String rootName = hoistedName.getIdent();
+// String getterName = mangler.createGetterSyntax(rootName, unitLibrary);
+// String lookupName = mangler.mangleLookupMethod(rootName, unitLibrary);
+
// TODO(jgw): See johnlenz' comment above about re-evaluation. This guard can go away once
// that problem is fixed.
if (!fnWasPreviouslyHoisted) {
@@ -2971,15 +3057,29 @@ public class GenerateJavascriptAST {
hoistedName = globalScope.declareName(mangled);
tramp.setName(hoistedName);
globalBlock.getStatements().add(tramp.makeStmt());
+
+// TODO(codefu): TAG:codefuHoistedFunctionTypes
+// if(x.getParent() != null && !(x.getParent() instanceof DartFunctionObjectInvocation)) {
+// rtt.generateRuntimeTypeInfo(x, rootName);
+// generateMethodGetter(x.getSymbol(), rootName);
+// }
}
// 5) Bind the necessary scope references and possibly "this".
JsExpression replacement;
+// TODO(codefu): TAG:codefuHoistedFunctionTypes
+// boolean callGetter = false;
if (list.isEmpty() && inFactoryOrStaticContext) {
// Simply replace the function
- replacement = new JsNameRef(hoistedName);
+// TODO(codefu): TAG:codefuHoistedFunctionTypes
+// if(x.getParent() != null && !(x.getParent() instanceof DartFunctionObjectInvocation)) {
+// replacement = new JsNameRef(getterName);
+// callGetter = true;
+// } else {
+ replacement = new JsNameRef(hoistedName);
+// }
} else {
// Replace "function (){}" with "bind(hoistedName, this, scope1, scope2, ...)"
@@ -3061,6 +3161,8 @@ public class GenerateJavascriptAST {
JsNameRef scopeF = makeScopeAliasNameRef(scope, x.getSymbol());
JsExpression assig = AstUtil.newAssignment(scopeF, replacement);
replacement = new JsBinaryOperation(JsBinaryOperator.COMMA, init, assig);
+// TODO(codefu): TAG:codefuHoistedFunctionTypes
+// callGetter = false;
// TODO(floitsch): we need to clear the scope object.
}
}
@@ -3076,10 +3178,20 @@ public class GenerateJavascriptAST {
} else {
// The parent expects an expression, but handles Var statements separately.
assert !hoistedName.equals(fnDeclaredName);
+// TODO(codefu): TAG:codefuHoistedFunctionTypes
+// if (callGetter) {
+// // codefu: change to invocation of getter.
+// replacement = AstUtil.newInvocation(replacement);
+// }
JsVars vars = AstUtil.newVar(x.getName(), fnDeclaredName, replacement);
return vars.setSourceRef(x);
}
} else {
+// TODO(codefu): TAG:codefuHoistedFunctionTypes
+// if (callGetter) {
+// // codefu: change to invocation of getter.
+// replacement = AstUtil.newInvocation(replacement);
+// }
return replacement.setSourceRef(x);
}
}
@@ -3532,6 +3644,15 @@ public class GenerateJavascriptAST {
@Override
public JsNode visitFunctionTypeAlias(DartFunctionTypeAlias node) {
+ // TODO(codefu): Optimize away if we're never the rhs of a "is" check.
+ ClassElement classElement = node.getSymbol();
+ JsName classJsName = getJsName(classElement);
+ JsFunction jsClass = new JsFunction(globalScope, classJsName).setSourceRef(node);
+ jsClass.setIsConstructor(false);
+ jsClass.setBody(new JsBlock());
+ globalBlock.getStatements().add(jsClass.makeStmt());
+
+ rtt.generateRuntimeTypeInfo(node);
return null;
}
@@ -3616,22 +3737,27 @@ public class GenerateJavascriptAST {
private JsExpression generateMethodBoundToVariable(DartIdentifier methodNode,
MethodElement methodElement, DartNode qualifier) {
JsExpression boundMethod;
- String mangledName = mangler.mangleNamedMethod(methodElement, unitLibrary);
+
+ String mangledName;
+ boolean isDirectReference = methodNode.getTargetSymbol() == methodElement;
+ mangledName = mangler.createGetterSyntax(methodElement, unitLibrary);
boolean isSuperCall = (qualifier != null) && isSuperCall(qualifier.getSymbol());
if (isSuperCall) {
boundMethod = generateSuperFieldAccess(qualifier,
- mangler.createGetterSyntax(methodElement.getName(), unitLibrary));
+ mangler.createGetterSyntax(methodElement, unitLibrary));
} else if (Elements.isTopLevel(methodElement)) {
+ mangledName = mangler.mangleNamedMethod(methodElement, unitLibrary);
boundMethod = AstUtil.newNameRef(null, mangledName);
+ // todo: can we lhs "is" top level methods?
} else if (methodElement.isStatic()) {
if (qualifier == null) {
qualifier = methodElement.getEnclosingElement().getNode();
assert (qualifier instanceof DartClass);
boundMethod = AstUtil.newNameRef(getJsName(qualifier.getSymbol()).makeRef(), mangledName);
} else {
- assert (qualifier instanceof DartIdentifier);
boundMethod = AstUtil.newNameRef((JsExpression) generate(qualifier), mangledName);
}
+ boundMethod = AstUtil.newInvocation(boundMethod);
} else {
// Should be an invocation on an instance
if (qualifier == null) {
@@ -3641,8 +3767,49 @@ public class GenerateJavascriptAST {
ClassElement classElement = (ClassElement) methodElement.getEnclosingElement();
String className = mangler.mangleClassName(classElement);
JsNameRef prototypeRef = AstUtil.newPrototypeNameRef(new JsNameRef(className));
- JsExpression methodToCall = AstUtil.newNameRef(prototypeRef, mangledName);
- boundMethod = AstUtil.newInvocation(new JsNameRef("$bind"), methodToCall, methodQualifier);
+ JsExpression methodToCall;
+ if (isDirectReference) {
+ methodToCall = AstUtil.newNameRef(methodQualifier, mangledName);
+ boundMethod = AstUtil.newInvocation(methodToCall);
+ } else {
+ methodToCall = AstUtil.newNameRef(prototypeRef, mangledName);
+ boundMethod = AstUtil.newInvocation(new JsNameRef("$bind"), methodToCall, methodQualifier);
+ }
+ }
+ boundMethod.setSourceRef(methodNode);
+ return boundMethod;
+ }
+
+ private JsExpression generateMethodLookup(DartIdentifier methodNode,
+ MethodElement methodElement, DartNode qualifier) {
+ JsExpression boundMethod;
+
+ String mangledName;
+ mangledName = mangler.mangleLookupMethod(methodElement, unitLibrary);
+ boolean isSuperCall = (qualifier != null) && isSuperCall(qualifier.getSymbol());
+ if (isSuperCall) {
+ boundMethod = generateSuperFieldAccess(qualifier,
+ mangler.mangleLookupMethod(methodElement, unitLibrary));
+ } else if (Elements.isTopLevel(methodElement)) {
+ boundMethod = AstUtil.newNameRef(null, mangledName);
+ // todo: can we lhs "is" top level methods?
+ } else if (methodElement.isStatic()) {
+ if (qualifier == null) {
+ qualifier = methodElement.getEnclosingElement().getNode();
+ assert (qualifier instanceof DartClass);
+ boundMethod = AstUtil.newNameRef(getJsName(qualifier.getSymbol()).makeRef(), mangledName);
+ } else {
+ boundMethod = AstUtil.newNameRef((JsExpression) generate(qualifier), mangledName);
+ }
+ boundMethod = AstUtil.newInvocation(boundMethod);
+ } else {
+ // Should be an invocation on an instance
+ if (qualifier == null) {
+ qualifier = DartThisExpression.get();
+ }
+ JsExpression methodQualifier = (JsExpression) generate(qualifier);
+ JsExpression methodToCall = AstUtil.newNameRef(methodQualifier, mangledName);
+ boundMethod = AstUtil.newInvocation(methodToCall);
}
boundMethod.setSourceRef(methodNode);
return boundMethod;
@@ -3652,6 +3819,13 @@ public class GenerateJavascriptAST {
return referenceName(element, node);
}
+ private DartBinaryExpression findBinaryExpression(DartNode node) {
+ while (node != null && !(node instanceof DartBinaryExpression)) {
+ node = node.getParent();
+ }
+ return (DartBinaryExpression) node;
+ }
+
private JsExpression generateLoad(DartNode qualifier, DartIdentifier node, Element element) {
boolean accessThroughShim = true;
if (element != null) {
@@ -3666,6 +3840,15 @@ public class GenerateJavascriptAST {
case FUNCTION_OBJECT:
// TODO(5089961): we should not generate code for class expressions.
case CLASS:
+ if (isInBinaryExpression && binaryExpressionOperator == Token.IS) {
+ DartBinaryExpression binaryExpr = findBinaryExpression(node);
+ if (binaryExpr == node.getParent() && isFunctionAlias(binaryExpr.getArg2())) {
+ JsExpression lookup = generateLoadTemporary(element, node);
+ JsNameRef methodToCall = AstUtil.newNameRef(lookup, "lookupRTT");
+ JsInvocation bindMethodCall = AstUtil.newInvocation(methodToCall);
+ return bindMethodCall;
+ }
+ }
return generateLoadTemporary(element, node);
case NONE:
@@ -3673,6 +3856,13 @@ public class GenerateJavascriptAST {
return generateSuperFieldAccess(qualifier,
mangler.createGetterSyntax(node.getTargetName(), unitLibrary));
}
+
+ // Unresolved element (var x = new Blah<int>()) used in a DartBinaryExpression - need to
+ // find the rhs symbol to see if its a FunctionAliasType.
+ if (isInBinaryExpression && isFunctionAlias(findBinaryExpression(node).getArg2())) {
+ return generateUnresolvedAccess(qualifier,
+ mangler.mangleLookupMethod(node.getTargetName(), unitLibrary));
+ }
return generateUnresolvedAccess(qualifier,
mangler.createGetterSyntax(node.getTargetName(), unitLibrary));
@@ -3693,6 +3883,9 @@ public class GenerateJavascriptAST {
case METHOD: {
MethodElement method = (MethodElement) element;
+ if (isInBinaryExpression && isFunctionAlias(findBinaryExpression(node).getArg2())) {
+ return generateMethodLookup(node, method, qualifier);
+ }
return generateMethodBoundToVariable(node, method, qualifier);
}

Powered by Google App Engine
This is Rietveld 408576698