Skip to content

Commit

Permalink
Add compiler implementation, tests for Java 16 pattern matching insta…
Browse files Browse the repository at this point in the history
  • Loading branch information
vegegoku committed Feb 8, 2024
1 parent 89c3aaf commit 8d1c2ff
Show file tree
Hide file tree
Showing 4 changed files with 345 additions and 20 deletions.
42 changes: 40 additions & 2 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,45 @@ 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 {
String localVariableName = jDeclarationStatement.getVariableRef().getTarget().getName();
if (!curMethod.instanceOfDeclarations.containsKey(localVariableName)) {
curMethod.body.getBlock().addStmt(0, jDeclarationStatement);
curMethod.instanceOfDeclarations.put(localVariableName, jDeclarationStatement);
}

// rewrite (o instanceof Foo foo)
// to
// Foo foo;
// (o instanceof Foo && null != (foo = (Foo) o))
CloneExpressionVisitor cloner = new CloneExpressionVisitor();

JVariableRef variableRef = jDeclarationStatement.getVariableRef();
JCastOperation jCastOperation = new JCastOperation(info, variableRef.getType(), cloner.cloneExpression(expr));
JBinaryOperation assignOperation =
new JBinaryOperation(info, variableRef.getType(), JBinaryOperator.ASG, variableRef,
jCastOperation);

JBinaryOperation refAssignExpr =
new JBinaryOperation(info, JPrimitiveType.BOOLEAN, JBinaryOperator.NEQ,
JNullLiteral.INSTANCE, assignOperation);

JBinaryOperation rewrittenSwitch =
new JBinaryOperation(info, JPrimitiveType.BOOLEAN, JBinaryOperator.AND,
new JInstanceOf(info, testType, expr), refAssignExpr);

push(rewrittenSwitch);
}
} catch (Throwable e) {
throw translateException(x, e);
}
Expand Down Expand Up @@ -3847,6 +3884,7 @@ 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) {
this.method = method;
Expand Down
196 changes: 179 additions & 17 deletions dev/core/test/com/google/gwt/dev/jjs/impl/Java17AstTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.javac.testing.impl.JavaResourceBase;
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.ast.JAbstractMethodBody;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JInterfaceType;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JStringLiteral;
import com.google.gwt.dev.jjs.ast.JType;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.StringUtils;

/**
* Tests that {@link GwtAstBuilder} correctly builds the AST for
Expand Down Expand Up @@ -51,12 +55,21 @@ public void setUp() throws Exception {
addAll(JavaResourceBase.createMockJavaResource("test.Square",
"package test;",
"public final class Square extends Shape {",
"public int getLength() {",
"return 10;",
"}",
"public double getSide() {",
"return 0;",
"}",
"}"
));

addAll(JavaResourceBase.createMockJavaResource("test.Circle",
"package test;",
"public final class Circle extends Shape {",
"public double getDiameter() {",
"return 0;",
"}",
"}"
));

Expand All @@ -66,6 +79,13 @@ public void setUp() throws Exception {
"JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER;",
"}"
));

addAll(JavaResourceBase.createMockJavaResource("test.TestSupplier",
"package test;",
"public interface TestSupplier {",
" boolean run();",
"}"
));
}

public void testTextBlocks() throws Exception {
Expand Down Expand Up @@ -134,23 +154,165 @@ public void testSwitchExpressionsNotSupported() {
}
}

public void testSwitchExpressionsInitializerShouldFail() {
try {
compileSnippet("void", " int i = switch(1) {\n" +
" case 1:\n" +
" yield 2;\n" +
" default:\n" +
" yield 7;\n" +
" };");
fail("Compile should have failed but succeeded, switch expressions as initializer should fail.");
} catch (Exception e) {
if (!(e.getCause() instanceof InternalCompilerException)
&& !(e instanceof InternalCompilerException)) {
e.printStackTrace();
fail();
}
assertEquals("Switch expressions not yet supported", e.getMessage());
}
public void testInstanceOfPatternMatching() throws UnableToCompleteException {
JProgram program = compileSnippet("void", "Shape shape1 = new Circle();" +
"if(shape1 instanceof Circle circle) {" +
"double diameter = circle.getDiameter();" +
"}"
);

JAbstractMethodBody onModuleLoadMethod = findMethod(program, "onModuleLoad")
.getBody();

assertTrue(onModuleLoadMethod
.toSource()
.contains("Circle circle;"));

assertTrue(onModuleLoadMethod
.toSource()
.contains("shape1 instanceof Circle && null != (circle = (Circle) shape1)"));
}

public void testInstanceOfPatternMatchingWithAnd() throws UnableToCompleteException {
JProgram program = compileSnippet("void",
"Shape shape1 = new Circle();\n" +
"Shape shape2 = new Square();\n" +
"if(shape1 instanceof Circle circle && shape2 instanceof Square square) {\n" +
"double diameter = circle.getDiameter();\n" +
"}\n"
);

JAbstractMethodBody onModuleLoadMethod = findMethod(program, "onModuleLoad")
.getBody();

assertTrue(onModuleLoadMethod
.toSource()
.contains("Circle circle;"));

assertTrue(onModuleLoadMethod
.toSource()
.contains("Square square;"));

assertTrue(onModuleLoadMethod
.toSource()
.contains("shape1 instanceof Circle && null != (circle = (Circle) shape1)"));

assertTrue(onModuleLoadMethod
.toSource()
.contains("shape2 instanceof Square && null != (square = (Square) shape2)"));
}

public void testInstanceOfPatternMatchingWithCondition() throws UnableToCompleteException {
JProgram program = compileSnippet("void",
"Shape shape2 = new Square();\n" +
"if(shape2 instanceof Square square && square.getLength() > 0) {\n" +
"double diameter = square.getSide();\n" +
"}\n"
);

JAbstractMethodBody onModuleLoadMethod = findMethod(program, "onModuleLoad")
.getBody();

assertTrue(onModuleLoadMethod
.toSource()
.contains("Square square;"));

assertTrue(onModuleLoadMethod
.toSource()
.contains("shape2 instanceof Square && null != (square = (Square) shape2)"));
}

public void testInstanceOfPatternMatchingWithAsNotCondition() throws UnableToCompleteException {
JProgram program = compileSnippet("void",
"Shape shape1 = new Square();\n" +
"if(!(shape1 instanceof Square square && square.getLength() > 0)) {\n" +
"}\n"
);

JAbstractMethodBody onModuleLoadMethod = findMethod(program, "onModuleLoad")
.getBody();

assertTrue(onModuleLoadMethod
.toSource()
.contains("Square square;"));

assertTrue(onModuleLoadMethod
.toSource()
.contains("shape1 instanceof Square && null != (square = (Square) shape1)"));
}

public void testMultipleInstanceOfPatternMatchingWithSameVariableName() throws UnableToCompleteException {
JProgram program = compileSnippet("void",
"Shape shape1 = new Square();\n" +
"Shape shape2 = new Square();\n" +
"if(shape1 instanceof Square square && square.getLength() > 0) {\n" +
"}\n" +
"if(shape2 instanceof Square square && square.getLength() > 0) {\n" +
"}\n"
);

JAbstractMethodBody onModuleLoadMethod = findMethod(program, "onModuleLoad")
.getBody();

assertEquals(1, StringUtils.countMatches(onModuleLoadMethod.toSource(), "Square square;"));

assertTrue(onModuleLoadMethod
.toSource()
.contains("shape1 instanceof Square && null != (square = (Square) shape1)"));

assertTrue(onModuleLoadMethod
.toSource()
.contains("shape2 instanceof Square && null != (square = (Square) shape2)"));
}

public void testInstanceOfPatternMatchingInLambda() throws UnableToCompleteException {
addSnippetClassDecl("public class Foo {\n" +
"private Shape shape;\n" +
"public Foo(){\n" +
"shape = new Square();\n" +
"}\n" +
"public TestSupplier isSquare(){\n" +
"return () -> shape instanceof Square square && square.getLength() > 0;\n" +
"}\n" +
"}");

JProgram program = compileSnippet("void", "Foo foo = new Foo();");
JType foo = findType(program, "test.EntryPoint.Foo");
JAbstractMethodBody lambda = findMethod((JDeclaredType) foo, "lambda$0")
.getBody();

assertTrue(lambda
.toSource()
.contains("Square square;"));

assertTrue(lambda
.toSource()
.contains("this.shape instanceof Square && null != (square = (Square) this.shape)"));
}

public void testInstanceOfPatternMatchingAsReturn() throws UnableToCompleteException {

addSnippetClassDecl("public class Foo {\n" +
"private Shape shape;\n" +
"public Foo(){\n" +
"shape = new Square();\n" +
"}\n" +
"public boolean isSquare(){\n" +
"return shape instanceof Square square && square.getLength() > 0;\n" +
"}\n" +
"}");
JProgram program = compileSnippet("void", "Foo foo = new Foo();");
JType foo = findType(program, "test.EntryPoint.Foo");
JAbstractMethodBody isSquare = findMethod((JDeclaredType) foo, "isSquare")
.getBody();

assertTrue(isSquare
.toSource()
.contains("Square square;"));

assertTrue(isSquare
.toSource()
.contains("this.shape instanceof Square && null != (square = (Square) this.shape)"));
}

@Override
Expand Down

0 comments on commit 8d1c2ff

Please sign in to comment.