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