pass type arguments to generic functions

This commit is contained in:
Dmitry Jemerov
2011-06-30 18:57:30 +02:00
parent 1bd4eaf474
commit d4453c055e
8 changed files with 73 additions and 23 deletions
@@ -123,7 +123,8 @@ public class ClosureCodegen {
private void generateBody(FunctionDescriptor funDescriptor, ClassVisitor cv, List<JetElement> body) {
FunctionCodegen fc = new FunctionCodegen(null, cv, state);
fc.generatedMethod(body, OwnerKind.IMPLEMENTATION, invokeSignature(funDescriptor), funDescriptor.getReceiverType(), funDescriptor.getValueParameters(), null);
fc.generatedMethod(body, OwnerKind.IMPLEMENTATION, invokeSignature(funDescriptor), funDescriptor.getReceiverType(),
funDescriptor.getValueParameters(), funDescriptor.getTypeParameters(), null);
}
private void generateBridge(String className, FunctionDescriptor funDescriptor, ClassVisitor cv) {
@@ -29,6 +29,7 @@ import java.util.*;
/**
* @author max
* @author yole
*/
public class ExpressionCodegen extends JetVisitor {
private static final String CLASS_OBJECT = "java/lang/Object";
@@ -83,6 +84,7 @@ public class ExpressionCodegen extends JetVisitor {
private final BindingContext bindingContext;
private final StackValue thisExpression;
private final Map<ClassDescriptor, StackValue> outerThisExpressions = new HashMap<ClassDescriptor, StackValue>();
private final Map<TypeParameterDescriptor, StackValue> typeParameterExpressions = new HashMap<TypeParameterDescriptor, StackValue>();
public ExpressionCodegen(MethodVisitor v,
FrameMap myMap,
@@ -106,6 +108,10 @@ public class ExpressionCodegen extends JetVisitor {
outerThisExpressions.put(outer, expression);
}
public void addTypeParameter(TypeParameterDescriptor typeParameter, StackValue expression) {
typeParameterExpressions.put(typeParameter, expression);
}
static void loadTypeInfo(JetTypeMapper typeMapper, ClassDescriptor descriptor, InstructionAdapter v) {
String owner = typeMapper.jvmName(descriptor, OwnerKind.IMPLEMENTATION);
if (descriptor.getTypeConstructor().getParameters().size() > 0) {
@@ -785,6 +791,7 @@ public class ExpressionCodegen extends JetVisitor {
ensureReceiverOnStack(expression, null);
}
pushMethodArguments(expression, methodDescriptor);
pushTypeArguments(expression);
final String owner = NamespaceCodegen.getJVMClassName(DescriptorRenderer.getFQName(functionParent));
v.invokestatic(owner, methodDescriptor.getName(), methodDescriptor.getDescriptor());
}
@@ -792,6 +799,7 @@ public class ExpressionCodegen extends JetVisitor {
ClassDescriptor containingClass = (ClassDescriptor) functionParent;
ensureReceiverOnStack(expression, containingClass);
pushMethodArguments(expression, methodDescriptor);
pushTypeArguments(expression);
final String owner = typeMapper.jvmName(containingClass, OwnerKind.INTERFACE);
int opcode = typeMapper.isInterface(containingClass, OwnerKind.INTERFACE)
? Opcodes.INVOKEINTERFACE
@@ -1456,12 +1464,7 @@ public class ExpressionCodegen extends JetVisitor {
Method method = typeMapper.mapConstructorSignature((ConstructorDescriptor) constructorDescriptor, OwnerKind.IMPLEMENTATION);
pushMethodArguments(expression, method);
for (JetTypeProjection jetTypeArgument : expression.getTypeArguments()) {
JetType typeArgument = bindingContext.resolveTypeReference(jetTypeArgument.getTypeReference());
// TODO is the makeNullable() call correct here?
ClassCodegen.newTypeInfo(v, typeArgument.isNullable(), typeMapper.mapType(TypeUtils.makeNullable(typeArgument)));
}
pushTypeArguments(expression);
v.invokespecial(JetTypeMapper.jvmNameForImplementation(classDecl), "<init>", method.getDescriptor());
}
@@ -1472,6 +1475,14 @@ public class ExpressionCodegen extends JetVisitor {
myStack.push(StackValue.onStack(type));
}
private void pushTypeArguments(JetCall expression) {
for (JetTypeProjection jetTypeArgument : expression.getTypeArguments()) {
JetType typeArgument = bindingContext.resolveTypeReference(jetTypeArgument.getTypeReference());
// TODO is the makeNullable() call correct here?
ClassCodegen.newTypeInfo(v, typeArgument.isNullable(), typeMapper.mapType(TypeUtils.makeNullable(typeArgument)));
}
}
private void pushOuterClassArguments(ClassDescriptor classDecl) {
if (classDecl.getContainingDeclaration() instanceof ClassDescriptor) {
v.load(0, JetTypeMapper.jetImplementationType(classDecl));
@@ -1709,7 +1720,7 @@ public class ExpressionCodegen extends JetVisitor {
private void generateTypeInfo(JetType jetType) {
DeclarationDescriptor declarationDescriptor = jetType.getConstructor().getDeclarationDescriptor();
if (declarationDescriptor instanceof TypeParameterDescriptor) {
loadTypeParameterTypeInfo(declarationDescriptor);
loadTypeParameterTypeInfo((TypeParameterDescriptor) declarationDescriptor);
return;
}
@@ -1742,11 +1753,16 @@ public class ExpressionCodegen extends JetVisitor {
}
}
private void loadTypeParameterTypeInfo(DeclarationDescriptor declarationDescriptor) {
DeclarationDescriptor containingDeclaration = declarationDescriptor.getContainingDeclaration();
private void loadTypeParameterTypeInfo(TypeParameterDescriptor typeParameterDescriptor) {
final StackValue value = typeParameterExpressions.get(typeParameterDescriptor);
if (value != null) {
value.put(JetTypeMapper.TYPE_TYPEINFO, v);
return;
}
DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration();
if (containingDeclaration == contextType && contextType instanceof ClassDescriptor) {
loadTypeInfo(typeMapper, (ClassDescriptor) contextType, v);
v.iconst(((TypeParameterDescriptor) declarationDescriptor).getIndex());
v.iconst(typeParameterDescriptor.getIndex());
v.invokevirtual("jet/typeinfo/TypeInfo", "getTypeParameter", "(I)Ljet/typeinfo/TypeInfo;");
return;
}
@@ -2,6 +2,8 @@ package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
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.*;
import org.jetbrains.jet.lang.types.JetType;
@@ -17,6 +19,7 @@ import java.util.List;
/**
* @author max
* @author yole
*/
public class FunctionCodegen {
private final JetDeclaration owner;
@@ -33,21 +36,23 @@ public class FunctionCodegen {
final JetTypeReference receiverTypeRef = f.getReceiverTypeRef();
final JetType receiverType = receiverTypeRef == null ? null : state.getBindingContext().resolveTypeReference(receiverTypeRef);
Method method = state.getTypeMapper().mapSignature(f);
List<ValueParameterDescriptor> paramDescrs = state.getBindingContext().getFunctionDescriptor(f).getValueParameters();
generateMethod(f, kind, method, receiverType, paramDescrs);
final FunctionDescriptor functionDescriptor = state.getBindingContext().getFunctionDescriptor(f);
generateMethod(f, kind, method, receiverType, functionDescriptor.getValueParameters(),
functionDescriptor.getTypeParameters());
}
public void generateMethod(JetDeclarationWithBody f,
OwnerKind kind,
Method jvmSignature,
@Nullable JetType receiverType,
List<ValueParameterDescriptor> paramDescrs) {
List<ValueParameterDescriptor> paramDescrs,
List<TypeParameterDescriptor> typeParameters) {
final DeclarationDescriptor contextDesc = owner instanceof JetClassOrObject
? state.getBindingContext().getClassDescriptor((JetClassOrObject) owner)
: state.getBindingContext().getNamespaceDescriptor((JetNamespace) owner);
final JetExpression bodyExpression = f.getBodyExpression();
final List<JetElement> bodyExpressions = bodyExpression != null ? Collections.<JetElement>singletonList(bodyExpression) : null;
generatedMethod(bodyExpressions, kind, jvmSignature, receiverType, paramDescrs, contextDesc);
generatedMethod(bodyExpressions, kind, jvmSignature, receiverType, paramDescrs, typeParameters, contextDesc);
}
public void generatedMethod(List<JetElement> bodyExpressions,
@@ -55,6 +60,7 @@ public class FunctionCodegen {
Method jvmSignature,
JetType receiverType,
List<ValueParameterDescriptor> paramDescrs,
List<TypeParameterDescriptor> typeParameters,
DeclarationDescriptor contextDesc)
{
int flags = Opcodes.ACC_PUBLIC; // TODO.
@@ -85,14 +91,22 @@ public class FunctionCodegen {
frameMap.enterTemp(); // Next slot for fake this
}
StackValue thisExpression = receiverType == null ? null : StackValue.local(thisIdx, state.getTypeMapper().mapType(receiverType));
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), contextDesc, kind, thisExpression, state);
int firstArg = thisIdx+1;
Type[] argTypes = jvmSignature.getArgumentTypes();
for (int i = 0; i < paramDescrs.size(); i++) {
ValueParameterDescriptor parameter = paramDescrs.get(i);
frameMap.enter(parameter, argTypes[i].getSize());
}
for (int i = 0; i < typeParameters.size(); i++) {
final TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
codegen.addTypeParameter(typeParameterDescriptor,
StackValue.local(firstArg + paramDescrs.size() + i, JetTypeMapper.TYPE_TYPEINFO));
frameMap.enterTemp();
}
StackValue thisExpression = receiverType == null ? null : StackValue.local(thisIdx, state.getTypeMapper().mapType(receiverType));
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), contextDesc, kind, thisExpression, state);
if (kind instanceof OwnerKind.DelegateKind) {
OwnerKind.DelegateKind dk = (OwnerKind.DelegateKind) kind;
InstructionAdapter iv = new InstructionAdapter(mv);
@@ -282,6 +282,9 @@ public class JetTypeMapper {
for (JetParameter parameter : parameters) {
parameterTypes.add(mapType(bindingContext.resolveTypeReference(parameter.getTypeReference())));
}
for (JetTypeParameter p: f.getTypeParameters()) {
parameterTypes.add(TYPE_TYPEINFO);
}
final JetTypeReference returnTypeRef = f.getReturnTypeRef();
Type returnType;
if (returnTypeRef == null) {
@@ -1,10 +1,7 @@
package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertySetterDescriptor;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lexer.JetTokens;
@@ -97,7 +94,9 @@ public class PropertyCodegen {
if (getter != null) {
if (getter.getBodyExpression() != null) {
functionCodegen.generateMethod(getter, kind, mapper.mapGetterSignature(propertyDescriptor),
null, Collections.<ValueParameterDescriptor>emptyList());
null,
Collections.<ValueParameterDescriptor>emptyList(),
Collections.<TypeParameterDescriptor>emptyList());
}
else if (!getter.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
generateDefaultGetter(p, getter, kind);
@@ -119,7 +118,9 @@ public class PropertyCodegen {
final PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter();
assert setterDescriptor != null;
functionCodegen.generateMethod(setter, kind, mapper.mapSetterSignature(propertyDescriptor),
null, setterDescriptor.getValueParameters());
null,
setterDescriptor.getValueParameters(),
Collections.<TypeParameterDescriptor>emptyList());
}
else if (!p.hasModifier(JetTokens.PRIVATE_KEYWORD)) {
generateDefaultSetter(p, setter, kind);
@@ -0,0 +1,10 @@
class Foo() { }
class Bar() { }
fun isInstance<T>(obj: Any?) = obj is T
fun box(): String {
if (! isInstance<Foo>(Foo())) return "fail 1"
if (isInstance<Bar>(Foo())) return "fail 2"
return "OK"
}
@@ -96,6 +96,10 @@ public class TypeInfoTest extends CodegenTestCase {
blackBoxFile("typeInfo/nullability.jet");
}
public void testGenericFunction() throws Exception {
blackBoxFile("typeInfo/genericFunction.jet");
}
private Runnable newRunnable() {
return new Runnable() {
@Override
+1
View File
@@ -6,6 +6,7 @@ import java.util.Arrays;
/**
* @author abreslav
* @author yole
*/
public class TypeInfo<T> implements JetObject {
private TypeInfo<?> typeInfo;