Constructors in objects

This commit is contained in:
Andrey Breslav
2011-09-23 19:36:52 +04:00
13 changed files with 178 additions and 134 deletions
@@ -2,22 +2,26 @@ package org.jetbrains.jet.codegen;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassKind;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.JetType;
/**
* @author abreslav
* @author alex.tkachman
*/
public class CodegenUtil {
public static boolean isInterface(DeclarationDescriptor descriptor, BindingContext bindingContext) {
PsiElement psiElement = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, descriptor);
if(psiElement instanceof JetClass) {
return ((JetClass)psiElement).isTrait();
}
if(psiElement instanceof PsiClass) {
return ((PsiClass)psiElement).isInterface();
}
return false;
private CodegenUtil() {
}
public static boolean isInterface(DeclarationDescriptor descriptor) {
return descriptor instanceof ClassDescriptor && ((ClassDescriptor)descriptor).getKind() == ClassKind.TRAIT;
}
public static boolean isInterface(JetType type) {
return isInterface(type.getConstructor().getDeclarationDescriptor());
}
}
@@ -721,7 +721,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
receiver.put(receiverType != null ? typeMapper.mapType(receiverType) : JetTypeMapper.TYPE_OBJECT, v);
if(receiverType != null) {
ClassDescriptor propReceiverDescriptor = (ClassDescriptor) propertyDescriptor.getContainingDeclaration();
if(!CodegenUtil.isInterface(propReceiverDescriptor, bindingContext) && CodegenUtil.isInterface(receiverType.getConstructor().getDeclarationDescriptor(), bindingContext)) {
if(!CodegenUtil.isInterface(propReceiverDescriptor) && CodegenUtil.isInterface(receiverType.getConstructor().getDeclarationDescriptor())) {
// I hope it happens only in case of required super class for traits
v.checkcast(typeMapper.mapType(propReceiverDescriptor.getDefaultType()));
}
@@ -2026,7 +2026,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
JetType defaultType = descriptor.getDefaultType();
Type ownerType = typeMapper.mapType(defaultType);
ownerType = JetTypeMapper.boxType(ownerType);
if(!typeMapper.isInterface(descriptor)) {
if(!CodegenUtil.isInterface(descriptor)) {
if (descriptor.getTypeConstructor().getParameters().size() > 0) {
v.load(0, JetTypeMapper.TYPE_OBJECT);
v.getfield(ownerType.getInternalName(), "$typeInfo", "Ljet/typeinfo/TypeInfo;");
@@ -8,7 +8,6 @@ import org.jetbrains.jet.lang.psi.JetDeclarationWithBody;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -47,33 +46,6 @@ public class FunctionCodegen {
generatedMethod(bodyExpression, jvmMethod, funContext, functionDescriptor);
}
private void generateBridgeMethod(Method function, Method overriden)
{
int flags = Opcodes.ACC_PUBLIC; // TODO.
final MethodVisitor mv = v.visitMethod(flags, function.getName(), overriden.getDescriptor(), null, null);
mv.visitCode();
Type[] argTypes = function.getArgumentTypes();
InstructionAdapter iv = new InstructionAdapter(mv);
iv.load(0, JetTypeMapper.TYPE_OBJECT);
for (int i = 0, reg = 1; i < argTypes.length; i++) {
Type argType = argTypes[i];
iv.load(reg, argType);
//noinspection AssignmentToForLoopParameter
reg += argType.getSize();
}
iv.invokevirtual(state.getTypeMapper().jvmName((ClassDescriptor) owner.getContextDescriptor(), OwnerKind.IMPLEMENTATION), function.getName(), function.getDescriptor());
if(JetTypeMapper.isPrimitive(function.getReturnType()) && !JetTypeMapper.isPrimitive(overriden.getReturnType()))
StackValue.valueOf(iv, function.getReturnType());
if(function.getReturnType() == Type.VOID_TYPE)
iv.aconst(null);
iv.areturn(overriden.getReturnType());
mv.visitMaxs(0, 0);
mv.visitEnd();
}
private void generatedMethod(JetExpression bodyExpressions,
Method jvmSignature,
ClassContext context,
@@ -86,10 +58,13 @@ public class FunctionCodegen {
OwnerKind kind = context.getContextKind();
if(kind == OwnerKind.TRAIT_IMPL && bodyExpressions == null)
return;
boolean isStatic = kind == OwnerKind.NAMESPACE || kind == OwnerKind.TRAIT_IMPL;
if (isStatic) flags |= Opcodes.ACC_STATIC;
boolean isAbstract = !isStatic && (bodyExpressions == null || CodegenUtil.isInterface(functionDescriptor.getContainingDeclaration(), state.getBindingContext()));
boolean isAbstract = !isStatic && (bodyExpressions == null || CodegenUtil.isInterface(functionDescriptor.getContainingDeclaration()));
if (isAbstract) flags |= Opcodes.ACC_ABSTRACT;
final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null);
@@ -122,21 +97,58 @@ public class FunctionCodegen {
iv.invokeinterface(dk.getOwnerClass(), jvmSignature.getName(), jvmSignature.getDescriptor());
iv.areturn(jvmSignature.getReturnType());
}
else if (!isAbstract) {
else {
codegen.returnExpression(bodyExpressions);
}
mv.visitMaxs(0, 0);
mv.visitEnd();
Set<? extends FunctionDescriptor> overriddenFunctions = functionDescriptor.getOverriddenDescriptors();
if(overriddenFunctions.size() > 0) {
for (FunctionDescriptor overriddenFunction : overriddenFunctions) {
// TODO should we check params here as well?
if(!TypeUtils.equalClasses(overriddenFunction.getOriginal().getReturnType(), functionDescriptor.getReturnType())) {
generateBridgeMethod(jvmSignature, state.getTypeMapper().mapSignature(overriddenFunction.getName(), overriddenFunction.getOriginal()));
}
}
generateBridgeIfNeeded(owner, state, v, jvmSignature, functionDescriptor, kind);
}
}
static void generateBridgeIfNeeded(ClassContext owner, GenerationState state, ClassVisitor v, Method jvmSignature, FunctionDescriptor functionDescriptor, OwnerKind kind) {
Set<? extends FunctionDescriptor> overriddenFunctions = functionDescriptor.getOverriddenDescriptors();
if(kind != OwnerKind.TRAIT_IMPL) {
for (FunctionDescriptor overriddenFunction : overriddenFunctions) {
// TODO should we check params here as well?
checkOverride(owner, state, v, jvmSignature, functionDescriptor, overriddenFunction);
}
checkOverride(owner, state, v, jvmSignature, functionDescriptor, functionDescriptor.getOriginal());
}
}
private static void checkOverride(ClassContext owner, GenerationState state, ClassVisitor v, Method jvmSignature, FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenFunction) {
Type type1 = state.getTypeMapper().mapType(overriddenFunction.getOriginal().getReturnType());
Type type2 = state.getTypeMapper().mapType(functionDescriptor.getReturnType());
if(!type1.equals(type2)) {
Method overriden = state.getTypeMapper().mapSignature(overriddenFunction.getName(), overriddenFunction.getOriginal());
int flags = Opcodes.ACC_PUBLIC; // TODO.
final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), overriden.getDescriptor(), null, null);
mv.visitCode();
Type[] argTypes = jvmSignature.getArgumentTypes();
InstructionAdapter iv = new InstructionAdapter(mv);
iv.load(0, JetTypeMapper.TYPE_OBJECT);
for (int i = 0, reg = 1; i < argTypes.length; i++) {
Type argType = argTypes[i];
iv.load(reg, argType);
if(argType.getSort() == Type.OBJECT) {
iv.checkcast(argType);
}
//noinspection AssignmentToForLoopParameter
reg += argType.getSize();
}
iv.invokevirtual(state.getTypeMapper().jvmName((ClassDescriptor) owner.getContextDescriptor(), OwnerKind.IMPLEMENTATION), jvmSignature.getName(), jvmSignature.getDescriptor());
if(JetTypeMapper.isPrimitive(jvmSignature.getReturnType()) && !JetTypeMapper.isPrimitive(overriden.getReturnType()))
StackValue.valueOf(iv, jvmSignature.getReturnType());
if(jvmSignature.getReturnType() == Type.VOID_TYPE)
iv.aconst(null);
iv.areturn(overriden.getReturnType());
mv.visitMaxs(0, 0);
mv.visitEnd();
}
}
@@ -6,6 +6,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.OverridingUtil;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
@@ -314,74 +315,60 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
if(!(myClass instanceof JetClass) || ((JetClass)myClass).isTrait() || ((JetClass)myClass).hasModifier(JetTokens.ABSTRACT_KEYWORD))
return;
HashSet<FunctionDescriptor> set = new HashSet<FunctionDescriptor>();
getAbstractMethods(descriptor.getDefaultType(), set);
for(FunctionDescriptor fun: set) {
int flags = Opcodes.ACC_PUBLIC; // TODO.
for (CallableDescriptor callableDescriptor : OverridingUtil.getEffectiveMembers(descriptor)) {
if(callableDescriptor instanceof FunctionDescriptor) {
FunctionDescriptor fun = (FunctionDescriptor) callableDescriptor;
DeclarationDescriptor containingDeclaration = fun.getContainingDeclaration();
if(containingDeclaration instanceof ClassDescriptor) {
ClassDescriptor declaration = (ClassDescriptor) containingDeclaration;
PsiElement psiElement = state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, declaration);
if(psiElement instanceof JetClass) {
JetClass jetClass = (JetClass) psiElement;
if(jetClass.isTrait()) {
int flags = Opcodes.ACC_PUBLIC; // TODO.
Method function = state.getTypeMapper().mapSignature(fun.getName(), fun);
Method function = state.getTypeMapper().mapSignature(fun.getName(), fun);
Method functionOriginal = state.getTypeMapper().mapSignature(fun.getName(), fun.getOriginal());
final MethodVisitor mv = v.visitMethod(flags, function.getName(), function.getDescriptor(), null, null);
mv.visitCode();
final MethodVisitor mv = v.visitMethod(flags, function.getName(), function.getDescriptor(), null, null);
mv.visitCode();
codegen.generateThisOrOuter(descriptor);
codegen.generateThisOrOuter(descriptor);
Type[] argTypes = function.getArgumentTypes();
InstructionAdapter iv = new InstructionAdapter(mv);
iv.load(0, JetTypeMapper.TYPE_OBJECT);
for (int i = 0, reg = 1; i < argTypes.length; i++) {
Type argType = argTypes[i];
iv.load(reg, argType);
//noinspection AssignmentToForLoopParameter
reg += argType.getSize();
}
Type[] argTypes = function.getArgumentTypes();
InstructionAdapter iv = new InstructionAdapter(mv);
iv.load(0, JetTypeMapper.TYPE_OBJECT);
for (int i = 0, reg = 1; i < argTypes.length; i++) {
Type argType = argTypes[i];
iv.load(reg, argType);
//noinspection AssignmentToForLoopParameter
reg += argType.getSize();
}
ClassDescriptor containingDeclaration = (ClassDescriptor) fun.getContainingDeclaration();
JetType jetType = TraitImplBodyCodegen.getSuperClass(containingDeclaration, state.getBindingContext());
Type type = state.getTypeMapper().mapType(jetType);
if(type.getInternalName().equals("java/lang/Object")) {
jetType = containingDeclaration.getDefaultType();
type = state.getTypeMapper().mapType(jetType);
}
JetType jetType = TraitImplBodyCodegen.getSuperClass(declaration, state.getBindingContext());
Type type = state.getTypeMapper().mapType(jetType);
if(type.getInternalName().equals("java/lang/Object")) {
jetType = declaration.getDefaultType();
type = state.getTypeMapper().mapType(jetType);
}
String fdescriptor = function.getDescriptor().replace("(","(" + type.getDescriptor());
iv.invokestatic(state.getTypeMapper().jvmName((ClassDescriptor) fun.getContainingDeclaration(), OwnerKind.TRAIT_IMPL), function.getName(), fdescriptor);
iv.areturn(function.getReturnType());
mv.visitMaxs(0, 0);
mv.visitEnd();
}
}
private void getAbstractMethods(JetType type, Set<FunctionDescriptor> set) {
if(type.equals(JetStandardClasses.getAny())) {
return;
}
String fdescriptor = functionOriginal.getDescriptor().replace("(","(" + type.getDescriptor());
iv.invokestatic(state.getTypeMapper().jvmName((ClassDescriptor) fun.getContainingDeclaration(), OwnerKind.TRAIT_IMPL), function.getName(), fdescriptor);
if(function.getReturnType().getSort() == Type.OBJECT) {
iv.checkcast(function.getReturnType());
}
iv.areturn(function.getReturnType());
mv.visitMaxs(0, 0);
mv.visitEnd();
for(JetType superType : type.getConstructor().getSupertypes()) {
getAbstractMethods(superType, set);
}
PsiElement psiElement = state.getBindingContext().get(BindingContext.DESCRIPTOR_TO_DECLARATION, type.getConstructor().getDeclarationDescriptor());
if(psiElement instanceof JetClass) {
JetClass jetClass = (JetClass) psiElement;
for(JetDeclaration decl : jetClass.getDeclarations()) {
if(decl instanceof JetNamedFunction) {
JetNamedFunction jetNamedFunction = (JetNamedFunction) decl;
FunctionDescriptor funDescriptor = state.getBindingContext().get(BindingContext.FUNCTION, decl);
set.removeAll(funDescriptor.getOverriddenDescriptors());
if(jetNamedFunction.getBodyExpression() == null || jetClass.isTrait()) {
set.add(funDescriptor);
FunctionCodegen.generateBridgeIfNeeded(context, state, v, function, fun, kind);
}
}
}
}
}
else if(psiElement instanceof PsiClass) {
// todo
PsiClass psiClass = (PsiClass) psiElement;
}
}
@Nullable
private ClassDescriptor getOuterClassDescriptor() {
if (myClass.getParent() instanceof JetClassObject) {
@@ -762,9 +749,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
return false;
}
public boolean hasDerivedTypeInfoField(JetType type, boolean exceptOwn) {
public static boolean hasDerivedTypeInfoField(JetType type, boolean exceptOwn) {
if(!exceptOwn) {
if(!state.getTypeMapper().isInterface((ClassDescriptor) type.getConstructor().getDeclarationDescriptor()))
if(!CodegenUtil.isInterface(type))
if(isParametrizedClass(type))
return true;
}
@@ -222,14 +222,6 @@ public class JetTypeMapper {
return jvmName(descriptor, OwnerKind.IMPLEMENTATION);
}
public boolean isInterface(ClassDescriptor jetClass) {
PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, jetClass);
if (declaration instanceof JetObjectDeclaration) {
return false;
}
return declaration instanceof JetClass && ((JetClass) declaration).isTrait();
}
private static String jetJvmName(ClassDescriptor jetClass, OwnerKind kind) {
if (jetClass.getKind() == ClassKind.OBJECT) {
return jvmNameForImplementation(jetClass);
@@ -496,7 +488,7 @@ public class JetTypeMapper {
else if (functionParent instanceof ClassDescriptor) {
ClassDescriptor containingClass = (ClassDescriptor) functionParent;
owner = jvmName(containingClass, OwnerKind.IMPLEMENTATION);
invokeOpcode = isInterface(containingClass)
invokeOpcode = CodegenUtil.isInterface(containingClass)
? Opcodes.INVOKEINTERFACE
: Opcodes.INVOKEVIRTUAL;
needsReceiver = true;
@@ -1,8 +0,0 @@
package org.jetbrains.jet.codegen;
/**
* @author max
*/
public class MethodCodeGen {
}
@@ -2,9 +2,7 @@ package org.jetbrains.jet.codegen;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
import org.jetbrains.jet.lang.descriptors.PropertySetterDescriptor;
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.lang.resolve.constants.CompileTimeConstant;
@@ -52,6 +50,10 @@ public class PropertyCodegen {
private void generateBackingField(JetProperty p, PropertyDescriptor propertyDescriptor) {
if (state.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
if(CodegenUtil.isInterface(containingDeclaration))
return;
Object value = null;
final JetExpression initializer = p.getInitializer();
if (initializer != null) {
@@ -131,7 +131,7 @@ public class DeclarationResolver {
if (!klass.hasPrimaryConstructor() && classDescriptor.getKind() != ClassKind.OBJECT) return;
if (classDescriptor.getKind() == ClassKind.TRAIT) {
// context.getTrace().getErrorHandler().genericError(klass.getPrimaryConstructorParameterList().getNode(), "A trait may not have a constructor");
// context.getTrace().getErrorHandler().genericError(klass.getPrimaryConstructorParameterList().getNode(), "A trait may not have a constructor");
context.getTrace().report(CONSTRUCTOR_IN_TRAIT.on(klass.getPrimaryConstructorParameterList()));
}
@@ -18,6 +18,9 @@ import java.util.Set;
*/
public class OverridingUtil {
private OverridingUtil() {
}
public static Set<CallableDescriptor> getEffectiveMembers(@NotNull ClassDescriptor classDescriptor) {
Collection<DeclarationDescriptor> allDescriptors = classDescriptor.getDefaultType().getMemberScope().getAllDescriptors();
Set<CallableDescriptor> allMembers = Sets.newLinkedHashSet();
@@ -31,7 +31,7 @@ public class TypeProjection {
@Override
public String toString() {
if (projection == Variance.INVARIANT) {
return type + "";
return type.toString();
}
return projection + " " + type;
}
+44
View File
@@ -0,0 +1,44 @@
trait ISized {
val size : Int
}
trait ReadOnlyArray<out T> : ISized, Iterable<T> {
fun get(index : Int) : T
override fun iterator () : Iterator<T> = object : Iterator<T> {
private var index = 0
override fun hasNext() : Boolean = index < size
val next : T
get() = get(index++)
}
}
trait WriteOnlyArray<in T> : ISized {
fun set(index : Int, value : T) : Unit
fun set(from: Int, count: Int, value: T) {
for(i in 0..(count-1)) {
set(i, value)
}
}
}
class MutableArray<T>(length: Int) : ReadOnlyArray<T>, WriteOnlyArray<T> {
private val array = Array<T>(length)
override fun get(index : Int) : T = array[index]
override fun set(index : Int, value : T) : Unit { array[index] = value }
override val size : Int
get() = array.size
}
fun box() : String {
var a = MutableArray<Int> (4)
a [0] = 10
a.set(1, 2, 13)
a [3] = 40
return "OK"
}
@@ -20,4 +20,9 @@ public class TraitsTest extends CodegenTestCase {
blackBoxFile("traits/multiple.jet");
System.out.println(generateToText());
}
public void testStdlib () throws Exception {
blackBoxFile("traits/stdlib.jet");
System.out.println(generateToText());
}
}
+8 -5
View File
@@ -1,6 +1,5 @@
package jet.typeinfo;
import com.sun.org.apache.bcel.internal.generic.MethodGen;
import jet.JetObject;
import jet.Tuple0;
@@ -92,7 +91,7 @@ public abstract class TypeInfo<T> implements JetObject {
nullable = false;
}
public TypeInfoVar(boolean nullable, Integer varIndex) {
public TypeInfoVar(boolean nullable, int varIndex) {
this.nullable = nullable;
this.varIndex = varIndex;
}
@@ -474,11 +473,12 @@ public abstract class TypeInfo<T> implements JetObject {
public List<TypeInfoProjection> parseVars() {
List<TypeInfoProjection> list = null;
while(cur != string.length && string[cur] == 'T') {
while(cur < string.length && string[cur] == 'T') {
if(list == null) {
list = new LinkedList<TypeInfoProjection>();
variables = new HashMap<String, Integer>();
}
cur++;
list.add(parseVar());
}
return list == null ? Collections.<TypeInfoProjection>emptyList() : list;
@@ -508,7 +508,7 @@ public abstract class TypeInfo<T> implements JetObject {
}
private String parseName() {
int c = ++cur; // skip 'T'
int c = cur;
while (string[c] != ';') {
c++;
}
@@ -522,7 +522,7 @@ public abstract class TypeInfo<T> implements JetObject {
cur += 3;
return TypeInfoVariance.IN_VARIANCE;
}
else if (string[cur] == 'o' && string[cur+1] == 'u' && string[cur+2] == 't' && string[cur+2] == ' ') {
else if (string[cur] == 'o' && string[cur+1] == 'u' && string[cur+2] == 't' && string[cur+3] == ' ') {
cur += 4;
return TypeInfoVariance.OUT_VARIANCE;
}
@@ -545,6 +545,7 @@ public abstract class TypeInfo<T> implements JetObject {
private TypeInfo parseType() {
switch (string[cur]) {
case 'L':
cur++;
String name = parseName();
Class<?> aClass;
try {
@@ -572,6 +573,7 @@ public abstract class TypeInfo<T> implements JetObject {
return new TypeInfoImpl(aClass, nullable,proj.toArray(new TypeInfoProjection[proj.size()]));
case 'T':
cur++;
return parseTypeVar();
default:
@@ -580,6 +582,7 @@ public abstract class TypeInfo<T> implements JetObject {
}
private TypeInfo parseTypeVar() {
TypeInfoVariance variance = parseVariance();
String name = parseName();
boolean nullable = false;
if(string[cur] == '?') {