KT-504 array like expressions with type parameters
This commit is contained in:
@@ -84,12 +84,4 @@ public class CallableMethod implements Callable {
|
||||
public boolean isNeedsReceiver() {
|
||||
return receiverFunction != null;
|
||||
}
|
||||
|
||||
public ClassDescriptor getThisClass() {
|
||||
return thisClass;
|
||||
}
|
||||
|
||||
public CallableDescriptor getReceiverFunction() {
|
||||
return receiverFunction;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,8 +53,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
private int myLastLineNumber = -1;
|
||||
|
||||
final InstructionAdapter v;
|
||||
private final FrameMap myFrameMap;
|
||||
private final JetTypeMapper typeMapper;
|
||||
final FrameMap myFrameMap;
|
||||
final JetTypeMapper typeMapper;
|
||||
|
||||
private final GenerationState state;
|
||||
private final Type returnType;
|
||||
@@ -1200,7 +1200,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
callableMethod.invokeWithDefault(v, mask);
|
||||
}
|
||||
|
||||
private void generateFromResolvedCall(ReceiverDescriptor descriptor) {
|
||||
protected void generateFromResolvedCall(ReceiverDescriptor descriptor) {
|
||||
if(descriptor instanceof ClassReceiver) {
|
||||
ClassReceiver classReceiver = (ClassReceiver) descriptor;
|
||||
generateThisOrOuter((ClassDescriptor) classReceiver.getDeclarationDescriptor()).put(typeMapper.mapType(descriptor.getType()), v);
|
||||
@@ -2111,12 +2111,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
boolean isGetter = accessor.getSignature().getName().equals("get");
|
||||
|
||||
ResolvedCall<FunctionDescriptor> resolvedSetCall = bindingContext.get(BindingContext.INDEXED_LVALUE_SET, expression);
|
||||
FunctionDescriptor setterDescriptor = resolvedSetCall == null ? null : resolvedSetCall.getResultingDescriptor();
|
||||
CallableMethod setter = resolvedSetCall == null ? null : typeMapper.mapToCallableMethod(setterDescriptor, false, OwnerKind.IMPLEMENTATION);
|
||||
|
||||
ResolvedCall<FunctionDescriptor> resolvedGetCall = bindingContext.get(BindingContext.INDEXED_LVALUE_GET, expression);
|
||||
|
||||
FunctionDescriptor setterDescriptor = resolvedSetCall == null ? null : resolvedSetCall.getResultingDescriptor();
|
||||
FunctionDescriptor getterDescriptor = resolvedGetCall == null ? null : resolvedGetCall.getResultingDescriptor();
|
||||
CallableMethod getter = resolvedGetCall == null ? null : typeMapper.mapToCallableMethod(getterDescriptor, false, OwnerKind.IMPLEMENTATION);
|
||||
|
||||
Type asmType;
|
||||
Type[] argumentTypes = accessor.getSignature().getArgumentTypes();
|
||||
@@ -2126,6 +2124,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
if(getterDescriptor.getReceiverParameter().exists()) {
|
||||
index++;
|
||||
}
|
||||
for (TypeParameterDescriptor typeParameterDescriptor : getterDescriptor.getTypeParameters()) {
|
||||
if(typeParameterDescriptor.isReified()) {
|
||||
generateTypeInfo(resolvedGetCall.getTypeArguments().get(typeParameterDescriptor));
|
||||
index++;
|
||||
}
|
||||
}
|
||||
asmType = accessor.getSignature().getReturnType();
|
||||
}
|
||||
else {
|
||||
@@ -2133,6 +2137,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
if(setterDescriptor.getReceiverParameter().exists()) {
|
||||
index++;
|
||||
}
|
||||
for (TypeParameterDescriptor typeParameterDescriptor : setterDescriptor.getOriginal().getTypeParameters()) {
|
||||
if(typeParameterDescriptor.isReified()) {
|
||||
generateTypeInfo(resolvedSetCall.getTypeArguments().get(typeParameterDescriptor));
|
||||
index++;
|
||||
}
|
||||
}
|
||||
asmType = argumentTypes[argumentTypes.length-1];
|
||||
}
|
||||
|
||||
@@ -2140,7 +2150,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
|
||||
gen(jetExpression, argumentTypes[index]);
|
||||
index++;
|
||||
}
|
||||
return StackValue.collectionElement(asmType, getter, setter, myFrameMap);
|
||||
return StackValue.collectionElement(asmType, resolvedGetCall, resolvedSetCall, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,12 @@ package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.jet.lexer.JetTokens;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
@@ -10,6 +15,8 @@ import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
* @author alex.tkachman
|
||||
@@ -85,8 +92,8 @@ public abstract class StackValue {
|
||||
return new ArrayElement(type, unbox);
|
||||
}
|
||||
|
||||
public static StackValue collectionElement(Type type, CallableMethod getter, CallableMethod setter, FrameMap frame) {
|
||||
return new CollectionElement(type, getter, setter, frame);
|
||||
public static StackValue collectionElement(Type type, ResolvedCall<FunctionDescriptor> getter, ResolvedCall<FunctionDescriptor> setter, ExpressionCodegen codegen) {
|
||||
return new CollectionElement(type, getter, setter, codegen);
|
||||
}
|
||||
|
||||
public static StackValue field(Type type, String owner, String name, boolean isStatic) {
|
||||
@@ -477,13 +484,23 @@ public abstract class StackValue {
|
||||
private static class CollectionElement extends StackValue {
|
||||
private final CallableMethod getter;
|
||||
private final CallableMethod setter;
|
||||
private final ExpressionCodegen codegen;
|
||||
private final FrameMap frame;
|
||||
private final ResolvedCall<FunctionDescriptor> resolvedGetCall;
|
||||
private final ResolvedCall<FunctionDescriptor> resolvedSetCall;
|
||||
private final FunctionDescriptor setterDescriptor;
|
||||
private final FunctionDescriptor getterDescriptor;
|
||||
|
||||
public CollectionElement(Type type, CallableMethod getter, CallableMethod setter, FrameMap frame) {
|
||||
public CollectionElement(Type type, ResolvedCall<FunctionDescriptor> resolvedGetCall, ResolvedCall<FunctionDescriptor> resolvedSetCall, ExpressionCodegen codegen) {
|
||||
super(type);
|
||||
this.getter = getter;
|
||||
this.setter = setter;
|
||||
this.frame = frame;
|
||||
this.resolvedGetCall = resolvedGetCall;
|
||||
this.resolvedSetCall = resolvedSetCall;
|
||||
this.setterDescriptor = resolvedSetCall == null ? null : resolvedSetCall.getResultingDescriptor();
|
||||
this.getterDescriptor = resolvedGetCall == null ? null : resolvedGetCall.getResultingDescriptor();
|
||||
this.setter = resolvedSetCall == null ? null : codegen.typeMapper.mapToCallableMethod(setterDescriptor, false, OwnerKind.IMPLEMENTATION);
|
||||
this.getter = resolvedGetCall == null ? null : codegen.typeMapper.mapToCallableMethod(getterDescriptor, false, OwnerKind.IMPLEMENTATION);
|
||||
this.codegen = codegen;
|
||||
this.frame = codegen.myFrameMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -505,69 +522,164 @@ public abstract class StackValue {
|
||||
|
||||
@Override
|
||||
public void dupReceiver(InstructionAdapter v) {
|
||||
int size = calcSize();
|
||||
|
||||
if(size == 2) {
|
||||
if(isStandardStack(resolvedGetCall) && isStandardStack(resolvedSetCall)) {
|
||||
v.dup2(); // collection and index
|
||||
}
|
||||
else {
|
||||
Method signature = getter.getSignature();
|
||||
Type[] argumentTypes = signature.getArgumentTypes();
|
||||
|
||||
int firstIndex = frame.enterTemp();
|
||||
int lastIndex = firstIndex;
|
||||
int size = 0;
|
||||
int lastIndex = frame.enterTemp();
|
||||
frame.leaveTemp();
|
||||
|
||||
for(int i = argumentTypes.length-1; i >= 0; i--) {
|
||||
int sz = argumentTypes[i].getSize();
|
||||
// indexes
|
||||
List<ValueParameterDescriptor> valueParameters = resolvedGetCall.getResultingDescriptor().getValueParameters();
|
||||
int firstParamIndex = -1;
|
||||
for(int i = valueParameters.size()-1; i >= 0; --i) {
|
||||
Type type = codegen.typeMapper.mapType(valueParameters.get(i).getOutType());
|
||||
int sz = type.getSize();
|
||||
frame.enterTemp(sz);
|
||||
lastIndex += sz;
|
||||
v.store(lastIndex-sz, argumentTypes[i]);
|
||||
size += sz;
|
||||
v.store((firstParamIndex = lastIndex)-sz, type);
|
||||
}
|
||||
|
||||
if(getter.getInvokeOpcode() != Opcodes.INVOKESTATIC) {
|
||||
List<TypeParameterDescriptor> typeParameters = resolvedGetCall.getResultingDescriptor().getTypeParameters();
|
||||
int firstTypeParamIndex = -1;
|
||||
for(int i = typeParameters.size()-1; i >= 0; --i) {
|
||||
if(typeParameters.get(i).isReified()) {
|
||||
frame.enterTemp();
|
||||
lastIndex++;
|
||||
size++;
|
||||
v.store(firstTypeParamIndex = lastIndex-1, JetTypeMapper.TYPE_OBJECT);
|
||||
}
|
||||
}
|
||||
|
||||
ReceiverDescriptor receiverParameter = resolvedGetCall.getReceiverArgument();
|
||||
int receiverIndex = -1;
|
||||
if(receiverParameter.exists()) {
|
||||
Type type = codegen.typeMapper.mapType(receiverParameter.getType());
|
||||
int sz = type.getSize();
|
||||
frame.enterTemp(sz);
|
||||
lastIndex += sz;
|
||||
size += sz;
|
||||
v.store((receiverIndex = lastIndex)-sz, type);
|
||||
}
|
||||
|
||||
ReceiverDescriptor thisObject = resolvedGetCall.getThisObject();
|
||||
int thisIndex = -1;
|
||||
if(thisObject.exists()) {
|
||||
frame.enterTemp();
|
||||
lastIndex++;
|
||||
v.store(lastIndex-1, JetTypeMapper.TYPE_OBJECT);
|
||||
size++;
|
||||
v.store((thisIndex = lastIndex)-1, JetTypeMapper.TYPE_OBJECT);
|
||||
}
|
||||
|
||||
// for setter
|
||||
|
||||
int realReceiverIndex;
|
||||
Type realReceiverType;
|
||||
if(thisIndex != -1) {
|
||||
if(receiverIndex != -1) {
|
||||
realReceiverIndex = receiverIndex;
|
||||
realReceiverType = codegen.typeMapper.mapType(receiverParameter.getType());
|
||||
}
|
||||
else {
|
||||
realReceiverIndex = thisIndex;
|
||||
realReceiverType = JetTypeMapper.TYPE_OBJECT;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(receiverIndex != -1) {
|
||||
realReceiverType = codegen.typeMapper.mapType(receiverParameter.getType());
|
||||
realReceiverIndex = receiverIndex;
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
firstIndex = lastIndex;
|
||||
int curIndex = lastIndex;
|
||||
if(getter.getInvokeOpcode() != Opcodes.INVOKESTATIC) {
|
||||
v.load(curIndex-1, JetTypeMapper.TYPE_OBJECT);
|
||||
curIndex--;
|
||||
if(resolvedSetCall.getThisObject().exists()) {
|
||||
if(resolvedSetCall.getReceiverArgument().exists()) {
|
||||
codegen.generateFromResolvedCall(resolvedSetCall.getThisObject());
|
||||
}
|
||||
v.load(realReceiverIndex - realReceiverType.getSize(), realReceiverType);
|
||||
}
|
||||
else {
|
||||
if(resolvedSetCall.getReceiverArgument().exists()) {
|
||||
v.load(realReceiverIndex - realReceiverType.getSize(), realReceiverType);
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i != argumentTypes.length; i++) {
|
||||
int sz = argumentTypes[i].getSize();
|
||||
v.load(curIndex-sz, argumentTypes[i]);
|
||||
curIndex -= sz;
|
||||
for (TypeParameterDescriptor typeParameterDescriptor : setterDescriptor.getOriginal().getTypeParameters()) {
|
||||
if(typeParameterDescriptor.isReified()) {
|
||||
codegen.generateTypeInfo(resolvedSetCall.getTypeArguments().get(typeParameterDescriptor));
|
||||
}
|
||||
}
|
||||
|
||||
curIndex = firstIndex;
|
||||
if(getter.getInvokeOpcode() != Opcodes.INVOKESTATIC) {
|
||||
v.load(curIndex-1, JetTypeMapper.TYPE_OBJECT);
|
||||
curIndex--;
|
||||
int index = firstParamIndex;
|
||||
for(int i = 0; i != valueParameters.size(); ++i) {
|
||||
Type type = codegen.typeMapper.mapType(valueParameters.get(i).getOutType());
|
||||
int sz = type.getSize();
|
||||
v.load(index-sz, type);
|
||||
index -= sz;
|
||||
}
|
||||
|
||||
for(int i = 0; i != argumentTypes.length; i++) {
|
||||
int sz = argumentTypes[i].getSize();
|
||||
v.load(curIndex-sz, argumentTypes[i]);
|
||||
curIndex -= sz;
|
||||
// restoring original
|
||||
if(thisIndex != -1) {
|
||||
v.load(thisIndex-1, JetTypeMapper.TYPE_OBJECT);
|
||||
}
|
||||
|
||||
if(receiverIndex != -1) {
|
||||
Type type = codegen.typeMapper.mapType(receiverParameter.getType());
|
||||
v.load(receiverIndex-type.getSize(), type);
|
||||
}
|
||||
|
||||
if(firstTypeParamIndex != -1) {
|
||||
index = firstTypeParamIndex;
|
||||
for(int i = 0; i != typeParameters.size(); ++i) {
|
||||
if(typeParameters.get(i).isReified()) {
|
||||
v.load(index-1, JetTypeMapper.TYPE_OBJECT);
|
||||
index--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
index = firstParamIndex;
|
||||
for(int i = 0; i != valueParameters.size(); ++i) {
|
||||
Type type = codegen.typeMapper.mapType(valueParameters.get(i).getOutType());
|
||||
int sz = type.getSize();
|
||||
v.load(index-sz, type);
|
||||
index -= sz;
|
||||
}
|
||||
|
||||
frame.leaveTemp(size);
|
||||
}
|
||||
}
|
||||
|
||||
private int calcSize() {
|
||||
assert getter != null;
|
||||
int size = getter.getInvokeOpcode() == Opcodes.INVOKESTATIC ? 0 : 1;
|
||||
Method signature = getter.getSignature();
|
||||
Type[] argumentTypes = signature.getArgumentTypes();
|
||||
for(int i = 0; i != argumentTypes.length; ++i)
|
||||
size += argumentTypes[i].getSize();
|
||||
return size;
|
||||
private boolean isStandardStack(ResolvedCall call) {
|
||||
for (TypeParameterDescriptor typeParameterDescriptor : call.getResultingDescriptor().getTypeParameters()) {
|
||||
if(typeParameterDescriptor.isReified())
|
||||
return false;
|
||||
}
|
||||
|
||||
if(call.getResultingDescriptor().getValueParameters().size() != 1)
|
||||
return false;
|
||||
|
||||
if(codegen.typeMapper.mapType(call.getResultingDescriptor().getValueParameters().get(0).getOutType()).getSize() != 1)
|
||||
return false;
|
||||
|
||||
if(call.getThisObject().exists()) {
|
||||
if(call.getReceiverArgument().exists())
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if(codegen.typeMapper.mapType(call.getResultingDescriptor().getReceiverParameter().getType()).getSize() != 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import java.util.HashMap
|
||||
import java.util.Map
|
||||
import java.io.*
|
||||
|
||||
fun <K, V> Map<K, V>.set(key : K, value : V) = put(key, value)
|
||||
|
||||
fun box() : String {
|
||||
|
||||
val commands : Map<String, String> = HashMap()
|
||||
|
||||
commands["c1"] = "239"
|
||||
if(commands["c1"] != "239") return "fail"
|
||||
|
||||
commands["c1"] += "932"
|
||||
return if(commands["c1"] == "239932") "OK" else "fail"
|
||||
}
|
||||
@@ -202,4 +202,10 @@ public class ClassGenTest extends CodegenTestCase {
|
||||
System.out.println(generateToText());
|
||||
blackBox();
|
||||
}
|
||||
|
||||
public void testKt504 () throws Exception {
|
||||
loadFile("regressions/kt504.jet");
|
||||
System.out.println(generateToText());
|
||||
blackBox();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user