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