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,120 +3267,48 @@ 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) { if (expressionToMatch != null) {
JetTypeReference typeReference = ((JetTypePattern) pattern).getTypeReference(); Type subjectType = expressionToMatch.type;
JetType jetType = bindingContext.get(BindingContext.TYPE, typeReference);
expressionToMatch.dupReceiver(v); expressionToMatch.dupReceiver(v);
generateInstanceOf(expressionToMatch, jetType, false); expressionToMatch.put(subjectType, v);
StackValue value = StackValue.onStack(Type.BOOLEAN_TYPE); boolean patternIsNullable = false;
return negated ? StackValue.not(value) : value; JetType condJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, patternExpression);
} Type condType;
else if (pattern instanceof JetTuplePattern) { if (CodegenUtil.isNumberPrimitive(subjectType) || subjectType.getSort() == Type.BOOLEAN) {
return generateTuplePatternMatch((JetTuplePattern) pattern, negated, expressionToMatch, nextEntry); assert condJetType != null;
} condType = asmType(condJetType);
else if (pattern instanceof JetExpressionPattern) { if (!(CodegenUtil.isNumberPrimitive(condType) || condType.getSort() == Type.BOOLEAN)) {
if (expressionToMatch != null) { subjectType = boxType(subjectType);
Type subjectType = expressionToMatch.type; expressionToMatch.coerce(subjectType, v);
expressionToMatch.dupReceiver(v);
expressionToMatch.put(subjectType, v);
JetExpression condExpression = ((JetExpressionPattern) pattern).getExpression();
boolean patternIsNullable = false;
JetType condJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, condExpression);
Type condType;
if (CodegenUtil.isNumberPrimitive(subjectType) || subjectType.getSort() == Type.BOOLEAN) {
assert condJetType != null;
condType = asmType(condJetType);
if (!(CodegenUtil.isNumberPrimitive(condType) || condType.getSort() == Type.BOOLEAN)) {
subjectType = boxType(subjectType);
expressionToMatch.coerce(subjectType, v);
}
} }
else {
condType = OBJECT_TYPE;
patternIsNullable = condJetType != null && condJetType.isNullable();
}
gen(condExpression, condType);
return generateEqualsForExpressionsOnStack(JetTokens.EQEQ, subjectType, condType, expressionToMatchIsNullable,
patternIsNullable);
} }
else { else {
JetExpression condExpression = ((JetExpressionPattern) pattern).getExpression(); condType = OBJECT_TYPE;
return gen(condExpression); patternIsNullable = condJetType != null && condJetType.isNullable();
} }
} gen(patternExpression, condType);
else if (pattern instanceof JetWildcardPattern) { return generateEqualsForExpressionsOnStack(JetTokens.EQEQ, subjectType, condType, expressionToMatchIsNullable,
return StackValue.constant(!negated, Type.BOOLEAN_TYPE); patternIsNullable);
}
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.put(varType, v);
final int varIndex = lookupLocalIndex(variableDescriptor);
v.store(varIndex, varType);
return generateWhenCondition(varType, varIndex, false, ((JetBindingPattern) pattern).getCondition(), null);
} }
else { else {
throw new UnsupportedOperationException("Unsupported pattern type: " + pattern); return gen(patternExpression);
} }
} }
private StackValue generateTuplePatternMatch( private StackValue generateIsCheck(StackValue expressionToMatch, JetTypeReference typeReference, boolean negated) {
JetTuplePattern pattern, boolean negated, StackValue expressionToMatch, JetType jetType = bindingContext.get(BindingContext.TYPE, typeReference);
@Nullable Label nextEntry
) {
final List<JetTuplePatternEntry> entries = pattern.getEntries();
Label lblFail = new Label();
Label lblDone = new Label();
expressionToMatch.dupReceiver(v); expressionToMatch.dupReceiver(v);
expressionToMatch.put(OBJECT_TYPE, v); generateInstanceOf(expressionToMatch, jetType, false);
v.dup(); StackValue value = StackValue.onStack(Type.BOOLEAN_TYPE);
final JvmClassName tupleClassName = JvmClassName.byInternalName("jet/Tuple" + entries.size()); return negated ? StackValue.not(value) : value;
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));