1st test for traits work

This commit is contained in:
Alex Tkachman
2011-09-12 09:26:50 +03:00
parent 24dc0fd11e
commit 60ab760d4a
14 changed files with 174 additions and 43 deletions
+6
View File
@@ -23,10 +23,16 @@
</option>
<envs />
<patterns />
<RunnerSettings RunnerId="Debug">
<option name="DEBUG_PORT" value="53032" />
<option name="TRANSPORT" value="0" />
<option name="LOCAL" value="true" />
</RunnerSettings>
<RunnerSettings RunnerId="Profile ">
<option name="myExternalizedOptions" value="&#13;&#10;snapshots-dir=&#13;&#10;additional-options2=onexit\=snapshot&#13;&#10;" />
</RunnerSettings>
<RunnerSettings RunnerId="Run" />
<ConfigurationWrapper RunnerId="Debug" />
<ConfigurationWrapper RunnerId="Run" />
<method />
</configuration>
@@ -71,13 +71,17 @@ public abstract class ClassBodyCodegen {
}
else if (declaration instanceof JetNamedFunction) {
try {
functionCodegen.gen((JetNamedFunction) declaration);
genNamedFunction((JetNamedFunction) declaration, functionCodegen);
} catch (RuntimeException e) {
throw new RuntimeException("Error generating method " + myClass.getName() + "." + declaration.getName() + " in " + context, e);
}
}
}
protected void genNamedFunction(JetNamedFunction declaration, FunctionCodegen functionCodegen) {
functionCodegen.gen(declaration);
}
private void generatePrimaryConstructorProperties(PropertyCodegen propertyCodegen) {
OwnerKind kind = context.getContextKind();
for (JetParameter p : getPrimaryConstructorParameters()) {
@@ -90,7 +94,7 @@ public abstract class ClassBodyCodegen {
}
//noinspection ConstantConditions
if (!(kind instanceof OwnerKind.DelegateKind) && kind != OwnerKind.INTERFACE && state.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
if (!(kind instanceof OwnerKind.DelegateKind) && state.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
v.visitField(Opcodes.ACC_PRIVATE, p.getName(), state.getTypeMapper().mapType(propertyDescriptor.getOutType()).getDescriptor(), null, null);
}
}
@@ -9,6 +9,7 @@ import org.objectweb.asm.commons.InstructionAdapter;
/**
* @author max
* @author alex.tkachman
*/
public class ClassCodegen {
private final GenerationState state;
@@ -35,6 +36,11 @@ public class ClassCodegen {
ClassDescriptor descriptor = state.getBindingContext().get(BindingContext.CLASS, aClass);
ClassVisitor v = state.forClassImplementation(descriptor);
new ImplementationBodyCodegen(aClass, parentContext.intoClass(descriptor, kind), v, state).generate();
if(aClass instanceof JetClass && ((JetClass)aClass).isTrait()) {
v = state.forTraitImplementation(descriptor);
new TraitImplBodyCodegen(aClass, parentContext.intoClass(descriptor, OwnerKind.TRAIT_IMPL), v, state).generate();
}
}
@@ -914,7 +914,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
CallableMethod callableMethod;
if (declarationPsiElement instanceof PsiMethod || declarationPsiElement instanceof JetNamedFunction) {
callableMethod = typeMapper.mapToCallableMethod((PsiNamedElement) declarationPsiElement);
callableMethod = typeMapper.mapToCallableMethod((PsiNamedElement) declarationPsiElement, null);
}
else if (fd instanceof FunctionDescriptor) {
callableMethod = ClosureCodegen.asCallableMethod((FunctionDescriptor) fd);
@@ -1708,7 +1708,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
accessor = JetTypeMapper.mapToCallableMethod((PsiMethod) declaration);
}
else if (declaration instanceof JetNamedFunction) {
accessor = typeMapper.mapToCallableMethod((JetNamedFunction) declaration);
accessor = typeMapper.mapToCallableMethod((JetNamedFunction) declaration, null);
}
else {
throw new UnsupportedOperationException("unknown accessor type: " + declaration);
@@ -35,7 +35,7 @@ public class FunctionCodegen {
}
public void gen(JetNamedFunction f) {
Method method = state.getTypeMapper().mapToCallableMethod(f).getSignature();
Method method = state.getTypeMapper().mapToCallableMethod(f, owner.getContextKind()).getSignature();
final FunctionDescriptor functionDescriptor = state.getBindingContext().get(BindingContext.FUNCTION, f);
generateMethod(f, method, functionDescriptor);
}
@@ -86,10 +86,10 @@ public class FunctionCodegen {
OwnerKind kind = context.getContextKind();
boolean isStatic = kind == OwnerKind.NAMESPACE;
boolean isStatic = kind == OwnerKind.NAMESPACE || kind == OwnerKind.TRAIT_IMPL;
if (isStatic) flags |= Opcodes.ACC_STATIC;
boolean isAbstract = bodyExpressions == null;
boolean isAbstract = !isStatic && (bodyExpressions == null || TypeUtils.isInterface(functionDescriptor.getContainingDeclaration(), state.getBindingContext()));
if (isAbstract) flags |= Opcodes.ACC_ABSTRACT;
final MethodVisitor mv = v.visitMethod(flags, jvmSignature.getName(), jvmSignature.getDescriptor(), null, null);
@@ -70,8 +70,8 @@ public class GenerationState {
return factory.newVisitor(typeMapper.jvmName(aClass, OwnerKind.IMPLEMENTATION) + ".class");
}
public ClassVisitor forClassDelegatingImplementation(ClassDescriptor aClass) {
return factory.newVisitor(JetTypeMapper.jvmNameForDelegatingImplementation(aClass) + ".class");
public ClassVisitor forTraitImplementation(ClassDescriptor aClass) {
return factory.newVisitor(typeMapper.jvmName(aClass, OwnerKind.TRAIT_IMPL) + ".class");
}
public Pair<String, ClassVisitor> forAnonymousSubclass(JetExpression expression) {
@@ -7,6 +7,7 @@ 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;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.Variance;
import org.jetbrains.jet.lexer.JetTokens;
@@ -215,7 +216,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
return;
ConstructorDescriptor constructorDescriptor = state.getBindingContext().get(BindingContext.CONSTRUCTOR, myClass);
// if (constructorDescriptor == null && !(myClass instanceof JetObjectDeclaration) && !isEnum(myClass)) return;
Method method;
CallableMethod callableMethod;
@@ -302,6 +302,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
generateInitializers(codegen, iv);
generateTraitMethods(codegen);
int curParam = 0;
List<JetParameter> constructorParameters = getPrimaryConstructorParameters();
for (JetParameter parameter : constructorParameters) {
@@ -320,9 +322,67 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
mv.visitEnd();
}
static boolean isEnum(JetClassOrObject myClass) {
final JetModifierList modifierList = myClass.getModifierList();
return modifierList != null && modifierList.hasModifier(JetTokens.ENUM_KEYWORD);
private void generateTraitMethods(ExpressionCodegen codegen) {
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.
Method function = state.getTypeMapper().mapSignature(fun.getName(), fun);
final MethodVisitor mv = v.visitMethod(flags, function.getName(), function.getDescriptor(), null, null);
mv.visitCode();
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();
}
String fdescriptor = function.getDescriptor().replace("(","(L" + state.getTypeMapper().jvmName((ClassDescriptor) fun.getContainingDeclaration(),OwnerKind.IMPLEMENTATION) + ";");
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;
}
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);
}
}
}
}
else if(psiElement instanceof PsiClass) {
PsiClass psiClass = (PsiClass) psiElement;
}
}
@Nullable
@@ -218,15 +218,15 @@ public class JetTypeMapper {
public String jvmName(JetClassObject classObject) {
final ClassDescriptor descriptor = bindingContext.get(BindingContext.CLASS, classObject.getObjectDeclaration());
return jvmName(descriptor, OwnerKind.IMPLEMENTATION);
return jvmName(descriptor, OwnerKind.IMPLEMENTATION);
}
public boolean isInterface(ClassDescriptor jetClass, OwnerKind kind) {
public boolean isInterface(ClassDescriptor jetClass) {
PsiElement declaration = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, jetClass);
if (declaration instanceof JetObjectDeclaration) {
return false;
}
return jetClass instanceof JetClass ? ((JetClass)jetClass).isTrait() : false;
return declaration instanceof JetClass && ((JetClass) declaration).isTrait();
}
private static String jetJvmName(ClassDescriptor jetClass, OwnerKind kind) {
@@ -236,6 +236,9 @@ public class JetTypeMapper {
else if (kind == OwnerKind.IMPLEMENTATION) {
return jvmNameForImplementation(jetClass);
}
else if (kind == OwnerKind.TRAIT_IMPL) {
return jvmNameForTraitImpl(jetClass);
}
else {
assert false : "Unsuitable kind";
return "java/lang/Object";
@@ -277,8 +280,8 @@ public class JetTypeMapper {
return jvmNameForInterface(descriptor);
}
public static String jvmNameForDelegatingImplementation(ClassDescriptor descriptor) {
return jvmNameForInterface(descriptor) + "$$DImpl";
private static String jvmNameForTraitImpl(ClassDescriptor descriptor) {
return jvmNameForInterface(descriptor) + "$$TImpl";
}
public String getOwner(DeclarationDescriptor descriptor, OwnerKind kind) {
@@ -426,7 +429,7 @@ public class JetTypeMapper {
}
private Method mapSignature(JetNamedFunction f, List<Type> valueParameterTypes) {
private Method mapSignature(JetNamedFunction f, List<Type> valueParameterTypes, OwnerKind kind) {
final JetTypeReference receiverTypeRef = f.getReceiverTypeRef();
final JetType receiverType = receiverTypeRef == null ? null : bindingContext.get(BindingContext.TYPE, receiverTypeRef);
final List<JetParameter> parameters = f.getValueParameters();
@@ -434,6 +437,13 @@ public class JetTypeMapper {
if (receiverType != null) {
parameterTypes.add(mapType(receiverType));
}
FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f);
if(kind == OwnerKind.TRAIT_IMPL) {
JetType jetType = ((ClassDescriptor)functionDescriptor.getContainingDeclaration()).getDefaultType();
final Type type = mapType(jetType);
valueParameterTypes.add(type);
parameterTypes.add(type);
}
for (JetParameter parameter : parameters) {
final Type type = mapType(bindingContext.get(BindingContext.TYPE, parameter.getTypeReference()));
valueParameterTypes.add(type);
@@ -445,7 +455,6 @@ public class JetTypeMapper {
final JetTypeReference returnTypeRef = f.getReturnTypeRef();
Type returnType;
if (returnTypeRef == null) {
final FunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, f);
assert functionDescriptor != null;
final JetType type = functionDescriptor.getReturnType();
returnType = mapReturnType(type);
@@ -456,7 +465,7 @@ public class JetTypeMapper {
return new Method(f.getName(), returnType, parameterTypes.toArray(new Type[parameterTypes.size()]));
}
public CallableMethod mapToCallableMethod(PsiNamedElement declaration) {
public CallableMethod mapToCallableMethod(PsiNamedElement declaration, OwnerKind kind) {
if (declaration instanceof PsiMethod) {
return mapToCallableMethod((PsiMethod) declaration);
}
@@ -468,7 +477,7 @@ public class JetTypeMapper {
assert functionDescriptor != null;
final DeclarationDescriptor functionParent = functionDescriptor.getContainingDeclaration();
final List<Type> valueParameterTypes = new ArrayList<Type>();
Method descriptor = mapSignature(f, valueParameterTypes);
Method descriptor = mapSignature(f, valueParameterTypes, kind);
String owner;
int invokeOpcode;
boolean needsReceiver;
@@ -481,7 +490,7 @@ public class JetTypeMapper {
else if (functionParent instanceof ClassDescriptor) {
ClassDescriptor containingClass = (ClassDescriptor) functionParent;
owner = jvmName(containingClass, OwnerKind.IMPLEMENTATION);
invokeOpcode = isInterface(containingClass, OwnerKind.INTERFACE)
invokeOpcode = isInterface(containingClass)
? Opcodes.INVOKEINTERFACE
: Opcodes.INVOKEVIRTUAL;
needsReceiver = true;
@@ -11,8 +11,8 @@ public class OwnerKind {
}
public static final OwnerKind NAMESPACE = new OwnerKind("namespace");
public static final OwnerKind INTERFACE = new OwnerKind("interface");
public static final OwnerKind IMPLEMENTATION = new OwnerKind("implementation");
public static final OwnerKind TRAIT_IMPL = new OwnerKind("trait implementation");
public static class DelegateKind extends OwnerKind {
private final StackValue delegate;
@@ -42,24 +42,6 @@ public class PropertyCodegen {
generateGetter(p, propertyDescriptor);
generateSetter(p, propertyDescriptor);
}
else if (kind == OwnerKind.INTERFACE) {
final JetPropertyAccessor getter = p.getGetter();
if ((getter != null && !getter.hasModifier(JetTokens.PRIVATE_KEYWORD) ||
(getter == null && isExternallyAccessible(p)))) {
v.visitMethod(Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC,
getterName(p.getName()),
state.getTypeMapper().mapGetterSignature(propertyDescriptor).getDescriptor(),
null, null);
}
final JetPropertyAccessor setter = p.getSetter();
if ((setter != null && !setter.hasModifier(JetTokens.PRIVATE_KEYWORD) ||
(setter == null && isExternallyAccessible(p) && p.isVar()))) {
v.visitMethod(Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC,
setterName(p.getName()),
state.getTypeMapper().mapSetterSignature(propertyDescriptor).getDescriptor(),
null, null);
}
}
else if (kind instanceof OwnerKind.DelegateKind) {
generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC);
if (propertyDescriptor.isVar()) {
@@ -0,0 +1,39 @@
package org.jetbrains.jet.codegen;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import org.jetbrains.jet.lexer.JetTokens;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Opcodes;
import java.util.ArrayList;
import java.util.List;
public class TraitImplBodyCodegen extends ClassBodyCodegen {
public TraitImplBodyCodegen(JetClassOrObject aClass, ClassContext context, ClassVisitor v, GenerationState state) {
super(aClass, context, v, state);
}
@Override
protected void generateDeclaration() {
v.visit(Opcodes.V1_6,
Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL,
jvmName(),
null,
"java/lang/Object",
new String[0]
);
v.visitSource(myClass.getContainingFile().getName(), null);
}
private String jvmName() {
return state.getTypeMapper().jvmName(descriptor, OwnerKind.TRAIT_IMPL);
}
@Override
protected void genNamedFunction(JetNamedFunction declaration, FunctionCodegen functionCodegen) {
super.genNamedFunction(declaration, functionCodegen); //To change body of overridden methods use File | Settings | File Templates.
}
}
@@ -25,7 +25,7 @@ public class PsiMethodCall implements IntrinsicMethod {
@Override
public StackValue generate(ExpressionCodegen codegen, InstructionAdapter v, Type expectedType, PsiElement element,
List<JetExpression> arguments, StackValue receiver) {
final CallableMethod callableMethod = codegen.getTypeMapper().mapToCallableMethod(myMethod);
final CallableMethod callableMethod = codegen.getTypeMapper().mapToCallableMethod(myMethod, null);
codegen.invokeMethodWithArguments(callableMethod, (JetCallExpression) element, receiver);
return StackValue.onStack(callableMethod.getSignature().getReturnType());
}
+12
View File
@@ -0,0 +1,12 @@
trait SimpleClass : java.lang.Object {
fun foo() : String = "239 " + toString ()
}
class SimpleClassImpl() : SimpleClass {
override fun toString() = "SimpleClassImpl"
}
fun box() : String {
val c = SimpleClassImpl()
return if("239 SimpleClassImpl" == c.foo()) "OK" else "fail"
}
@@ -0,0 +1,13 @@
package org.jetbrains.jet.codegen;
public class TraitsTest extends CodegenTestCase {
@Override
protected String getPrefix() {
return "traits";
}
public void testSimple () throws Exception {
blackBoxFile("traits/simple.jet");
System.out.println(generateToText());
}
}