Fix for KT-11590: IllegalAccessError: SAM adapter generated with invalid accessibility for inline function
#KT-11590 Fixed
This commit is contained in:
@@ -2317,7 +2317,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Type asmType =
|
final Type asmType =
|
||||||
state.getSamWrapperClasses().getSamWrapperClass(samType, expression.getContainingKtFile(), getParentCodegen());
|
state.getSamWrapperClasses().getSamWrapperClass(samType, expression.getContainingKtFile(), this);
|
||||||
|
|
||||||
return StackValue.operation(asmType, new Function1<InstructionAdapter, Unit>() {
|
return StackValue.operation(asmType, new Function1<InstructionAdapter, Unit>() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2015 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.kotlin.codegen;
|
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
import com.intellij.openapi.util.Factory;
|
|
||||||
import com.intellij.openapi.util.Pair;
|
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
|
||||||
import org.jetbrains.kotlin.psi.KtFile;
|
|
||||||
import org.jetbrains.org.objectweb.asm.Type;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class SamWrapperClasses {
|
|
||||||
private final GenerationState state;
|
|
||||||
|
|
||||||
private final Map<Pair<SamType, KtFile>, Type> samInterfaceToWrapperClass = Maps.newHashMap();
|
|
||||||
|
|
||||||
public SamWrapperClasses(@NotNull GenerationState state) {
|
|
||||||
this.state = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public Type getSamWrapperClass(@NotNull final SamType samType, @NotNull final KtFile file, @NotNull final MemberCodegen<?> parentCodegen) {
|
|
||||||
return ContainerUtil.getOrCreate(samInterfaceToWrapperClass, Pair.create(samType, file),
|
|
||||||
new Factory<Type>() {
|
|
||||||
@Override
|
|
||||||
public Type create() {
|
|
||||||
return new SamWrapperCodegen(state, samType, parentCodegen).genWrapper(file);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 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.kotlin.codegen
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
|
||||||
|
class SamWrapperClasses(private val state: GenerationState) {
|
||||||
|
|
||||||
|
private data class WrapperKey(val samType: SamType, val file: KtFile, val insideInline: Boolean)
|
||||||
|
|
||||||
|
private val samInterfaceToWrapperClass = hashMapOf<WrapperKey, Type>()
|
||||||
|
|
||||||
|
fun getSamWrapperClass(samType: SamType, file: KtFile, expressionCodegen: ExpressionCodegen): Type {
|
||||||
|
val isInsideInline = InlineUtil.isInlineOrContainingInline(expressionCodegen.context.contextDescriptor)
|
||||||
|
return samInterfaceToWrapperClass.getOrPut(WrapperKey(samType, file, isInsideInline)) {
|
||||||
|
SamWrapperCodegen(state, samType, expressionCodegen.parentCodegen, isInsideInline).genWrapper(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,17 +49,27 @@ public class SamWrapperCodegen {
|
|||||||
private static final String FUNCTION_FIELD_NAME = "function";
|
private static final String FUNCTION_FIELD_NAME = "function";
|
||||||
|
|
||||||
private final GenerationState state;
|
private final GenerationState state;
|
||||||
|
private final boolean isInsideInline;
|
||||||
private final KotlinTypeMapper typeMapper;
|
private final KotlinTypeMapper typeMapper;
|
||||||
private final SamType samType;
|
private final SamType samType;
|
||||||
private final MemberCodegen<?> parentCodegen;
|
private final MemberCodegen<?> parentCodegen;
|
||||||
|
private final int visibility;
|
||||||
|
|
||||||
public SamWrapperCodegen(@NotNull GenerationState state, @NotNull SamType samType, @NotNull MemberCodegen<?> parentCodegen) {
|
public SamWrapperCodegen(
|
||||||
|
@NotNull GenerationState state,
|
||||||
|
@NotNull SamType samType,
|
||||||
|
@NotNull MemberCodegen<?> parentCodegen,
|
||||||
|
boolean isInsideInline
|
||||||
|
) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
|
this.isInsideInline = isInsideInline;
|
||||||
this.typeMapper = state.getTypeMapper();
|
this.typeMapper = state.getTypeMapper();
|
||||||
this.samType = samType;
|
this.samType = samType;
|
||||||
this.parentCodegen = parentCodegen;
|
this.parentCodegen = parentCodegen;
|
||||||
|
visibility = isInsideInline ? ACC_PUBLIC : NO_FLAG_PACKAGE_PRIVATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
public Type genWrapper(@NotNull KtFile file) {
|
public Type genWrapper(@NotNull KtFile file) {
|
||||||
// Name for generated class, in form of whatever$1
|
// Name for generated class, in form of whatever$1
|
||||||
FqName fqName = getWrapperName(file);
|
FqName fqName = getWrapperName(file);
|
||||||
@@ -88,7 +98,7 @@ public class SamWrapperCodegen {
|
|||||||
ClassBuilder cv = state.getFactory().newVisitor(JvmDeclarationOriginKt.OtherOrigin(erasedInterfaceFunction), asmType, file);
|
ClassBuilder cv = state.getFactory().newVisitor(JvmDeclarationOriginKt.OtherOrigin(erasedInterfaceFunction), asmType, file);
|
||||||
cv.defineClass(file,
|
cv.defineClass(file,
|
||||||
V1_6,
|
V1_6,
|
||||||
ACC_FINAL | ACC_SUPER,
|
ACC_FINAL | ACC_SUPER | visibility,
|
||||||
asmType.getInternalName(),
|
asmType.getInternalName(),
|
||||||
null,
|
null,
|
||||||
OBJECT_TYPE.getInternalName(),
|
OBJECT_TYPE.getInternalName(),
|
||||||
@@ -118,7 +128,7 @@ public class SamWrapperCodegen {
|
|||||||
|
|
||||||
private void generateConstructor(Type ownerType, Type functionType, ClassBuilder cv) {
|
private void generateConstructor(Type ownerType, Type functionType, ClassBuilder cv) {
|
||||||
MethodVisitor mv = cv.newMethod(JvmDeclarationOriginKt.OtherOrigin(samType.getJavaClassDescriptor()),
|
MethodVisitor mv = cv.newMethod(JvmDeclarationOriginKt.OtherOrigin(samType.getJavaClassDescriptor()),
|
||||||
NO_FLAG_PACKAGE_PRIVATE, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, functionType), null, null);
|
visibility, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, functionType), null, null);
|
||||||
|
|
||||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
@@ -177,9 +187,10 @@ public class SamWrapperCodegen {
|
|||||||
int hash = PackagePartClassUtils.getPathHashCode(containingFile.getVirtualFile()) * 31 +
|
int hash = PackagePartClassUtils.getPathHashCode(containingFile.getVirtualFile()) * 31 +
|
||||||
DescriptorUtils.getFqNameSafe(descriptor).hashCode();
|
DescriptorUtils.getFqNameSafe(descriptor).hashCode();
|
||||||
String shortName = String.format(
|
String shortName = String.format(
|
||||||
"%s$sam$%s$%08x",
|
"%s$sam$%s%s$%08x",
|
||||||
fileClassFqName.shortName().asString(),
|
fileClassFqName.shortName().asString(),
|
||||||
descriptor.getName().asString(),
|
descriptor.getName().asString(),
|
||||||
|
(isInsideInline ? "$i" : ""),
|
||||||
hash
|
hash
|
||||||
);
|
);
|
||||||
return fileClassFqName.parent().child(Name.identifier(shortName));
|
return fileClassFqName.parent().child(Name.identifier(shortName));
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// FILE: 1.kt
|
||||||
|
package test
|
||||||
|
|
||||||
|
inline fun <reified T> makeRunnable(noinline lambda: ()->Unit) : Runnable {
|
||||||
|
return Runnable(lambda)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: 2.kt
|
||||||
|
|
||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var result = "fail"
|
||||||
|
|
||||||
|
makeRunnable<String> { result = "OK" }.run()
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
inline fun <reified T> makeRunnable(noinline lambda: ()->Unit) : Runnable {
|
||||||
|
return Runnable(lambda)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun makeRunnable2(noinline lambda: ()->Unit) : Runnable {
|
||||||
|
return Runnable(lambda)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun noInline(lambda: ()->Unit) : Runnable {
|
||||||
|
return Runnable(lambda)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun noInline2(lambda: ()->Unit) : Runnable {
|
||||||
|
return Runnable(lambda)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1 final class test/_1Kt\$sam\$Runnable\$89f9321c
|
||||||
|
// 1 public final class test/_1Kt\$sam\$Runnable\$i\$89f9321c
|
||||||
|
// 2 class test/_1Kt\$sam\$
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
@kotlin.Metadata
|
||||||
|
final class test/SamAdapterAndInlinedOneKt$sam$Runnable$82391ccd {
|
||||||
|
private synthetic final field function: kotlin.jvm.functions.Function0
|
||||||
|
method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||||
|
public synthetic final method run(): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class test/SamAdapterAndInlinedOneKt$sam$Runnable$i$82391ccd {
|
||||||
|
private synthetic final field function: kotlin.jvm.functions.Function0
|
||||||
|
public method <init>(p0: kotlin.jvm.functions.Function0): void
|
||||||
|
public synthetic final method run(): void
|
||||||
|
}
|
||||||
|
|
||||||
|
@kotlin.Metadata
|
||||||
|
public final class test/SamAdapterAndInlinedOneKt {
|
||||||
|
private final static method makeRunnable(p0: kotlin.jvm.functions.Function0): java.lang.Runnable
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method makeRunnable2(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.Runnable
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method noInline(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.Runnable
|
||||||
|
public final static @org.jetbrains.annotations.NotNull method noInline2(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function0): java.lang.Runnable
|
||||||
|
}
|
||||||
@@ -175,6 +175,12 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("sam.kt")
|
||||||
|
public void testSam() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/sam.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/enumWhen")
|
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/enumWhen")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
@@ -59,6 +59,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("samAdapterAndInlinedOne.kt")
|
||||||
|
public void testSamAdapterAndInlinedOne() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/samAdapterAndInlinedOne.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/bytecodeListing/annotations")
|
@TestMetadata("compiler/testData/codegen/bytecodeListing/annotations")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
+6
@@ -175,6 +175,12 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("sam.kt")
|
||||||
|
public void testSam() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/anonymousObject/sam.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/enumWhen")
|
@TestMetadata("compiler/testData/codegen/boxInline/anonymousObject/enumWhen")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
Reference in New Issue
Block a user