Fix for KT-4250: IllegalAccessError when using protected java member from lambda function
#KT-4250 Fixed
This commit is contained in:
@@ -373,7 +373,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
return labelTarget;
|
return labelTarget;
|
||||||
}
|
}
|
||||||
assert descriptor instanceof ClassDescriptor : "Don't know how to generate super-call to not a class";
|
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
|
@NotNull
|
||||||
@@ -2397,17 +2399,17 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
return callable.invokeMethodWithArguments(resolvedCall, receiver, this);
|
return callable.invokeMethodWithArguments(resolvedCall, receiver, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
// Find the first parent of the current context which corresponds to a subclass of a given class
|
// Find the first parent of the current context which corresponds to a subclass of a given class
|
||||||
@NotNull
|
public static CodegenContext getParentContextSubclassOf(ClassDescriptor descriptor, CodegenContext context) {
|
||||||
private static CodegenContext getParentContextSubclassOf(ClassDescriptor descriptor, CodegenContext context) {
|
|
||||||
CodegenContext c = context;
|
CodegenContext c = context;
|
||||||
while (true) {
|
while (c != null) {
|
||||||
if (c instanceof ClassContext && DescriptorUtils.isSubclass(c.getThisDescriptor(), descriptor)) {
|
if (c instanceof ClassContext && DescriptorUtils.isSubclass(c.getThisDescriptor(), descriptor)) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
c = c.getParentContext();
|
c = c.getParentContext();
|
||||||
assert c != null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
|||||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
|
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
|
||||||
import org.jetbrains.kotlin.fileClasses.FileClasses;
|
import org.jetbrains.kotlin.fileClasses.FileClasses;
|
||||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
|
import org.jetbrains.kotlin.fileClasses.JvmFileClassesProvider;
|
||||||
|
import org.jetbrains.kotlin.load.java.JavaVisibilities;
|
||||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||||
import org.jetbrains.kotlin.name.Name;
|
import org.jetbrains.kotlin.name.Name;
|
||||||
import org.jetbrains.kotlin.name.SpecialNames;
|
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.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
|
||||||
import static org.jetbrains.kotlin.resolve.BindingContext.VARIABLE;
|
import static org.jetbrains.kotlin.resolve.BindingContext.VARIABLE;
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
|
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.AsmTypes.*;
|
||||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
|
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
|
||||||
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt.Synthetic;
|
import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt.Synthetic;
|
||||||
@@ -637,7 +638,9 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
|
|||||||
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
|
public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
|
||||||
boolean syntheticBackingField = accessor instanceof AccessorForPropertyBackingFieldFromLocal;
|
boolean syntheticBackingField = accessor instanceof AccessorForPropertyBackingFieldFromLocal;
|
||||||
boolean forceField = (AsmUtil.isPropertyWithBackingFieldInOuterClass(original) &&
|
boolean forceField = (AsmUtil.isPropertyWithBackingFieldInOuterClass(original) &&
|
||||||
!isCompanionObject(accessor.getContainingDeclaration())) || syntheticBackingField;
|
!isCompanionObject(accessor.getContainingDeclaration())) ||
|
||||||
|
syntheticBackingField ||
|
||||||
|
original.getVisibility() == JavaVisibilities.PROTECTED_STATIC_VISIBILITY;
|
||||||
StackValue property = codegen.intermediateValueForProperty(
|
StackValue property = codegen.intermediateValueForProperty(
|
||||||
original, forceField, syntheticBackingField, accessor.getSuperCallTarget(), true, StackValue.none()
|
original, forceField, syntheticBackingField, accessor.getSuperCallTarget(), true, StackValue.none()
|
||||||
);
|
);
|
||||||
@@ -696,15 +699,15 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
|
|||||||
((AccessorForCallableDescriptor) accessorDescriptor).getSuperCallTarget() != null
|
((AccessorForCallableDescriptor) accessorDescriptor).getSuperCallTarget() != null
|
||||||
);
|
);
|
||||||
|
|
||||||
boolean isTopLevelDeclaration = isTopLevelDeclaration(functionDescriptor);
|
boolean hasDispatchReceiver = !isStaticDeclaration(functionDescriptor);
|
||||||
int reg = isTopLevelDeclaration ? 0 : 1;
|
int reg = hasDispatchReceiver ? 1 : 0;
|
||||||
boolean accessorIsConstructor = accessorDescriptor instanceof AccessorForConstructorDescriptor;
|
boolean accessorIsConstructor = accessorDescriptor instanceof AccessorForConstructorDescriptor;
|
||||||
if (!accessorIsConstructor && functionDescriptor instanceof ConstructorDescriptor) {
|
if (!accessorIsConstructor && functionDescriptor instanceof ConstructorDescriptor) {
|
||||||
iv.anew(callableMethod.getOwner());
|
iv.anew(callableMethod.getOwner());
|
||||||
iv.dup();
|
iv.dup();
|
||||||
reg = 0;
|
reg = 0;
|
||||||
}
|
}
|
||||||
else if (accessorIsConstructor || (accessorDescriptor != null && JetTypeMapper.isAccessor(accessorDescriptor) && !isTopLevelDeclaration)) {
|
else if (accessorIsConstructor || (accessorDescriptor != null && JetTypeMapper.isAccessor(accessorDescriptor) && hasDispatchReceiver)) {
|
||||||
if (!AnnotationUtilKt.isPlatformStaticInObjectOrClass(functionDescriptor)) {
|
if (!AnnotationUtilKt.isPlatformStaticInObjectOrClass(functionDescriptor)) {
|
||||||
iv.load(0, OBJECT_TYPE);
|
iv.load(0, OBJECT_TYPE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,12 +24,15 @@ import org.jetbrains.kotlin.codegen.binding.MutableClosure;
|
|||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
||||||
import org.jetbrains.kotlin.descriptors.*;
|
import org.jetbrains.kotlin.descriptors.*;
|
||||||
|
import org.jetbrains.kotlin.load.java.JavaVisibilities;
|
||||||
|
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
|
||||||
import org.jetbrains.kotlin.psi.KtFile;
|
import org.jetbrains.kotlin.psi.KtFile;
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
|
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
|
||||||
import org.jetbrains.kotlin.storage.NullableLazyValue;
|
import org.jetbrains.kotlin.storage.NullableLazyValue;
|
||||||
import org.jetbrains.kotlin.types.KotlinType;
|
import org.jetbrains.kotlin.types.KotlinType;
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils;
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
import org.jetbrains.org.objectweb.asm.Type;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -544,6 +547,14 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
if (descriptorContext == null) {
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|||||||
+10
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -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()
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
public abstract class First {
|
||||||
|
protected static String TEST = "OK";
|
||||||
|
|
||||||
|
protected static String test() {
|
||||||
|
return TEST;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
+18
@@ -627,5 +627,23 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
|
|||||||
doTestWithJava(fileName);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user