JVM Back-end does not handle complex patterns any more
#KT-2359 In Progress
This commit is contained in:
@@ -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));
|
||||||
|
|||||||
Reference in New Issue
Block a user