support explicit calls to some intrinsic functions
This commit is contained in:
@@ -666,7 +666,7 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
final Type fieldType = JetTypeMapper.psiTypeToAsm(psiField.getType());
|
||||
final boolean isStatic = psiField.hasModifierProperty(PsiModifier.STATIC);
|
||||
if (!isStatic) {
|
||||
ensureReceiverOnStack(expression, null);
|
||||
ensureReceiverOnStack(expression, null, JetTypeMapper.TYPE_OBJECT);
|
||||
}
|
||||
myStack.push(StackValue.field(fieldType, owner, psiField.getName(), isStatic));
|
||||
}
|
||||
@@ -710,7 +710,7 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
final boolean forceInterface = receiver != null && !(receiver instanceof JetThisExpression);
|
||||
final StackValue iValue = intermediateValueForProperty(propertyDescriptor, directToField, forceInterface);
|
||||
if (!isStatic) {
|
||||
ensureReceiverOnStack(expression, container instanceof ClassDescriptor ? (ClassDescriptor) container : null);
|
||||
ensureReceiverOnStack(expression, container instanceof ClassDescriptor ? (ClassDescriptor) container : null, JetTypeMapper.TYPE_OBJECT);
|
||||
}
|
||||
myStack.push(iValue);
|
||||
}
|
||||
@@ -877,7 +877,7 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
setOwnerFromCall(callableMethod, expression);
|
||||
}
|
||||
if (callableMethod.needsReceiverOnStack() && !haveReceiver) {
|
||||
ensureReceiverOnStack(expression, callableMethod.getReceiverClass());
|
||||
ensureReceiverOnStack(expression, callableMethod.getReceiverClass(), JetTypeMapper.TYPE_OBJECT);
|
||||
}
|
||||
pushMethodArguments(expression, callableMethod.getValueParameterTypes());
|
||||
if (callableMethod.acceptsTypeArguments()) {
|
||||
@@ -906,7 +906,16 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ensureReceiverOnStack(PsiElement expression, @Nullable ClassDescriptor calleeContainingClass) {
|
||||
public void ensureReceiverOnStack(PsiElement expression, @Nullable ClassDescriptor calleeContainingClass,
|
||||
final Type expectedReceiverType) {
|
||||
final StackValue receiver = getReceiverAsStackValue(expression, calleeContainingClass, expectedReceiverType);
|
||||
if (receiver != null) {
|
||||
receiver.put(receiver.type, v);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public StackValue getReceiverAsStackValue(PsiElement expression, @Nullable ClassDescriptor calleeContainingClass, Type expectedReceiverType) {
|
||||
JetExpression receiver = getReceiverForSelector(expression);
|
||||
if (receiver != null) {
|
||||
if (!resolvesToClassOrPackage(receiver)) {
|
||||
@@ -914,13 +923,14 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
if (myStack.isEmpty()) {
|
||||
throw new IllegalStateException("expected receiver on stack but it's not there: " + receiver.getText());
|
||||
}
|
||||
myStack.pop().put(JetTypeMapper.TYPE_OBJECT, v);
|
||||
return myStack.pop();
|
||||
}
|
||||
}
|
||||
else if (!(expression.getParent() instanceof JetSafeQualifiedExpression) &&
|
||||
!(expression.getParent() instanceof JetPredicateExpression)) {
|
||||
generateThisOrOuter(calleeContainingClass);
|
||||
return generateThisOrOuter(calleeContainingClass);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isSubclass(ClassDescriptor subClass, ClassDescriptor superClass) {
|
||||
@@ -948,8 +958,9 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
public void generateThisOrOuter(ClassDescriptor calleeContainingClass) {
|
||||
public StackValue generateThisOrOuter(ClassDescriptor calleeContainingClass) {
|
||||
boolean thisDone = false;
|
||||
StackValue result = null;
|
||||
|
||||
ClassContext cur = context;
|
||||
while (true) {
|
||||
@@ -973,16 +984,16 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
}
|
||||
|
||||
thisDone = true;
|
||||
outer.put(outer.type, v);
|
||||
|
||||
result = outer;
|
||||
}
|
||||
|
||||
cur = parentContext;
|
||||
}
|
||||
|
||||
if (!thisDone) {
|
||||
thisToStack();
|
||||
return thisExpression();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isReceiver(PsiElement expression) {
|
||||
@@ -1513,8 +1524,7 @@ public class ExpressionCodegen extends JetVisitor {
|
||||
public void visitThisExpression(JetThisExpression expression) {
|
||||
final DeclarationDescriptor descriptor = bindingContext.resolveReferenceExpression(expression.getThisReference());
|
||||
if (descriptor instanceof ClassDescriptor) {
|
||||
generateThisOrOuter((ClassDescriptor) descriptor);
|
||||
myStack.push(StackValue.onStack(JetTypeMapper.TYPE_OBJECT));
|
||||
myStack.push(generateThisOrOuter((ClassDescriptor) descriptor));
|
||||
}
|
||||
else {
|
||||
generateThis();
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.JetTypeMapper;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.objectweb.asm.Type;
|
||||
@@ -15,7 +16,7 @@ import java.util.List;
|
||||
public class ArraySize implements IntrinsicMethod {
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, boolean haveReceiver) {
|
||||
codegen.ensureReceiverOnStack(element, null);
|
||||
codegen.ensureReceiverOnStack(element, null, JetTypeMapper.TYPE_OBJECT);
|
||||
v.arraylength();
|
||||
return StackValue.onStack(Type.INT_TYPE);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.jetbrains.jet.codegen.intrinsics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.ExpressionCodegen;
|
||||
import org.jetbrains.jet.codegen.JetTypeMapper;
|
||||
import org.jetbrains.jet.codegen.StackValue;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.objectweb.asm.Type;
|
||||
@@ -21,10 +22,17 @@ public class BinaryOp implements IntrinsicMethod {
|
||||
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, boolean haveReceiver) {
|
||||
if (!haveReceiver) {
|
||||
if (arguments.size() == 1) {
|
||||
// intrinsic is called as an ordinary function
|
||||
codegen.ensureReceiverOnStack(element, null, expectedType);
|
||||
codegen.gen(arguments.get(0), expectedType);
|
||||
}
|
||||
codegen.gen(arguments.get(1), expectedType);
|
||||
else {
|
||||
if (!haveReceiver) {
|
||||
codegen.gen(arguments.get(0), expectedType);
|
||||
}
|
||||
codegen.gen(arguments.get(1), expectedType);
|
||||
}
|
||||
v.visitInsn(expectedType.getOpcode(opcode));
|
||||
return StackValue.onStack(expectedType);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,13 @@ import java.util.List;
|
||||
public class Not implements IntrinsicMethod {
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, boolean haveReceiver) {
|
||||
final StackValue stackValue = codegen.generateIntermediateValue(arguments.get(0));
|
||||
final StackValue stackValue;
|
||||
if (arguments.size() == 1) {
|
||||
stackValue = codegen.generateIntermediateValue(arguments.get(0));
|
||||
}
|
||||
else {
|
||||
stackValue = codegen.getReceiverAsStackValue(element, null, expectedType);
|
||||
}
|
||||
return StackValue.not(stackValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,12 @@ import java.util.List;
|
||||
public class UnaryMinus implements IntrinsicMethod {
|
||||
@Override
|
||||
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element, List<JetExpression> arguments, boolean haveReceiver) {
|
||||
codegen.gen(arguments.get(0), expectedType);
|
||||
if (arguments.size() == 1) {
|
||||
codegen.gen(arguments.get(0), expectedType);
|
||||
}
|
||||
else {
|
||||
codegen.ensureReceiverOnStack(element, null, expectedType);
|
||||
}
|
||||
v.neg(expectedType);
|
||||
return StackValue.onStack(expectedType);
|
||||
}
|
||||
|
||||
@@ -463,4 +463,22 @@ public class NamespaceGenTest extends CodegenTestCase {
|
||||
final Method main = generateFunction();
|
||||
assertEquals("IntelliJ IDEA Rulezzz", main.invoke(null, "IDEA"));
|
||||
}
|
||||
|
||||
public void testExplicitCallOfBinaryOpIntrinsic() throws Exception {
|
||||
loadText("fun foo(a: Int) = a.plus(1)");
|
||||
final Method main = generateFunction();
|
||||
assertEquals(2, ((Integer) main.invoke(null, 1)).intValue());
|
||||
}
|
||||
|
||||
public void testExplicitCallOfUnaryMinusIntrinsic() throws Exception {
|
||||
loadText("fun foo(a: Int) = a.minus()");
|
||||
final Method main = generateFunction();
|
||||
assertEquals(-1, ((Integer) main.invoke(null, 1)).intValue());
|
||||
}
|
||||
|
||||
public void testExplicitCallOfBooleanNotIntrinsic() throws Exception {
|
||||
loadText("fun foo(a: Boolean) = a.not()");
|
||||
final Method main = generateFunction();
|
||||
assertEquals(false, ((Boolean) main.invoke(null, true)).booleanValue());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user