diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 5aba7bf005c..3dec4fc7718 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -373,7 +373,9 @@ public class ExpressionCodegen extends KtVisitor impleme return labelTarget; } assert descriptor instanceof ClassDescriptor : "Don't know how to generate super-call to not a class"; - return getParentContextSubclassOf((ClassDescriptor) descriptor, context).getThisDescriptor(); + CodegenContext result = getParentContextSubclassOf((ClassDescriptor) descriptor, context); + assert result != null : "Can't find parent context for " + descriptor; + return result.getThisDescriptor(); } @NotNull @@ -2397,17 +2399,17 @@ public class ExpressionCodegen extends KtVisitor impleme return callable.invokeMethodWithArguments(resolvedCall, receiver, this); } + @Nullable // Find the first parent of the current context which corresponds to a subclass of a given class - @NotNull - private static CodegenContext getParentContextSubclassOf(ClassDescriptor descriptor, CodegenContext context) { + public static CodegenContext getParentContextSubclassOf(ClassDescriptor descriptor, CodegenContext context) { CodegenContext c = context; - while (true) { + while (c != null) { if (c instanceof ClassContext && DescriptorUtils.isSubclass(c.getThisDescriptor(), descriptor)) { return c; } c = c.getParentContext(); - assert c != null; } + return null; } @NotNull diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java index a7fb5ac1f7d..d592fe6e4ab 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/MemberCodegen.java @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations; import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl; import org.jetbrains.kotlin.fileClasses.FileClasses; import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider; +import org.jetbrains.kotlin.load.java.JavaVisibilities; import org.jetbrains.kotlin.load.java.JvmAbi; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.name.SpecialNames; @@ -65,7 +66,7 @@ import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive; import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED; import static org.jetbrains.kotlin.resolve.BindingContext.VARIABLE; import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject; -import static org.jetbrains.kotlin.resolve.DescriptorUtils.isTopLevelDeclaration; +import static org.jetbrains.kotlin.resolve.DescriptorUtils.isStaticDeclaration; import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*; import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN; import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt.Synthetic; @@ -637,7 +638,9 @@ public abstract class MemberCodegen { } } + if (descriptorContext == null && + JavaVisibilities.PROTECTED_STATIC_VISIBILITY == descriptor.getVisibility() && + !(descriptor instanceof SamConstructorDescriptor)) { + //seems we need static receiver in resolved call + descriptorContext = ExpressionCodegen.getParentContextSubclassOf((ClassDescriptor) enclosed, this); + superCallTarget = (ClassDescriptor) enclosed; + } + if (descriptorContext == null) { return descriptor; } diff --git a/compiler/testData/codegen/boxWithJava/statics/protectedSamConstructor/JavaClass.java b/compiler/testData/codegen/boxWithJava/statics/protectedSamConstructor/JavaClass.java new file mode 100644 index 00000000000..e8949e5a732 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/statics/protectedSamConstructor/JavaClass.java @@ -0,0 +1,10 @@ +public class JavaClass { + + public String runZ(Z z) { + return z.run("O", "K"); + } + + protected interface Z { + String run(String s1, String s2); + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/statics/protectedSamConstructor/Kotlin.kt b/compiler/testData/codegen/boxWithJava/statics/protectedSamConstructor/Kotlin.kt new file mode 100644 index 00000000000..7ea4551fdee --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/statics/protectedSamConstructor/Kotlin.kt @@ -0,0 +1,12 @@ +package zzz + +import JavaClass +import JavaClass.Z + +class A : JavaClass() { + fun test() = runZ(JavaClass.Z {a, b -> a + b}) +} + +fun box(): String { + return A().test() +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/statics/protectedStatic/First.java b/compiler/testData/codegen/boxWithJava/statics/protectedStatic/First.java new file mode 100644 index 00000000000..5dc5860e7b4 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/statics/protectedStatic/First.java @@ -0,0 +1,7 @@ +public abstract class First { + protected static String TEST = "OK"; + + protected static String test() { + return TEST; + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/statics/protectedStatic/First.kt b/compiler/testData/codegen/boxWithJava/statics/protectedStatic/First.kt new file mode 100644 index 00000000000..822826ed391 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/statics/protectedStatic/First.kt @@ -0,0 +1,23 @@ +package anotherPackage + +import First + +class Second : First() { + val some = { First.TEST } + fun foo() = { First.test() } + + val some2 = { TEST } + fun foo2() = { test() } +} + +fun box(): String { + if (Second().some.invoke() != "OK") return "fail 1" + + if (Second().foo().invoke() != "OK") return "fail 2" + + if (Second().some2.invoke() != "OK") return "fail 3" + + if (Second().foo2().invoke() != "OK") return "fail 4" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/statics/protectedStatic2/Base.java b/compiler/testData/codegen/boxWithJava/statics/protectedStatic2/Base.java new file mode 100644 index 00000000000..ca2c6f34927 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/statics/protectedStatic2/Base.java @@ -0,0 +1,22 @@ +public class Base { + + protected static String BASE_ONLY = "BASE"; + + protected static String baseOnly() { + return BASE_ONLY; + } + + protected static String TEST = "BASE"; + + protected static String test() { + return TEST; + } + + public static class Derived extends Base { + protected static String TEST = "DERIVED"; + + protected static String test() { + return TEST; + } + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/statics/protectedStatic2/Kotlin.kt b/compiler/testData/codegen/boxWithJava/statics/protectedStatic2/Kotlin.kt new file mode 100644 index 00000000000..bb1b8eb82d8 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/statics/protectedStatic2/Kotlin.kt @@ -0,0 +1,31 @@ +package anotherPackage + +import Base.Derived +import Base + +class Kotlin : Base.Derived() { + fun doTest(): String { + + if ({ TEST }() != "DERIVED") return "fail 1" + if ({ test() }() != "DERIVED") return "fail 2" + + if ({ Derived.TEST }() != "DERIVED") return "fail 3" + if ({ Derived.test() }() != "DERIVED") return "fail 4" + + if ({ Base.TEST }() != "BASE") return "fail 5" + if ({ Base.test() }() != "BASE") return "fail 6" + + + if ({ Base.BASE_ONLY }() != "BASE") return "fail 7" + if ({ Base.baseOnly() }() != "BASE") return "fail 8" + + if ({ BASE_ONLY }() != "BASE") return "fail 9" + if ({ baseOnly() }() != "BASE") return "fail 10" + + return "OK" + } +} + +fun box(): String { + return Kotlin().doTest() +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java index 22af32a5ef4..eea869b5faf 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java @@ -627,5 +627,23 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege doTestWithJava(fileName); } + @TestMetadata("protectedSamConstructor") + public void testProtectedSamConstructor() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/statics/protectedSamConstructor/"); + doTestWithJava(fileName); + } + + @TestMetadata("protectedStatic") + public void testProtectedStatic() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/statics/protectedStatic/"); + doTestWithJava(fileName); + } + + @TestMetadata("protectedStatic2") + public void testProtectedStatic2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/statics/protectedStatic2/"); + doTestWithJava(fileName); + } + } }