Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for instanceof pattern matching feature #9917

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
70 changes: 67 additions & 3 deletions dev/core/src/com/google/gwt/dev/jjs/impl/GwtAstBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
import com.google.gwt.dev.jjs.ast.JUnaryOperator;
import com.google.gwt.dev.jjs.ast.JUnsafeTypeCoercion;
import com.google.gwt.dev.jjs.ast.JVariable;
import com.google.gwt.dev.jjs.ast.JVariableRef;
import com.google.gwt.dev.jjs.ast.JWhileStatement;
import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
import com.google.gwt.dev.jjs.ast.js.JsniClassLiteral;
Expand Down Expand Up @@ -1095,9 +1096,71 @@ public void endVisit(Initializer x, MethodScope scope) {
public void endVisit(InstanceOfExpression x, BlockScope scope) {
try {
SourceInfo info = makeSourceInfo(x);
JExpression expr = pop(x.expression);
JExpression expr;
JDeclarationStatement jDeclarationStatement = null;
if (x.pattern != null) {
jDeclarationStatement = (JDeclarationStatement) pop();
}
expr = pop(x.expression);
JReferenceType testType = (JReferenceType) typeMap.get(x.type.resolvedType);
push(new JInstanceOf(info, testType, expr));

if (jDeclarationStatement == null) {
push(new JInstanceOf(info, testType, expr));
} else {
// If <expr> is of type X, then
//
// rewrite (<expr> instanceof Foo foo)
// to
// Foo foo;
// X $instanceof_1;
// (($instanceof_1 = <expr>) instanceof Foo && null != (foo = (Foo) $instanceof_1))
//
// to avoid side effects from evaluating the original expression twice

// Foo foo;
String patternDeclarationName = jDeclarationStatement.getVariableRef().getTarget()
.getName();
if (!curMethod.instanceOfDeclarations.containsKey(patternDeclarationName)) {
curMethod.body.getBlock().addStmt(0, jDeclarationStatement);
curMethod.instanceOfDeclarations.put(patternDeclarationName, jDeclarationStatement);
}

// X $instanceof_1;
JType expressionType = typeMap.get(x.expression.resolvedType);
JLocal local =
createLocal(info, "$instanceOfExpr", expressionType);
JDeclarationStatement expressionDeclaration =
makeDeclaration(info, local, null);
curMethod.body.getBlock().addStmt(0, expressionDeclaration);
curMethod.instanceOfDeclarations.put(local.getName(), expressionDeclaration);

// (Foo) $instanceof_1
JVariableRef variableRef = jDeclarationStatement.getVariableRef();
JCastOperation jCastOperation =
new JCastOperation(info, variableRef.getType(), local.createRef(info));

// foo = (Foo) $instanceof_1
JBinaryOperation assignOperation =
new JBinaryOperation(info, variableRef.getType(), JBinaryOperator.ASG, variableRef,
jCastOperation);

// null != (foo = (Foo) $instanceof_1)
JBinaryOperation nullCheckOperation =
new JBinaryOperation(info, JPrimitiveType.BOOLEAN, JBinaryOperator.NEQ,
JNullLiteral.INSTANCE, assignOperation);

// $instanceof_1 = o
JBinaryOperation assignLocalOperation =
new JBinaryOperation(info, expressionType, JBinaryOperator.ASG, local.createRef(info),
expr);

// (($instanceof_1 = o) instanceof Foo && null != (foo = (Foo) $instanceof_1))
JBinaryOperation rewrittenSwitch =
new JBinaryOperation(info, JPrimitiveType.BOOLEAN, JBinaryOperator.AND,
new JInstanceOf(info, testType, assignLocalOperation), nullCheckOperation);

push(rewrittenSwitch);
}
} catch (Throwable e) {
throw translateException(x, e);
}
Expand Down Expand Up @@ -3847,8 +3910,9 @@ static class MethodInfo {
public final Map<LocalVariableBinding, JVariable> locals = Maps.newIdentityHashMap();
public final JMethod method;
public final MethodScope scope;
public final Map<String, JStatement> instanceOfDeclarations = Maps.newHashMap();

public MethodInfo(JMethod method, JMethodBody methodBody, MethodScope methodScope) {
MethodInfo(JMethod method, JMethodBody methodBody, MethodScope methodScope) {
this.method = method;
this.body = methodBody;
this.scope = methodScope;
Expand Down