pattern matching with type patterns

This commit is contained in:
Dmitry Jemerov
2011-05-19 19:48:19 +02:00
parent 0fe2b7ef2f
commit a58672515a
3 changed files with 38 additions and 15 deletions
@@ -1295,7 +1295,7 @@ public class ExpressionCodegen extends JetVisitor {
}
@Override
public void visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression) {
public void visitBinaryWithTypeRHSExpression(final JetBinaryExpressionWithTypeRHS expression) {
JetSimpleNameExpression operationSign = expression.getOperationSign();
IElementType opToken = operationSign.getReferencedNameElementType();
if (opToken == JetTokens.COLON) {
@@ -1311,7 +1311,12 @@ public class ExpressionCodegen extends JetVisitor {
Type type = typeMapper.jvmType((ClassDescriptor) descriptor, OwnerKind.INTERFACE);
gen(expression.getLeft(), OBJECT_TYPE);
if (opToken == JetTokens.AS_SAFE) {
generateInstanceOf(expression.getLeft(), jetType, true);
generateInstanceOf(new Runnable() {
@Override
public void run() {
gen(expression.getLeft(), OBJECT_TYPE);
}
}, jetType, true);
Label isInstance = new Label();
v.ifne(isInstance);
v.pop();
@@ -1332,33 +1337,41 @@ public class ExpressionCodegen extends JetVisitor {
}
@Override
public void visitIsExpression(JetIsExpression expression) {
JetPattern pattern = expression.getPattern();
public void visitIsExpression(final JetIsExpression expression) {
generatePatternMatch(expression.getPattern(), expression.isNegated(), new Runnable() {
@Override
public void run() {
gen(expression.getLeftHandSide(), OBJECT_TYPE);
}
});
}
private void generatePatternMatch(JetPattern pattern, boolean negated, Runnable expressionGen) {
if (!(pattern instanceof JetTypePattern)) {
throw new UnsupportedOperationException("can only generate a type pattern with 'is'");
}
JetTypeReference typeReference = ((JetTypePattern) pattern).getTypeReference();
JetType jetType = bindingContext.resolveTypeReference(typeReference);
generateInstanceOf(expression.getLeftHandSide(), jetType, false);
generateInstanceOf(expressionGen, jetType, false);
StackValue value = StackValue.onStack(Type.BOOLEAN_TYPE);
myStack.push(expression.isNot() ? StackValue.not(value) : value);
myStack.push(negated ? StackValue.not(value) : value);
}
private void generateInstanceOf(JetExpression expression, JetType jetType, boolean leaveExpressionOnStack) {
private void generateInstanceOf(Runnable expressionGen, JetType jetType, boolean leaveExpressionOnStack) {
DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
if (!(descriptor instanceof ClassDescriptor)) {
throw new UnsupportedOperationException("don't know how to handle non-class types");
}
if (jetType.getArguments().size() > 0) {
generateTypeInfo(jetType);
gen(expression, OBJECT_TYPE);
expressionGen.run();
if (leaveExpressionOnStack) {
v.dupX1();
}
v.invokevirtual("jet/typeinfo/TypeInfo", "isInstance", "(Ljava/lang/Object;)Z");
}
else {
gen(expression, OBJECT_TYPE);
expressionGen.run();
if (leaveExpressionOnStack) {
v.dup();
}
@@ -1405,8 +1418,8 @@ public class ExpressionCodegen extends JetVisitor {
@Override
public void visitWhenExpression(JetWhenExpression expression) {
JetExpression expr = expression.getSubjectExpression();
Type subjectType = expressionType(expr);
int subjectLocal = myMap.enterTemp(subjectType.getSize());
final Type subjectType = expressionType(expr);
final int subjectLocal = myMap.enterTemp(subjectType.getSize());
gen(expr, subjectType);
v.store(subjectLocal, subjectType);
@@ -1426,18 +1439,28 @@ public class ExpressionCodegen extends JetVisitor {
Type condType = expressionType(condExpression);
gen(condExpression, condType);
generateEqualsForExpressionsOnStack(JetTokens.EQEQ, subjectType, condType);
myStack.pop().condJump(nextEntry, true, v);
}
else if (condition instanceof JetWhenConditionInRange) {
JetExpression range = ((JetWhenConditionInRange) condition).getRangeExpression();
gen(range, RANGE_TYPE);
new StackValue.Local(subjectLocal, subjectType).put(OBJECT_TYPE, v);
v.invokeinterface(CLASS_RANGE, "contains", "(Ljava/lang/Comparable;)Z");
new StackValue.OnStack(Type.BOOLEAN_TYPE).condJump(nextEntry, true, v);
myStack.push(new StackValue.OnStack(Type.BOOLEAN_TYPE));
}
else if (condition instanceof JetWhenConditionIsPattern) {
JetWhenConditionIsPattern patternCondition = (JetWhenConditionIsPattern) condition;
JetPattern pattern = patternCondition.getPattern();
generatePatternMatch(pattern, patternCondition.isNegated(), new Runnable() {
@Override
public void run() {
new StackValue.Local(subjectLocal, subjectType).put(OBJECT_TYPE, v);
}
});
}
else {
throw new UnsupportedOperationException("unsupported kind of when condition");
}
myStack.pop().condJump(nextEntry, true, v);
}
else {
hasElse = true;
@@ -34,7 +34,7 @@ public class JetIsExpression extends JetExpression {
return (JetSimpleNameExpression) findChildByType(JetNodeTypes.OPERATION_REFERENCE);
}
public boolean isNot() {
public boolean isNegated() {
return getOperationReference().getReferencedNameElementType() == JetTokens.NOT_IS;
}
@@ -35,7 +35,7 @@ public class PatternMatchingTest extends CodegenTestCase {
assertTrue(caught);
}
public void _testPattern() throws Exception {
public void testPattern() throws Exception {
loadFile();
Method foo = generateFunction();
assertEquals("string", foo.invoke(null, ""));