JVM Back-end does not handle complex patterns any more

#KT-2359 In Progress
This commit is contained in:
Andrey Breslav
2012-09-05 12:53:32 +04:00
parent 756ca9b284
commit 4dd0b27e93
2 changed files with 35 additions and 120 deletions
@@ -3267,33 +3267,20 @@ The "returned" value of try expression with no finally is either the last expres
@Override @Override
public StackValue visitIsExpression(final JetIsExpression expression, StackValue receiver) { public StackValue visitIsExpression(final JetIsExpression expression, StackValue receiver) {
final StackValue match = StackValue.expression(OBJECT_TYPE, expression.getLeftHandSide(), this); final StackValue match = StackValue.expression(OBJECT_TYPE, expression.getLeftHandSide(), this);
return generatePatternMatch(expression.getPattern(), expression.isNegated(), match, false, null); return generateIsCheck(match, expression.getTypeRef(), expression.isNegated());
} }
// on entering the function, expressionToMatch is already placed on stack, and we should consume it private StackValue generateExpressionMatch(
private StackValue generatePatternMatch( StackValue expressionToMatch,
JetPattern pattern, boolean negated, StackValue expressionToMatch, JetExpression patternExpression,
boolean expressionToMatchIsNullable, @Nullable Label nextEntry boolean expressionToMatchIsNullable
) { ) {
if (pattern instanceof JetTypePattern) {
JetTypeReference typeReference = ((JetTypePattern) pattern).getTypeReference();
JetType jetType = bindingContext.get(BindingContext.TYPE, typeReference);
expressionToMatch.dupReceiver(v);
generateInstanceOf(expressionToMatch, jetType, false);
StackValue value = StackValue.onStack(Type.BOOLEAN_TYPE);
return negated ? StackValue.not(value) : value;
}
else if (pattern instanceof JetTuplePattern) {
return generateTuplePatternMatch((JetTuplePattern) pattern, negated, expressionToMatch, nextEntry);
}
else if (pattern instanceof JetExpressionPattern) {
if (expressionToMatch != null) { if (expressionToMatch != null) {
Type subjectType = expressionToMatch.type; Type subjectType = expressionToMatch.type;
expressionToMatch.dupReceiver(v); expressionToMatch.dupReceiver(v);
expressionToMatch.put(subjectType, v); expressionToMatch.put(subjectType, v);
JetExpression condExpression = ((JetExpressionPattern) pattern).getExpression();
boolean patternIsNullable = false; boolean patternIsNullable = false;
JetType condJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, condExpression); JetType condJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, patternExpression);
Type condType; Type condType;
if (CodegenUtil.isNumberPrimitive(subjectType) || subjectType.getSort() == Type.BOOLEAN) { if (CodegenUtil.isNumberPrimitive(subjectType) || subjectType.getSort() == Type.BOOLEAN) {
assert condJetType != null; assert condJetType != null;
@@ -3307,80 +3294,21 @@ The "returned" value of try expression with no finally is either the last expres
condType = OBJECT_TYPE; condType = OBJECT_TYPE;
patternIsNullable = condJetType != null && condJetType.isNullable(); patternIsNullable = condJetType != null && condJetType.isNullable();
} }
gen(condExpression, condType); gen(patternExpression, condType);
return generateEqualsForExpressionsOnStack(JetTokens.EQEQ, subjectType, condType, expressionToMatchIsNullable, return generateEqualsForExpressionsOnStack(JetTokens.EQEQ, subjectType, condType, expressionToMatchIsNullable,
patternIsNullable); patternIsNullable);
} }
else { else {
JetExpression condExpression = ((JetExpressionPattern) pattern).getExpression(); return gen(patternExpression);
return gen(condExpression);
} }
} }
else if (pattern instanceof JetWildcardPattern) {
return StackValue.constant(!negated, Type.BOOLEAN_TYPE); private StackValue generateIsCheck(StackValue expressionToMatch, JetTypeReference typeReference, boolean negated) {
} JetType jetType = bindingContext.get(BindingContext.TYPE, typeReference);
else if (pattern instanceof JetBindingPattern) {
final JetProperty var = ((JetBindingPattern) pattern).getVariableDeclaration();
final VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, var);
assert variableDescriptor != null;
final Type varType = asmType(variableDescriptor.getType());
myFrameMap.enter(variableDescriptor, varType);
expressionToMatch.dupReceiver(v); expressionToMatch.dupReceiver(v);
expressionToMatch.put(varType, v); generateInstanceOf(expressionToMatch, jetType, false);
final int varIndex = lookupLocalIndex(variableDescriptor); StackValue value = StackValue.onStack(Type.BOOLEAN_TYPE);
v.store(varIndex, varType); return negated ? StackValue.not(value) : value;
return generateWhenCondition(varType, varIndex, false, ((JetBindingPattern) pattern).getCondition(), null);
}
else {
throw new UnsupportedOperationException("Unsupported pattern type: " + pattern);
}
}
private StackValue generateTuplePatternMatch(
JetTuplePattern pattern, boolean negated, StackValue expressionToMatch,
@Nullable Label nextEntry
) {
final List<JetTuplePatternEntry> entries = pattern.getEntries();
Label lblFail = new Label();
Label lblDone = new Label();
expressionToMatch.dupReceiver(v);
expressionToMatch.put(OBJECT_TYPE, v);
v.dup();
final JvmClassName tupleClassName = JvmClassName.byInternalName("jet/Tuple" + entries.size());
Type tupleType = tupleClassName.getAsmType();
v.instanceOf(tupleType);
Label lblCheck = new Label();
v.ifne(lblCheck);
Label lblPopAndFail = new Label();
v.mark(lblPopAndFail);
v.pop();
v.goTo(lblFail);
v.mark(lblCheck);
for (int i = 0; i < entries.size(); i++) {
final StackValue tupleField = StackValue.field(OBJECT_TYPE, tupleClassName, "_" + (i + 1), false);
final StackValue stackValue = generatePatternMatch(entries.get(i).getPattern(), false, tupleField, false, nextEntry);
stackValue.condJump(lblPopAndFail, true, v);
}
v.pop(); // delete extra copy of expressionToMatch
if (negated && nextEntry != null) {
v.goTo(nextEntry);
}
else {
v.iconst(!negated ? 1 : 0);
}
v.goTo(lblDone);
v.mark(lblFail);
if (!negated && nextEntry != null) {
v.goTo(nextEntry);
}
else {
v.iconst(negated ? 1 : 0);
}
v.mark(lblDone);
return StackValue.onStack(Type.BOOLEAN_TYPE);
} }
private void generateInstanceOf(StackValue expressionToGen, JetType jetType, boolean leaveExpressionOnStack) { private void generateInstanceOf(StackValue expressionToGen, JetType jetType, boolean leaveExpressionOnStack) {
@@ -3498,23 +3426,18 @@ The "returned" value of try expression with no finally is either the last expres
} }
return StackValue.onStack(Type.BOOLEAN_TYPE); return StackValue.onStack(Type.BOOLEAN_TYPE);
} }
JetPattern pattern; StackValue.Local match = subjectLocal == -1 ? null : StackValue.local(subjectLocal, subjectType);
boolean isNegated;
if (condition instanceof JetWhenConditionIsPattern) { if (condition instanceof JetWhenConditionIsPattern) {
JetWhenConditionIsPattern patternCondition = (JetWhenConditionIsPattern) condition; JetWhenConditionIsPattern patternCondition = (JetWhenConditionIsPattern) condition;
pattern = patternCondition.getPattern(); return generateIsCheck(match, patternCondition.getTypeRef(), patternCondition.isNegated());
isNegated = patternCondition.isNegated();
} }
else if (condition instanceof JetWhenConditionWithExpression) { else if (condition instanceof JetWhenConditionWithExpression) {
pattern = ((JetWhenConditionWithExpression) condition).getPattern(); JetExpression patternExpression = ((JetWhenConditionWithExpression) condition).getExpression();
isNegated = false; return generateExpressionMatch(match, patternExpression, subjectIsNullable);
} }
else { else {
throw new UnsupportedOperationException("unsupported kind of when condition"); throw new UnsupportedOperationException("unsupported kind of when condition");
} }
return generatePatternMatch(pattern, isNegated,
subjectLocal == -1 ? null : StackValue.local(subjectLocal, subjectType),
subjectIsNullable, nextEntry);
} }
private void invokeFunctionByReference(JetSimpleNameExpression operationReference) { private void invokeFunctionByReference(JetSimpleNameExpression operationReference) {
@@ -16,7 +16,6 @@
package org.jetbrains.jet.codegen; package org.jetbrains.jet.codegen;
import jet.Tuple2;
import org.jetbrains.jet.ConfigurationKind; import org.jetbrains.jet.ConfigurationKind;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -97,13 +96,13 @@ public class PatternMatchingTest extends CodegenTestCase {
} }
public void testWildcardPattern() throws Exception { public void testWildcardPattern() throws Exception {
loadText("fun foo(x: String) = when(x) { is * -> \"something\" }"); loadText("fun foo(x: String) = when(x) { else -> \"something\" }");
Method foo = generateFunction(); Method foo = generateFunction();
assertEquals("something", foo.invoke(null, "")); assertEquals("something", foo.invoke(null, ""));
} }
public void testNoReturnType() throws Exception { public void testNoReturnType() throws Exception {
loadText("fun foo(x: String) = when(x) { is * -> \"x\" }"); loadText("fun foo(x: String) = when(x) { else -> \"x\" }");
Method foo = generateFunction(); Method foo = generateFunction();
assertEquals("x", foo.invoke(null, "")); assertEquals("x", foo.invoke(null, ""));
} }
@@ -119,15 +118,8 @@ public class PatternMatchingTest extends CodegenTestCase {
blackBoxFile("patternMatching/callProperty.jet"); blackBoxFile("patternMatching/callProperty.jet");
} }
public void testNames() throws Exception {
loadText("fun foo(x: #(Any, Any)) = when(x) { is #(val a is String, *) -> a; else -> \"something\" }");
Method foo = generateFunction();
assertEquals("JetBrains", foo.invoke(null, new Tuple2<String, String>("JetBrains", "s.r.o.")));
assertEquals("something", foo.invoke(null, new Tuple2<Integer, Integer>(1, 2)));
}
public void testMultipleConditions() throws Exception { public void testMultipleConditions() throws Exception {
loadText("fun foo(x: Any) = when(x) { is 0, 1 -> \"bit\"; else -> \"something\" }"); loadText("fun foo(x: Any) = when(x) { 0, 1 -> \"bit\"; else -> \"something\" }");
Method foo = generateFunction(); Method foo = generateFunction();
assertEquals("bit", foo.invoke(null, 0)); assertEquals("bit", foo.invoke(null, 0));
assertEquals("bit", foo.invoke(null, 1)); assertEquals("bit", foo.invoke(null, 1));