diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java index 8a818ac3f6d..fbe222a069f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AsmUtil.java @@ -30,6 +30,7 @@ import org.jetbrains.jet.codegen.binding.CalculatedClosure; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.psi.JetPsiUtil; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; @@ -48,6 +49,7 @@ import java.util.Set; import static org.jetbrains.asm4.Opcodes.*; import static org.jetbrains.jet.codegen.CodegenUtil.*; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumEntry; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE; public class AsmUtil { @@ -239,15 +241,13 @@ public class AsmUtil { return null; } // the following code is only for PRIVATE visibility of member - if (isClassObject(containingDeclaration)) { + if (isEnumEntry(memberDescriptor)) { return NO_FLAG_PACKAGE_PRIVATE; } if (memberDescriptor instanceof ConstructorDescriptor) { ClassKind kind = ((ClassDescriptor) containingDeclaration).getKind(); if (kind == ClassKind.OBJECT) { - //TODO: should be NO_FLAG_PACKAGE_PRIVATE - // see http://youtrack.jetbrains.com/issue/KT-2700 - return ACC_PUBLIC; + return NO_FLAG_PACKAGE_PRIVATE; } else if (kind == ClassKind.ENUM_ENTRY) { return NO_FLAG_PACKAGE_PRIVATE; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java index e56d5ed6834..ca47be38717 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CallableMethod.java @@ -105,10 +105,14 @@ public class CallableMethod implements Callable { @NotNull GenerationState state, @NotNull ResolvedCall resolvedCall ) { - invoke(v); + invokeWithoutAssertions(v); AsmUtil.genNotNullAssertionForMethod(v, state, resolvedCall); } + public void invokeWithoutAssertions(@NotNull InstructionAdapter v) { + invoke(v); + } + @Nullable public Type getGenerateCalleeType() { return generateCalleeType; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java index bfbf4597349..8ef88ae3fdf 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClassBodyCodegen.java @@ -19,7 +19,6 @@ package org.jetbrains.jet.codegen; import org.jetbrains.annotations.NotNull; import org.jetbrains.asm4.MethodVisitor; import org.jetbrains.asm4.Type; -import org.jetbrains.asm4.commons.InstructionAdapter; import org.jetbrains.jet.codegen.context.CodegenContext; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; @@ -76,12 +75,25 @@ public abstract class ClassBodyCodegen extends MemberCodegen { PropertyCodegen propertyCodegen = new PropertyCodegen(context, v, functionCodegen); for (JetDeclaration declaration : myClass.getDeclarations()) { - generateDeclaration(propertyCodegen, declaration, functionCodegen); + //generate nested classes first and only then generate class body. It necessary to access to nested CodegenContexts + if (shouldProcessFirst(declaration)) { + generateDeclaration(propertyCodegen, declaration, functionCodegen); + } + } + + for (JetDeclaration declaration : myClass.getDeclarations()) { + if (!shouldProcessFirst(declaration)) { + generateDeclaration(propertyCodegen, declaration, functionCodegen); + } } generatePrimaryConstructorProperties(propertyCodegen, myClass); } + private boolean shouldProcessFirst(JetDeclaration declaration) { + return false == (declaration instanceof JetProperty || declaration instanceof JetNamedFunction); + } + protected void generateDeclaration(PropertyCodegen propertyCodegen, JetDeclaration declaration, FunctionCodegen functionCodegen) { if (declaration instanceof JetProperty || declaration instanceof JetNamedFunction) { genFunctionOrProperty(context, (JetTypeParameterListOwner) declaration, v); @@ -126,18 +138,18 @@ public abstract class ClassBodyCodegen extends MemberCodegen { private void generateStaticInitializer() { if (staticInitializerChunks.size() > 0) { - MethodVisitor mv = v.newMethod(null, ACC_PUBLIC | ACC_STATIC, "", "()V", null, null); + MethodVisitor mv = v.newMethod(null, ACC_STATIC, "", "()V", null, null); if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { mv.visitCode(); - InstructionAdapter v = new InstructionAdapter(mv); + ExpressionCodegen codegen = new ExpressionCodegen(mv, new FrameMap(), Type.VOID_TYPE, context, state); for (CodeChunk chunk : staticInitializerChunks) { - chunk.generate(v); + chunk.generate(codegen); } mv.visitInsn(RETURN); - FunctionCodegen.endVisit(v, "static initializer", myClass); + FunctionCodegen.endVisit(codegen.v, "static initializer", myClass); } } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/CodeChunk.java b/compiler/backend/src/org/jetbrains/jet/codegen/CodeChunk.java index 9aa1cb2ca30..293a3fdbfe6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/CodeChunk.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/CodeChunk.java @@ -16,8 +16,6 @@ package org.jetbrains.jet.codegen; -import org.jetbrains.asm4.commons.InstructionAdapter; - public interface CodeChunk { - void generate(InstructionAdapter v); + void generate(ExpressionCodegen codegen); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 46b869544f4..295167f4a53 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1562,7 +1562,7 @@ public class ExpressionCodegen extends JetVisitor implem expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER && contextKind() != OwnerKind.TRAIT_IMPL; JetExpression r = getReceiverForSelector(expression); boolean isSuper = r instanceof JetSuperExpression; - propertyDescriptor = accessablePropertyDescriptor(context, propertyDescriptor); + propertyDescriptor = accessablePropertyDescriptor(propertyDescriptor); StackValue.Property iValue = intermediateValueForProperty(propertyDescriptor, directToField, isSuper ? (JetSuperExpression) r : null); if (directToField) { @@ -1677,16 +1677,14 @@ public class ExpressionCodegen extends JetVisitor implem boolean forceField, @Nullable JetSuperExpression superExpression ) { - return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, state, context, false); + return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, false); } @NotNull - public static StackValue.Property intermediateValueForProperty( + public StackValue.Property intermediateValueForProperty( PropertyDescriptor propertyDescriptor, boolean forceField, @Nullable JetSuperExpression superExpression, - @NotNull GenerationState state, - @NotNull CodegenContext context, @NotNull boolean forceSpecialFlag ) { JetTypeMapper typeMapper = state.getTypeMapper(); @@ -1720,7 +1718,7 @@ public class ExpressionCodegen extends JetVisitor implem } } - propertyDescriptor = accessablePropertyDescriptor(context, propertyDescriptor); + propertyDescriptor = accessablePropertyDescriptor(propertyDescriptor); if (propertyDescriptor.getGetter() != null) { callableGetter = typeMapper.mapToCallableMethod(propertyDescriptor.getGetter(), isSuper || forceSpecialFlag, isInsideClass, isInsideModule, OwnerKind.IMPLEMENTATION); @@ -1854,47 +1852,17 @@ public class ExpressionCodegen extends JetVisitor implem } } - private static PropertyDescriptor accessablePropertyDescriptor(CodegenContext context, PropertyDescriptor propertyDescriptor) { - PropertySetterDescriptor setter = propertyDescriptor.getSetter(); - PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); - - int flag = getVisibilityAccessFlag(propertyDescriptor) | - (getter == null ? 0 : getVisibilityAccessFlag(getter)) | - (setter == null ? 0 : getVisibilityAccessFlag(setter)); - - if ((flag & ACC_PRIVATE) == 0) { - return propertyDescriptor; - } - - return (PropertyDescriptor) accessibleDescriptor(context, propertyDescriptor); + @NotNull + private PropertyDescriptor accessablePropertyDescriptor(PropertyDescriptor propertyDescriptor) { + return context.accessablePropertyDescriptor(propertyDescriptor); } - private FunctionDescriptor accessableFunctionDescriptor(FunctionDescriptor fd) { - int flag = getVisibilityAccessFlag(fd); - if ((flag & ACC_PRIVATE) == 0) { - return fd; - } - - return (FunctionDescriptor) accessibleDescriptor(context, fd); - } - - private static MemberDescriptor accessibleDescriptor(CodegenContext context, DeclarationDescriptor descriptor) { - if (context.getClassOrNamespaceDescriptor() != descriptor.getContainingDeclaration()) { - DeclarationDescriptor enclosed = descriptor.getContainingDeclaration(); - if (context.hasThisDescriptor() && enclosed != context.getThisDescriptor()) { - CodegenContext c = context; - while (c.getContextDescriptor() != enclosed) { - c = c.getParentContext(); - if (c == null) { - return (MemberDescriptor) descriptor; - } - } - return (MemberDescriptor) c.getAccessor(descriptor); - } - } - return (MemberDescriptor) descriptor; + @NotNull + protected FunctionDescriptor accessableFunctionDescriptor(FunctionDescriptor fd) { + return context.accessableFunctionDescriptor(fd); } + @NotNull public StackValue invokeFunction( Call call, StackValue receiver, @@ -1943,7 +1911,7 @@ public class ExpressionCodegen extends JetVisitor implem } @Nullable - private static JetSuperExpression getSuperCallExpression(Call call) { + private static JetSuperExpression getSuperCallExpression(@NotNull Call call) { ReceiverValue explicitReceiver = call.getExplicitReceiver(); if (explicitReceiver instanceof ExpressionReceiver) { JetExpression receiverExpression = ((ExpressionReceiver) explicitReceiver).getExpression(); @@ -1954,7 +1922,7 @@ public class ExpressionCodegen extends JetVisitor implem return null; } - private static boolean isSuperCall(Call call) { + private static boolean isSuperCall(@NotNull Call call) { return getSuperCallExpression(call) != null; } @@ -1972,6 +1940,7 @@ public class ExpressionCodegen extends JetVisitor implem } } + @NotNull private StackValue returnValueAsStackValue(FunctionDescriptor fd, Type callReturnType) { if (callReturnType != Type.VOID_TYPE) { JetType type = fd.getReturnType(); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index ccbff63900f..697c37b290f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -37,6 +37,7 @@ import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter; import org.jetbrains.jet.codegen.signature.kotlin.JetValueParameterAnnotationWriter; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationStateAware; +import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.codegen.state.JetTypeMapperMode; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.JetNamedFunction; @@ -132,6 +133,8 @@ public class FunctionCodegen extends GenerationStateAware { endVisit(mv, null, origin); generateBridgeIfNeeded(owner, state, v, jvmSignature.getAsmMethod(), functionDescriptor); + + methodContext.recordSyntheticAccessorIfNeeded(functionDescriptor, typeMapper); } @Nullable @@ -180,7 +183,9 @@ public class FunctionCodegen extends GenerationStateAware { labelsForSharedVars.putAll(createSharedVarsForParameters(mv, functionDescriptor, frameMap)); - genNotNullAssertionsForParameters(new InstructionAdapter(mv), state, functionDescriptor, frameMap); + if (!JetTypeMapper.isAccessor(functionDescriptor)) { + genNotNullAssertionsForParameters(new InstructionAdapter(mv), state, functionDescriptor, frameMap); + } strategy.generateBody(mv, signature, context); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 785d3a0913e..05668955841 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -750,22 +750,25 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { MethodContext functionContext = context.intoFunction(function); FunctionCodegen.generateDefaultIfNeeded(functionContext, state, v, methodSignature, function, OwnerKind.IMPLEMENTATION, - new DefaultParameterValueLoader() { - @Override - public void putValueOnStack( - ValueParameterDescriptor descriptor, - ExpressionCodegen codegen - ) { - assert (KotlinBuiltIns.getInstance().isData((ClassDescriptor) function.getContainingDeclaration())) - : "Trying to create function with default arguments for function that isn't presented in code for class without data annotation"; - PropertyDescriptor propertyDescriptor = codegen.getBindingContext().get( - BindingContext.VALUE_PARAMETER_AS_PROPERTY, descriptor); - assert propertyDescriptor != null : "Trying to generate default value for parameter of copy function that doesn't correspond to any property"; - codegen.v.load(0, thisDescriptorType); - Type propertyType = codegen.typeMapper.mapType(propertyDescriptor.getType()); - codegen.intermediateValueForProperty(propertyDescriptor, false, null).put(propertyType, codegen.v); - } - }); + new DefaultParameterValueLoader() { + @Override + public void putValueOnStack( + ValueParameterDescriptor descriptor, + ExpressionCodegen codegen + ) { + assert (KotlinBuiltIns.getInstance() + .isData((ClassDescriptor) function.getContainingDeclaration())) + : "Trying to create function with default arguments for function that isn't presented in code for class without data annotation"; + PropertyDescriptor propertyDescriptor = codegen.getBindingContext().get( + BindingContext.VALUE_PARAMETER_AS_PROPERTY, descriptor); + assert propertyDescriptor != + null : "Trying to generate default value for parameter of copy function that doesn't correspond to any property"; + codegen.v.load(0, thisDescriptorType); + Type propertyType = codegen.typeMapper.mapType(propertyDescriptor.getType()); + codegen.intermediateValueForProperty(propertyDescriptor, false, null) + .put(propertyType, codegen.v); + } + }); } private void generateEnumMethods() { @@ -802,8 +805,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } } - private void generateSyntheticAccessors() { - for (Map.Entry entry : context.getAccessors().entrySet()) { + protected void generateSyntheticAccessors() { + Map accessors = context.getAccessors(); + for (Map.Entry entry : accessors.entrySet()) { generateSyntheticAccessor(entry); } } @@ -811,51 +815,21 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { private void generateSyntheticAccessor(Map.Entry entry) { if (entry.getValue() instanceof FunctionDescriptor) { FunctionDescriptor bridge = (FunctionDescriptor) entry.getValue(); - FunctionDescriptor original = (FunctionDescriptor) entry.getKey(); + final FunctionDescriptor original = (FunctionDescriptor) entry.getKey(); + functionCodegen.generateMethod(null, typeMapper.mapSignature(bridge), false, bridge, + new FunctionGenerationStrategy.CodegenBased(state, bridge) { + @Override + public void doGenerateBody(ExpressionCodegen codegen, JvmMethodSignature signature) { + generateMethodCallTo(original, codegen.v); - Method method = typeMapper.mapSignature(bridge).getAsmMethod(); - boolean isConstructor = original instanceof ConstructorDescriptor; - Method originalMethod = isConstructor ? - typeMapper.mapConstructorSignature((ConstructorDescriptor) original).getAsmMethod() : - typeMapper.mapSignature(original).getAsmMethod(); - Type[] argTypes = method.getArgumentTypes(); - - String owner = typeMapper.getOwner(original, OwnerKind.IMPLEMENTATION, isCallInsideSameModuleAsDeclared(original, context)).getInternalName(); - MethodVisitor mv = v.newMethod(null, ACC_SYNTHETIC | ACC_STATIC, bridge.getName().asString(), - method.getDescriptor(), null, null); - if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { - genStubCode(mv); - } - else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { - mv.visitCode(); - - InstructionAdapter iv = new InstructionAdapter(mv); - - if (isConstructor) { - iv.anew(method.getReturnType()); - iv.dup(); - } - else { - // todo: note that for now we never have access bridges for namespace methods, if at some point we do... - iv.load(0, OBJECT_TYPE); - } - - for (int i = isConstructor ? 0 : 1, reg = isConstructor ? 0 : 1; i < argTypes.length; i++) { - Type argType = argTypes[i]; - iv.load(reg, argType); - //noinspection AssignmentToForLoopParameter - reg += argType.getSize(); - } - iv.invokespecial(owner, originalMethod.getName(), originalMethod.getDescriptor()); - - iv.areturn(method.getReturnType()); - FunctionCodegen.endVisit(iv, "accessor", null); - } + codegen.v.areturn(signature.getAsmMethod().getReturnType()); + } + }); } else if (entry.getValue() instanceof PropertyDescriptor) { PropertyDescriptor bridge = (PropertyDescriptor) entry.getValue(); final PropertyDescriptor original = (PropertyDescriptor) entry.getKey(); - final StackValue.Property property = ExpressionCodegen.intermediateValueForProperty(original, false, null, state, context, true); + PropertyGetterDescriptor getter = bridge.getGetter(); assert getter != null; @@ -863,6 +837,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { new FunctionGenerationStrategy.CodegenBased(state, getter) { @Override public void doGenerateBody(ExpressionCodegen codegen, JvmMethodSignature signature) { + StackValue.Property property = codegen.intermediateValueForProperty(original, false, null, true); InstructionAdapter iv = codegen.v; iv.load(0, OBJECT_TYPE); property.put(property.type, iv); @@ -879,6 +854,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { new FunctionGenerationStrategy.CodegenBased(state, setter) { @Override public void doGenerateBody(ExpressionCodegen codegen, JvmMethodSignature signature) { + StackValue.Property property = codegen.intermediateValueForProperty(original, false, null, true); InstructionAdapter iv = codegen.v; iv.load(0, OBJECT_TYPE); @@ -901,23 +877,58 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { } } + private void generateMethodCallTo(FunctionDescriptor functionDescriptor, InstructionAdapter iv) { + boolean isConstructor = functionDescriptor instanceof ConstructorDescriptor; + boolean callFromAccessor = !JetTypeMapper.isAccessor(functionDescriptor); + CallableMethod callableMethod = isConstructor ? + typeMapper.mapToCallableMethod((ConstructorDescriptor) functionDescriptor) : + typeMapper.mapToCallableMethod(functionDescriptor, callFromAccessor, + isCallInsideSameClassAsDeclared(functionDescriptor, context), + isCallInsideSameModuleAsDeclared(functionDescriptor, context), + context.getContextKind()); + + Method method = callableMethod.getSignature().getAsmMethod(); + Type[] argTypes = method.getArgumentTypes(); + + int reg = 1; + if (isConstructor) { + iv.anew(callableMethod.getOwner().getAsmType()); + iv.dup(); + reg = 0; + } + else if (callFromAccessor) { + iv.load(0, OBJECT_TYPE); + } + + for (int paramIndex = 0; paramIndex < argTypes.length; paramIndex++) { + Type argType = argTypes[paramIndex]; + iv.load(reg, argType); + //noinspection AssignmentToForLoopParameter + reg += argType.getSize(); + } + callableMethod.invokeWithoutAssertions(iv); + } + private void generateFieldForSingleton() { boolean hasClassObject = descriptor.getClassObjectDescriptor() != null; boolean isEnumClass = DescriptorUtils.isEnumClass(descriptor); if (!(isNonLiteralObject(myClass) || hasClassObject) || isEnumClass) return; - ClassDescriptor fieldTypeDescriptor = hasClassObject ? descriptor.getClassObjectDescriptor() : descriptor; + final ClassDescriptor fieldTypeDescriptor = hasClassObject ? descriptor.getClassObjectDescriptor() : descriptor; assert fieldTypeDescriptor != null; - final FieldInfo info = FieldInfo.createForSingleton(fieldTypeDescriptor, typeMapper); + final StackValue.Field field = StackValue.singleton(fieldTypeDescriptor, typeMapper); JetClassOrObject original = hasClassObject ? ((JetClass) myClass).getClassObject().getObjectDeclaration() : myClass; - v.newField(original, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, info.getFieldName(), info.getFieldType().getDescriptor(), null, null); + v.newField(original, ACC_PUBLIC | ACC_STATIC | ACC_FINAL, field.name, field.type.getDescriptor(), null, null); staticInitializerChunks.add(new CodeChunk() { @Override - public void generate(InstructionAdapter iv) { - genInitSingletonField(info, iv); + public void generate(ExpressionCodegen codegen) { + ConstructorDescriptor constructorDescriptor = DescriptorUtils.getConstructorOfSingletonObject(fieldTypeDescriptor); + FunctionDescriptor fd = codegen.accessableFunctionDescriptor(constructorDescriptor); + generateMethodCallTo(fd, codegen.v); + field.store(field.type, codegen.v); } }); } @@ -963,6 +974,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { CallableMethod callableMethod = typeMapper.mapToCallableMethod(constructorDescriptor, closure); FunctionCodegen.generateConstructorWithoutParametersIfNeeded(state, callableMethod, constructorDescriptor, v); + + if (isClassObject(descriptor)) { + context.recordSyntheticAccessorIfNeeded(constructorDescriptor, typeMapper); + } } private void generatePrimaryConstructorImpl( @@ -1418,8 +1433,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { if (myEnumConstants.isEmpty()) { staticInitializerChunks.add(new CodeChunk() { @Override - public void generate(InstructionAdapter v) { - initializeEnumConstants(v); + public void generate(ExpressionCodegen codegen) { + initializeEnumConstants(codegen.v); } }); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java index 34c71c9655b..493de79443b 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -77,6 +77,8 @@ public class PropertyCodegen extends GenerationStateAware { } generateGetter(p, propertyDescriptor, p.getGetter()); generateSetter(p, propertyDescriptor, p.getSetter()); + + context.recordSyntheticAccessorIfNeeded(propertyDescriptor, typeMapper); } public void generatePrimaryConstructorProperty(JetParameter p, PropertyDescriptor descriptor) { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java index b7f8d673b7d..55b37b180b6 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/StackValue.java @@ -131,7 +131,7 @@ public abstract class StackValue { } @NotNull - public static StackValue field(@NotNull Type type, @NotNull JvmClassName owner, @NotNull String name, boolean isStatic) { + public static Field field(@NotNull Type type, @NotNull JvmClassName owner, @NotNull String name, boolean isStatic) { return new Field(type, owner, name, isStatic); } @@ -338,7 +338,7 @@ public abstract class StackValue { return receiverWithParameter; } - public static StackValue singleton(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) { + public static Field singleton(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) { FieldInfo info = FieldInfo.createForSingleton(classDescriptor, typeMapper); return field(info.getFieldType(), JvmClassName.byInternalName(info.getOwnerInternalName()), info.getFieldName(), true); } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/ClassContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/ClassContext.java index 2dac8bb2e83..6b99c7baaf5 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/context/ClassContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/ClassContext.java @@ -24,7 +24,8 @@ import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import static org.jetbrains.jet.codegen.binding.CodegenBinding.CLOSURE; -public class ClassContext extends CodegenContext { +public class ClassContext extends CodegenContext { + public ClassContext( @NotNull JetTypeMapper typeMapper, @NotNull ClassDescriptor contextDescriptor, @@ -38,6 +39,15 @@ public class ClassContext extends CodegenContext { initOuterExpression(typeMapper, contextDescriptor); } + + @Nullable + public CodegenContext getClassObjectContext() { + if (getContextDescriptor().getClassObjectDescriptor() != null) { + return findChildContext(getContextDescriptor().getClassObjectDescriptor()); + } + return null; + } + @Override public boolean isStatic() { return false; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java index f78261f5c6c..14a55244cbc 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/context/CodegenContext.java @@ -27,21 +27,25 @@ import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.DescriptorUtils; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import static org.jetbrains.asm4.Opcodes.ACC_PRIVATE; import static org.jetbrains.jet.codegen.AsmUtil.CAPTURED_THIS_FIELD; +import static org.jetbrains.jet.codegen.AsmUtil.getVisibilityAccessFlag; import static org.jetbrains.jet.codegen.binding.CodegenBinding.*; import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; -public abstract class CodegenContext { +public abstract class CodegenContext { public static final CodegenContext STATIC = new RootContext(); @NotNull - private final DeclarationDescriptor contextDescriptor; + private final T contextDescriptor; @NotNull private final OwnerKind contextKind; @@ -52,13 +56,16 @@ public abstract class CodegenContext { public final MutableClosure closure; - HashMap accessors; + private HashMap accessors; + + private Map childContexts; protected StackValue outerExpression; + private final LocalLookup enclosingLocalLookup; public CodegenContext( - @NotNull DeclarationDescriptor contextDescriptor, + @NotNull T contextDescriptor, @NotNull OwnerKind contextKind, @Nullable CodegenContext parentContext, @Nullable MutableClosure closure, @@ -71,6 +78,10 @@ public abstract class CodegenContext { this.closure = closure; this.thisDescriptor = thisDescriptor; this.enclosingLocalLookup = expressionCodegen; + + if (parentContext != null) { + parentContext.addChild(this); + } } @NotNull @@ -126,7 +137,7 @@ public abstract class CodegenContext { } @NotNull - public DeclarationDescriptor getContextDescriptor() { + public T getContextDescriptor() { return contextDescriptor; } @@ -143,7 +154,7 @@ public abstract class CodegenContext { return new NamespaceContext(descriptor, this, new OwnerKind.StaticDelegateKind(delegateTo)); } - public CodegenContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) { + public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) { return new ClassContext(state.getTypeMapper(), descriptor, kind, this, null); } @@ -297,4 +308,110 @@ public abstract class CodegenContext { public Map getAccessors() { return accessors == null ? Collections.emptyMap() : accessors; } + + @NotNull + public PropertyDescriptor accessablePropertyDescriptor(PropertyDescriptor propertyDescriptor) { + return (PropertyDescriptor) accessibleDescriptorIfNeeded(propertyDescriptor, true); + } + + @NotNull + public FunctionDescriptor accessableFunctionDescriptor(FunctionDescriptor fd) { + return (FunctionDescriptor) accessibleDescriptorIfNeeded(fd, true); + } + + @NotNull + public void recordSyntheticAccessorIfNeeded(@NotNull FunctionDescriptor fd, @NotNull JetTypeMapper typeMapper) { + if (fd instanceof ConstructorDescriptor || needSyntheticAccessorInBindingTrace(fd, typeMapper)) { + accessibleDescriptorIfNeeded(fd, false); + } + } + + @NotNull + public void recordSyntheticAccessorIfNeeded(PropertyDescriptor propertyDescriptor, JetTypeMapper typeMapper) { + if (needSyntheticAccessorInBindingTrace(propertyDescriptor, typeMapper)) { + accessibleDescriptorIfNeeded(propertyDescriptor, false); + } + } + + private boolean needSyntheticAccessorInBindingTrace(@NotNull CallableMemberDescriptor descriptor, @NotNull JetTypeMapper typeMapper) { + Boolean result = typeMapper.getBindingContext().get(BindingContext.NEED_SYNTHETIC_ACCESSOR, descriptor); + return result == null ? false : result.booleanValue(); + } + + @NotNull + private int getAccessFlags(CallableMemberDescriptor descriptor) { + int flag = getVisibilityAccessFlag(descriptor); + if (descriptor instanceof PropertyDescriptor) { + PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; + + PropertySetterDescriptor setter = propertyDescriptor.getSetter(); + PropertyGetterDescriptor getter = propertyDescriptor.getGetter(); + + flag |= (getter == null ? 0 : getVisibilityAccessFlag(getter)) | + (setter == null ? 0 : getVisibilityAccessFlag(setter)); + } + return flag; + } + + @NotNull + private MemberDescriptor accessibleDescriptorIfNeeded(CallableMemberDescriptor descriptor, boolean fromOutsideContext) { + int flag = getAccessFlags(descriptor); + if ((flag & ACC_PRIVATE) == 0) { + return descriptor; + } + + CodegenContext descriptorContext = null; + if (!fromOutsideContext || getClassOrNamespaceDescriptor() != descriptor.getContainingDeclaration()) { + DeclarationDescriptor enclosed = descriptor.getContainingDeclaration(); + boolean isClassObjectMember = DescriptorUtils.isClassObject(enclosed); + //go upper + if (hasThisDescriptor() && (enclosed != getThisDescriptor() || !fromOutsideContext)) { + CodegenContext currentContext = this; + while (currentContext != null) { + if (currentContext.getContextDescriptor() == enclosed) { + descriptorContext = currentContext; + break; + } + + //accessors for private members in class object for call from class + if (isClassObjectMember && currentContext instanceof ClassContext) { + ClassContext classContext = (ClassContext) currentContext; + CodegenContext classObject = classContext.getClassObjectContext(); + if (classObject != null && classObject.getContextDescriptor() == enclosed) { + descriptorContext = classObject; + break; + } + } + + currentContext = currentContext.getParentContext(); + } + } + } + + return (MemberDescriptor) (descriptorContext != null ? descriptorContext.getAccessor(descriptor) : descriptor); + } + + private void addChild(@NotNull CodegenContext child) { + if (shouldAddChild(child)) { + if (childContexts == null) { + childContexts = new HashMap(); + } + DeclarationDescriptor childContextDescriptor = child.getContextDescriptor(); + childContexts.put(childContextDescriptor, child); + } + } + + protected boolean shouldAddChild(@NotNull CodegenContext child) { + DeclarationDescriptor childContextDescriptor = child.contextDescriptor; + if (childContextDescriptor instanceof ClassDescriptor) { + ClassKind kind = ((ClassDescriptor) childContextDescriptor).getKind(); + return kind == ClassKind.CLASS_OBJECT; + } + return false; + } + + @Nullable + public CodegenContext findChildContext(@NotNull DeclarationDescriptor child) { + return childContexts == null ? null : childContexts.get(child); + } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java index f39ccfdc0bc..7bd46ce35e7 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java @@ -22,6 +22,7 @@ import org.jetbrains.jet.lang.resolve.BodyResolver; import org.jetbrains.jet.lang.resolve.ControlFlowAnalyzer; import org.jetbrains.jet.lang.resolve.DeclarationsChecker; import org.jetbrains.jet.lang.resolve.DescriptorResolver; +import org.jetbrains.jet.lang.resolve.calls.NeedSyntheticCallResolverExtension; import com.intellij.openapi.project.Project; import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; import org.jetbrains.jet.lang.resolve.BindingTrace; @@ -73,6 +74,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly private ControlFlowAnalyzer controlFlowAnalyzer; private DeclarationsChecker declarationsChecker; private DescriptorResolver descriptorResolver; + private NeedSyntheticCallResolverExtension needSyntheticCallResolverExtension; private final Project project; private final TopDownAnalysisParameters topDownAnalysisParameters; private final BindingTrace bindingTrace; @@ -125,6 +127,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly this.controlFlowAnalyzer = new ControlFlowAnalyzer(); this.declarationsChecker = new DeclarationsChecker(); this.descriptorResolver = new DescriptorResolver(); + this.needSyntheticCallResolverExtension = new NeedSyntheticCallResolverExtension(); this.project = project; this.topDownAnalysisParameters = topDownAnalysisParameters; this.bindingTrace = bindingTrace; @@ -224,6 +227,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly callResolver.setArgumentTypeResolver(argumentTypeResolver); callResolver.setCandidateResolver(candidateResolver); callResolver.setExpressionTypingServices(expressionTypingServices); + callResolver.setExtension(needSyntheticCallResolverExtension); callResolver.setTypeResolver(typeResolver); argumentTypeResolver.setExpressionTypingServices(expressionTypingServices); diff --git a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForBodyResolve.java b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForBodyResolve.java index 2e403ff5caa..9926b81519a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForBodyResolve.java +++ b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForBodyResolve.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.di; import org.jetbrains.jet.lang.resolve.BodyResolver; +import org.jetbrains.jet.lang.resolve.calls.NeedSyntheticCallResolverExtension; import com.intellij.openapi.project.Project; import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; import org.jetbrains.jet.lang.resolve.BindingTrace; @@ -42,6 +43,7 @@ import javax.annotation.PreDestroy; public class InjectorForBodyResolve { private BodyResolver bodyResolver; + private NeedSyntheticCallResolverExtension needSyntheticCallResolverExtension; private final Project project; private final TopDownAnalysisParameters topDownAnalysisParameters; private final BindingTrace bindingTrace; @@ -69,6 +71,7 @@ public class InjectorForBodyResolve { @NotNull ModuleDescriptor moduleDescriptor ) { this.bodyResolver = new BodyResolver(); + this.needSyntheticCallResolverExtension = new NeedSyntheticCallResolverExtension(); this.project = project; this.topDownAnalysisParameters = topDownAnalysisParameters; this.bindingTrace = bindingTrace; @@ -101,6 +104,7 @@ public class InjectorForBodyResolve { callResolver.setArgumentTypeResolver(argumentTypeResolver); callResolver.setCandidateResolver(candidateResolver); callResolver.setExpressionTypingServices(expressionTypingServices); + callResolver.setExtension(needSyntheticCallResolverExtension); callResolver.setTypeResolver(typeResolver); argumentTypeResolver.setExpressionTypingServices(expressionTypingServices); diff --git a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForLazyResolve.java b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForLazyResolve.java index 75abc36457b..845263ea0ca 100644 --- a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForLazyResolve.java +++ b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForLazyResolve.java @@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.resolve.lazy.ScopeProvider; import org.jetbrains.jet.lang.resolve.AnnotationResolver; import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver; import org.jetbrains.jet.lang.psi.JetImportsFactory; +import org.jetbrains.jet.lang.resolve.calls.NeedSyntheticCallResolverExtension; import org.jetbrains.jet.lang.resolve.calls.CallExpressionResolver; import org.jetbrains.jet.lang.resolve.calls.CallResolver; import org.jetbrains.jet.lang.resolve.calls.ArgumentTypeResolver; @@ -46,6 +47,7 @@ public class InjectorForLazyResolve { private AnnotationResolver annotationResolver; private QualifiedExpressionResolver qualifiedExpressionResolver; private JetImportsFactory jetImportsFactory; + private NeedSyntheticCallResolverExtension needSyntheticCallResolverExtension; private CallExpressionResolver callExpressionResolver; private CallResolver callResolver; private ArgumentTypeResolver argumentTypeResolver; @@ -66,6 +68,7 @@ public class InjectorForLazyResolve { this.annotationResolver = new AnnotationResolver(); this.qualifiedExpressionResolver = new QualifiedExpressionResolver(); this.jetImportsFactory = new JetImportsFactory(); + this.needSyntheticCallResolverExtension = new NeedSyntheticCallResolverExtension(); this.callExpressionResolver = new CallExpressionResolver(); this.callResolver = new CallResolver(); this.argumentTypeResolver = new ArgumentTypeResolver(); @@ -96,6 +99,7 @@ public class InjectorForLazyResolve { callResolver.setArgumentTypeResolver(argumentTypeResolver); callResolver.setCandidateResolver(candidateResolver); callResolver.setExpressionTypingServices(expressionTypingServices); + callResolver.setExtension(needSyntheticCallResolverExtension); callResolver.setTypeResolver(typeResolver); argumentTypeResolver.setExpressionTypingServices(expressionTypingServices); diff --git a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForMacros.java b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForMacros.java index 72b331eb103..b4625f5ba1f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForMacros.java +++ b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForMacros.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.di; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; +import org.jetbrains.jet.lang.resolve.calls.NeedSyntheticCallResolverExtension; import com.intellij.openapi.project.Project; import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; import org.jetbrains.jet.lang.resolve.calls.CallExpressionResolver; @@ -34,6 +35,7 @@ import javax.annotation.PreDestroy; public class InjectorForMacros { private ExpressionTypingServices expressionTypingServices; + private NeedSyntheticCallResolverExtension needSyntheticCallResolverExtension; private final Project project; private final ModuleDescriptor moduleDescriptor; private CallExpressionResolver callExpressionResolver; @@ -50,6 +52,7 @@ public class InjectorForMacros { @NotNull ModuleDescriptor moduleDescriptor ) { this.expressionTypingServices = new ExpressionTypingServices(); + this.needSyntheticCallResolverExtension = new NeedSyntheticCallResolverExtension(); this.project = project; this.moduleDescriptor = moduleDescriptor; this.callExpressionResolver = new CallExpressionResolver(); @@ -72,6 +75,7 @@ public class InjectorForMacros { callResolver.setArgumentTypeResolver(argumentTypeResolver); callResolver.setCandidateResolver(candidateResolver); callResolver.setExpressionTypingServices(expressionTypingServices); + callResolver.setExtension(needSyntheticCallResolverExtension); callResolver.setTypeResolver(typeResolver); argumentTypeResolver.setExpressionTypingServices(expressionTypingServices); diff --git a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java index c79fe48893c..966d52b828c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java +++ b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java @@ -22,6 +22,7 @@ import org.jetbrains.jet.lang.resolve.BodyResolver; import org.jetbrains.jet.lang.resolve.ControlFlowAnalyzer; import org.jetbrains.jet.lang.resolve.DeclarationsChecker; import org.jetbrains.jet.lang.resolve.DescriptorResolver; +import org.jetbrains.jet.lang.resolve.calls.NeedSyntheticCallResolverExtension; import com.intellij.openapi.project.Project; import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; import org.jetbrains.jet.lang.resolve.BindingTrace; @@ -56,6 +57,7 @@ public class InjectorForTopDownAnalyzerBasic { private ControlFlowAnalyzer controlFlowAnalyzer; private DeclarationsChecker declarationsChecker; private DescriptorResolver descriptorResolver; + private NeedSyntheticCallResolverExtension needSyntheticCallResolverExtension; private final Project project; private final TopDownAnalysisParameters topDownAnalysisParameters; private final BindingTrace bindingTrace; @@ -91,6 +93,7 @@ public class InjectorForTopDownAnalyzerBasic { this.controlFlowAnalyzer = new ControlFlowAnalyzer(); this.declarationsChecker = new DeclarationsChecker(); this.descriptorResolver = new DescriptorResolver(); + this.needSyntheticCallResolverExtension = new NeedSyntheticCallResolverExtension(); this.project = project; this.topDownAnalysisParameters = topDownAnalysisParameters; this.bindingTrace = bindingTrace; @@ -162,6 +165,7 @@ public class InjectorForTopDownAnalyzerBasic { callResolver.setArgumentTypeResolver(argumentTypeResolver); callResolver.setCandidateResolver(candidateResolver); callResolver.setExpressionTypingServices(expressionTypingServices); + callResolver.setExtension(needSyntheticCallResolverExtension); callResolver.setTypeResolver(typeResolver); argumentTypeResolver.setExpressionTypingServices(expressionTypingServices); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index 6b4980374a0..b84fa9060f8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -133,6 +133,8 @@ public interface BindingContext { WritableSlice CAPTURED_IN_CLOSURE = new BasicWritableSlice(DO_NOTHING); + WritableSlice NEED_SYNTHETIC_ACCESSOR = new BasicWritableSlice(DO_NOTHING); + // enum DeferredTypeKey {DEFERRED_TYPE_KEY} // WritableSlice> DEFERRED_TYPES = Slices.createSimpleSlice(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java index 5a48b391d44..84dd2283356 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/DescriptorUtils.java @@ -420,10 +420,24 @@ public class DescriptorUtils { return (ClassDescriptor) classifier; } + @NotNull public static ConstructorDescriptor getConstructorOfDataClass(ClassDescriptor classDescriptor) { + ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor); + assert descriptor != null : "Data class must have only one constructor: " + classDescriptor.getConstructors(); + return descriptor; + } + + @NotNull + public static ConstructorDescriptor getConstructorOfSingletonObject(ClassDescriptor classDescriptor) { + ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor); + assert descriptor != null : "Class of singleton object must have only one constructor: " + classDescriptor.getConstructors(); + return descriptor; + } + + @Nullable + private static ConstructorDescriptor getConstructorDescriptorIfOnlyOne(ClassDescriptor classDescriptor) { Collection constructors = classDescriptor.getConstructors(); - assert constructors.size() == 1 : "Data class must have only one constructor: " + constructors; - return constructors.iterator().next(); + return constructors.size() != 1 ? null : constructors.iterator().next(); } @Nullable diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 5a1b5923a77..f5bb8302e8f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -21,6 +21,7 @@ import com.google.common.collect.Lists; import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.impl.FunctionDescriptorImpl; import org.jetbrains.jet.lang.descriptors.impl.FunctionDescriptorUtil; @@ -70,6 +71,8 @@ public class CallResolver { private CandidateResolver candidateResolver; @NotNull private ArgumentTypeResolver argumentTypeResolver; + @Nullable + private CallResolverExtension extension; @Inject public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) { @@ -91,6 +94,11 @@ public class CallResolver { this.argumentTypeResolver = argumentTypeResolver; } + @Inject + public void setExtension(@NotNull CallResolverExtension extension) { + this.extension = extension; + } + @NotNull public OverloadResolutionResults resolveSimpleProperty(@NotNull BasicCallResolutionContext context) { JetExpression calleeExpression = context.call.getCalleeExpression(); @@ -142,7 +150,7 @@ public class CallResolver { ProgressIndicatorProvider.checkCanceled(); List> prioritizedTasks; - + JetExpression calleeExpression = context.call.getCalleeExpression(); JetReferenceExpression functionReference; if (calleeExpression instanceof JetSimpleNameExpression) { @@ -239,7 +247,7 @@ public class CallResolver { } return checkArgumentTypesAndFail(context); } - + FunctionDescriptorImpl functionDescriptor = new ExpressionAsFunctionDescriptor(context.scope.getContainingDeclaration(), Name.special("")); FunctionDescriptorUtil.initializeFromFunctionType(functionDescriptor, calleeType, NO_RECEIVER_PARAMETER, Modality.FINAL, Visibilities.LOCAL); @@ -296,12 +304,17 @@ public class CallResolver { } traceToResolveCall.commit(); - if (prioritizedTasks.isEmpty()) { - return results; + if (prioritizedTasks.isEmpty() || context.resolveMode == ResolveMode.NESTED_CALL) { + //do nothing + } else { + results = completeTypeInferenceDependentOnExpectedType(context, results, tracing); } - if (context.resolveMode == ResolveMode.NESTED_CALL) return results; - return completeTypeInferenceDependentOnExpectedType(context, results, tracing); + if (extension != null) { + extension.run(results, context); + } + + return results; } private void completeTypeInferenceDependentOnFunctionLiterals( diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverExtension.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverExtension.java new file mode 100644 index 00000000000..d6ddb7ac4a6 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverExtension.java @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.calls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; +import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext; +import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl; + +public interface CallResolverExtension { + void run(@NotNull OverloadResolutionResultsImpl results, @NotNull BasicCallResolutionContext context); +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/NeedSyntheticCallResolverExtension.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/NeedSyntheticCallResolverExtension.java new file mode 100644 index 00000000000..bebcce131aa --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/NeedSyntheticCallResolverExtension.java @@ -0,0 +1,54 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.calls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.CallableDescriptor; +import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; +import org.jetbrains.jet.lang.descriptors.Visibilities; +import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace; +import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResultsImpl; +import org.jetbrains.jet.lang.resolve.scopes.JetScope; + +import static org.jetbrains.jet.lang.resolve.BindingContext.NEED_SYNTHETIC_ACCESSOR; + +public class NeedSyntheticCallResolverExtension implements CallResolverExtension { + + @Override + public void run( + @NotNull OverloadResolutionResultsImpl results, + @NotNull BasicCallResolutionContext context + ) { + if (results.isSingleResult()) { + ResolvedCallWithTrace resolvedCall = results.getResultingCall(); + CallableDescriptor targetDescriptor = resolvedCall.getResultingDescriptor(); + if (needSyntheticAccessor(context.scope, targetDescriptor)) { + context.trace.record(NEED_SYNTHETIC_ACCESSOR, (CallableMemberDescriptor) targetDescriptor, Boolean.TRUE); + } + } + } + + //Necessary synthetic accessors in outer classes generated via old logic: CodegenContext.getAccessor + //Generation of accessors in nested classes (to invoke from outer, + // e.g.: from class to classobject) controlled via NEED_SYNTHETIC_ACCESSOR slice + private boolean needSyntheticAccessor(JetScope invokationScope, CallableDescriptor targetDescriptor) { + return targetDescriptor instanceof CallableMemberDescriptor && + targetDescriptor.getVisibility() == Visibilities.PRIVATE && + targetDescriptor.getContainingDeclaration() != invokationScope.getContainingDeclaration().getContainingDeclaration(); + } +} diff --git a/compiler/testData/writeFlags/function/classObjectPrivate/privateFun.kt b/compiler/testData/writeFlags/function/classObjectPrivate/privateFun.kt new file mode 100644 index 00000000000..6d4b5eac24d --- /dev/null +++ b/compiler/testData/writeFlags/function/classObjectPrivate/privateFun.kt @@ -0,0 +1,14 @@ +class Foo { + + {Foo.test()} + + class object { + private fun test() { + + } + } +} + +// TESTED_OBJECT_KIND: function +// TESTED_OBJECTS: Foo$object, test +// FLAGS: ACC_PRIVATE, ACC_FINAL \ No newline at end of file diff --git a/compiler/testData/writeFlags/function/classObjectPrivate/privateVal.kt b/compiler/testData/writeFlags/function/classObjectPrivate/privateVal.kt new file mode 100644 index 00000000000..25438523a72 --- /dev/null +++ b/compiler/testData/writeFlags/function/classObjectPrivate/privateVal.kt @@ -0,0 +1,12 @@ +class Foo { + + {Foo.test} + + class object { + private val test = "String" + } +} + +// TESTED_OBJECT_KIND: function +// TESTED_OBJECTS: Foo$object, getTest +// FLAGS: ACC_PRIVATE, ACC_FINAL \ No newline at end of file diff --git a/compiler/testData/writeFlags/function/classObjectPrivate/privateVar.kt b/compiler/testData/writeFlags/function/classObjectPrivate/privateVar.kt new file mode 100644 index 00000000000..03cb784f676 --- /dev/null +++ b/compiler/testData/writeFlags/function/classObjectPrivate/privateVar.kt @@ -0,0 +1,12 @@ +class Foo { + + {Foo.test} + + class object { + private var test = "String" + } +} + +// TESTED_OBJECT_KIND: function +// TESTED_OBJECTS: Foo$object, setTest +// FLAGS: ACC_PRIVATE, ACC_FINAL \ No newline at end of file diff --git a/compiler/testData/writeFlags/function/constructors/classObject.kt b/compiler/testData/writeFlags/function/constructors/classObject.kt new file mode 100644 index 00000000000..d0c6e867203 --- /dev/null +++ b/compiler/testData/writeFlags/function/constructors/classObject.kt @@ -0,0 +1,8 @@ +class Foo { + class object { + } +} + +// TESTED_OBJECT_KIND: function +// TESTED_OBJECTS: Foo$object, +// FLAGS: ACC_PRIVATE diff --git a/compiler/testData/writeFlags/function/constructors/objectInClass.kt b/compiler/testData/writeFlags/function/constructors/objectInClass.kt new file mode 100644 index 00000000000..bf61f402f18 --- /dev/null +++ b/compiler/testData/writeFlags/function/constructors/objectInClass.kt @@ -0,0 +1,8 @@ +class Foo { + object Test { + } +} + +// TESTED_OBJECT_KIND: function +// TESTED_OBJECTS: Foo$Test, +// FLAGS: \ No newline at end of file diff --git a/compiler/testData/writeFlags/function/constructors/objectLiteral.kt b/compiler/testData/writeFlags/function/constructors/objectLiteral.kt new file mode 100644 index 00000000000..57ccd6b8d9d --- /dev/null +++ b/compiler/testData/writeFlags/function/constructors/objectLiteral.kt @@ -0,0 +1,9 @@ +class Foo { + fun a() { + val s = object { } + } +} + +// TESTED_OBJECT_KIND: function +// TESTED_OBJECTS: Foo$a$s$1, +// FLAGS: \ No newline at end of file diff --git a/compiler/testData/writeFlags/function/constructors/topLevelObject.kt b/compiler/testData/writeFlags/function/constructors/topLevelObject.kt new file mode 100644 index 00000000000..65bc75b1560 --- /dev/null +++ b/compiler/testData/writeFlags/function/constructors/topLevelObject.kt @@ -0,0 +1,7 @@ +object Foo { + +} + +// TESTED_OBJECT_KIND: function +// TESTED_OBJECTS: Foo, +// FLAGS: \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/flags/WriteFlagsTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/flags/WriteFlagsTestGenerated.java index 0ef9a9a1feb..a71dae112dc 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/flags/WriteFlagsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/flags/WriteFlagsTestGenerated.java @@ -277,12 +277,63 @@ public class WriteFlagsTestGenerated extends AbstractWriteFlagsTest { } @TestMetadata("compiler/testData/writeFlags/function") - @InnerTestClasses({Function.DeprecatedFlag.class}) + @InnerTestClasses({Function.ClassObjectPrivate.class, Function.Constructors.class, Function.DeprecatedFlag.class}) public static class Function extends AbstractWriteFlagsTest { public void testAllFilesPresentInFunction() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/writeFlags/function"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("compiler/testData/writeFlags/function/classObjectPrivate") + public static class ClassObjectPrivate extends AbstractWriteFlagsTest { + public void testAllFilesPresentInClassObjectPrivate() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/writeFlags/function/classObjectPrivate"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("privateFun.kt") + public void testPrivateFun() throws Exception { + doTest("compiler/testData/writeFlags/function/classObjectPrivate/privateFun.kt"); + } + + @TestMetadata("privateVal.kt") + public void testPrivateVal() throws Exception { + doTest("compiler/testData/writeFlags/function/classObjectPrivate/privateVal.kt"); + } + + @TestMetadata("privateVar.kt") + public void testPrivateVar() throws Exception { + doTest("compiler/testData/writeFlags/function/classObjectPrivate/privateVar.kt"); + } + + } + + @TestMetadata("compiler/testData/writeFlags/function/constructors") + public static class Constructors extends AbstractWriteFlagsTest { + public void testAllFilesPresentInConstructors() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/writeFlags/function/constructors"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("classObject.kt") + public void testClassObject() throws Exception { + doTest("compiler/testData/writeFlags/function/constructors/classObject.kt"); + } + + @TestMetadata("objectInClass.kt") + public void testObjectInClass() throws Exception { + doTest("compiler/testData/writeFlags/function/constructors/objectInClass.kt"); + } + + @TestMetadata("objectLiteral.kt") + public void testObjectLiteral() throws Exception { + doTest("compiler/testData/writeFlags/function/constructors/objectLiteral.kt"); + } + + @TestMetadata("topLevelObject.kt") + public void testTopLevelObject() throws Exception { + doTest("compiler/testData/writeFlags/function/constructors/topLevelObject.kt"); + } + + } + @TestMetadata("compiler/testData/writeFlags/function/deprecatedFlag") public static class DeprecatedFlag extends AbstractWriteFlagsTest { public void testAllFilesPresentInDeprecatedFlag() throws Exception { @@ -354,6 +405,8 @@ public class WriteFlagsTestGenerated extends AbstractWriteFlagsTest { public static Test innerSuite() { TestSuite suite = new TestSuite("Function"); suite.addTestSuite(Function.class); + suite.addTestSuite(ClassObjectPrivate.class); + suite.addTestSuite(Constructors.class); suite.addTestSuite(DeprecatedFlag.class); return suite; } diff --git a/compiler/tests/org/jetbrains/jet/di/InjectorForTests.java b/compiler/tests/org/jetbrains/jet/di/InjectorForTests.java index 80be3fe32cd..0692ca721cc 100644 --- a/compiler/tests/org/jetbrains/jet/di/InjectorForTests.java +++ b/compiler/tests/org/jetbrains/jet/di/InjectorForTests.java @@ -20,6 +20,7 @@ import org.jetbrains.jet.lang.resolve.DescriptorResolver; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; import org.jetbrains.jet.lang.resolve.TypeResolver; import org.jetbrains.jet.lang.resolve.calls.CallResolver; +import org.jetbrains.jet.lang.resolve.calls.NeedSyntheticCallResolverExtension; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import com.intellij.openapi.project.Project; import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; @@ -38,6 +39,7 @@ public class InjectorForTests { private ExpressionTypingServices expressionTypingServices; private TypeResolver typeResolver; private CallResolver callResolver; + private NeedSyntheticCallResolverExtension needSyntheticCallResolverExtension; private KotlinBuiltIns kotlinBuiltIns; private final Project project; private final ModuleDescriptor moduleDescriptor; @@ -55,6 +57,7 @@ public class InjectorForTests { this.expressionTypingServices = new ExpressionTypingServices(); this.typeResolver = new TypeResolver(); this.callResolver = new CallResolver(); + this.needSyntheticCallResolverExtension = new NeedSyntheticCallResolverExtension(); this.kotlinBuiltIns = KotlinBuiltIns.getInstance(); this.project = project; this.moduleDescriptor = moduleDescriptor; @@ -82,6 +85,7 @@ public class InjectorForTests { this.callResolver.setArgumentTypeResolver(argumentTypeResolver); this.callResolver.setCandidateResolver(candidateResolver); this.callResolver.setExpressionTypingServices(expressionTypingServices); + this.callResolver.setExtension(needSyntheticCallResolverExtension); this.callResolver.setTypeResolver(typeResolver); annotationResolver.setCallResolver(callResolver); diff --git a/generators/org/jetbrains/jet/generators/injectors/GenerateInjectors.java b/generators/org/jetbrains/jet/generators/injectors/GenerateInjectors.java index 0ff749f5b92..4b685395a26 100644 --- a/generators/org/jetbrains/jet/generators/injectors/GenerateInjectors.java +++ b/generators/org/jetbrains/jet/generators/injectors/GenerateInjectors.java @@ -24,14 +24,13 @@ import org.jetbrains.jet.codegen.ScriptCodegen; import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods; import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.JetTypeMapper; -import org.jetbrains.jet.di.DependencyInjectorGenerator; -import org.jetbrains.jet.di.GivenExpression; -import org.jetbrains.jet.di.InjectorForTopDownAnalyzer; +import org.jetbrains.jet.di.*; import org.jetbrains.jet.lang.descriptors.ModuleDescriptor; import org.jetbrains.jet.lang.descriptors.ModuleDescriptorImpl; import org.jetbrains.jet.lang.psi.JetImportsFactory; import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.calls.CallResolver; +import org.jetbrains.jet.lang.resolve.calls.NeedSyntheticCallResolverExtension; import org.jetbrains.jet.lang.resolve.java.*; import org.jetbrains.jet.lang.resolve.lazy.ResolveSession; import org.jetbrains.jet.lang.resolve.lazy.ScopeProvider; @@ -74,6 +73,7 @@ public class GenerateInjectors { generator.addPublicField(AnnotationResolver.class); generator.addPublicField(QualifiedExpressionResolver.class); generator.addPublicField(JetImportsFactory.class); + generator.addField(NeedSyntheticCallResolverExtension.class); generator.generate("compiler/frontend/src", "org.jetbrains.jet.di", "InjectorForLazyResolve", GenerateInjectors.class); } @@ -131,6 +131,7 @@ public class GenerateInjectors { generator.addPublicField(ControlFlowAnalyzer.class); generator.addPublicField(DeclarationsChecker.class); generator.addPublicField(DescriptorResolver.class); + generator.addField(NeedSyntheticCallResolverExtension.class); // Parameters generator.addPublicParameter(Project.class); @@ -144,6 +145,7 @@ public class GenerateInjectors { // Fields generator.addPublicField(ExpressionTypingServices.class); + generator.addField(NeedSyntheticCallResolverExtension.class); // Parameters generator.addPublicParameter(Project.class); @@ -160,6 +162,7 @@ public class GenerateInjectors { generator.addPublicField(ExpressionTypingServices.class); generator.addPublicField(TypeResolver.class); generator.addPublicField(CallResolver.class); + generator.addField(NeedSyntheticCallResolverExtension.class); generator.addField(true, KotlinBuiltIns.class, null, new GivenExpression("KotlinBuiltIns.getInstance()")); // Parameters @@ -219,6 +222,7 @@ public class GenerateInjectors { DependencyInjectorGenerator generator = new DependencyInjectorGenerator(); // Fields generator.addPublicField(BodyResolver.class); + generator.addField(NeedSyntheticCallResolverExtension.class); // Parameters generator.addPublicParameter(Project.class); diff --git a/js/js.translator/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJs.java b/js/js.translator/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJs.java index 3d823a2b021..14976718021 100644 --- a/js/js.translator/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJs.java +++ b/js/js.translator/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJs.java @@ -22,6 +22,7 @@ import org.jetbrains.jet.lang.resolve.BodyResolver; import org.jetbrains.jet.lang.resolve.ControlFlowAnalyzer; import org.jetbrains.jet.lang.resolve.DeclarationsChecker; import org.jetbrains.jet.lang.resolve.DescriptorResolver; +import org.jetbrains.jet.lang.resolve.calls.NeedSyntheticCallResolverExtension; import com.intellij.openapi.project.Project; import org.jetbrains.jet.lang.resolve.TopDownAnalysisParameters; import org.jetbrains.jet.lang.resolve.BindingTrace; @@ -56,6 +57,7 @@ public class InjectorForTopDownAnalyzerForJs { private ControlFlowAnalyzer controlFlowAnalyzer; private DeclarationsChecker declarationsChecker; private DescriptorResolver descriptorResolver; + private NeedSyntheticCallResolverExtension needSyntheticCallResolverExtension; private final Project project; private final TopDownAnalysisParameters topDownAnalysisParameters; private final BindingTrace bindingTrace; @@ -91,6 +93,7 @@ public class InjectorForTopDownAnalyzerForJs { this.controlFlowAnalyzer = new ControlFlowAnalyzer(); this.declarationsChecker = new DeclarationsChecker(); this.descriptorResolver = new DescriptorResolver(); + this.needSyntheticCallResolverExtension = new NeedSyntheticCallResolverExtension(); this.project = project; this.topDownAnalysisParameters = topDownAnalysisParameters; this.bindingTrace = bindingTrace; @@ -162,6 +165,7 @@ public class InjectorForTopDownAnalyzerForJs { callResolver.setArgumentTypeResolver(argumentTypeResolver); callResolver.setCandidateResolver(candidateResolver); callResolver.setExpressionTypingServices(expressionTypingServices); + callResolver.setExtension(needSyntheticCallResolverExtension); callResolver.setTypeResolver(typeResolver); argumentTypeResolver.setExpressionTypingServices(expressionTypingServices);