Type parameters mapping

#KT-10429 Fixed
This commit is contained in:
Michael Bogdanov
2015-12-23 14:47:05 +03:00
parent 5cdf170511
commit fee6d4f282
19 changed files with 312 additions and 73 deletions
@@ -2429,7 +2429,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
@NotNull
protected CallGenerator getOrCreateCallGenerator(
private CallGenerator getOrCreateCallGenerator(
@NotNull CallableDescriptor descriptor,
@Nullable KtElement callElement,
@Nullable TypeParameterMappings typeParameterMappings
@@ -2448,7 +2448,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
@NotNull
public CallGenerator getOrCreateCallGenerator(@NotNull FunctionDescriptor descriptor, @Nullable KtNamedFunction function) {
protected CallGenerator getOrCreateCallGeneratorForDefaultImplBody(@NotNull FunctionDescriptor descriptor, @Nullable KtNamedFunction function) {
return getOrCreateCallGenerator(descriptor, function, null);
}
@@ -21,7 +21,6 @@ import com.intellij.psi.PsiElement;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -29,7 +28,6 @@ import org.jetbrains.kotlin.backend.common.bridges.Bridge;
import org.jetbrains.kotlin.backend.common.bridges.ImplKt;
import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithOnlyTargetedAnnotations;
import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics;
import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
@@ -699,7 +697,7 @@ public class FunctionCodegen {
ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, signature.getReturnType(), methodContext, state, parentCodegen);
CallGenerator generator = codegen.getOrCreateCallGenerator(functionDescriptor, function);
CallGenerator generator = codegen.getOrCreateCallGeneratorForDefaultImplBody(functionDescriptor, function);
loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator);
@@ -347,7 +347,7 @@ public class AnonymousObjectTransformer {
return new RemappingClassBuilder(
classBuilder,
new AsmTypeRemapper(inliningContext.typeRemapper, inliningContext.getRoot().typeParameterMappings, transformationResult)
new AsmTypeRemapper(inliningContext.typeRemapper, inliningContext.getRoot().typeParameterMappings == null, transformationResult)
);
}
@@ -21,24 +21,22 @@ import org.jetbrains.org.objectweb.asm.commons.RemappingSignatureAdapter
import org.jetbrains.org.objectweb.asm.signature.SignatureReader
import org.jetbrains.org.objectweb.asm.signature.SignatureVisitor
class AsmTypeRemapper(val typeRemapper: TypeRemapper, val mappings: TypeParameterMappings?, val result: InlineResult) : Remapper() {
class AsmTypeRemapper(val typeRemapper: TypeRemapper, val isDefaultGeneration: Boolean, val result: InlineResult) : Remapper() {
override fun map(type: String): String {
return typeRemapper.map(type)
}
override fun createRemappingSignatureAdapter(v: SignatureVisitor?): SignatureVisitor {
if (mappings == null) {
//don't remap default generation
if (isDefaultGeneration) {
return super.createRemappingSignatureAdapter(v);
}
return object : RemappingSignatureAdapter(v, this) {
override fun visitTypeVariable(name: String) {
val mapping = getMappingByName(name) ?:
return super.visitTypeVariable(name)
/*TODO try to erase absent type variable*/
val mapping = typeRemapper.mapTypeParameter(name) ?: return super.visitTypeVariable(name)
if (mapping.newName != null) {
if (mapping.isReified) {
@@ -51,19 +49,9 @@ class AsmTypeRemapper(val typeRemapper: TypeRemapper, val mappings: TypeParamete
}
override fun visitFormalTypeParameter(name: String) {
val mapping: TypeParameterMapping = getMappingByName(name) ?:
return super.visitFormalTypeParameter(name)
if (mapping.newName != null ) {
if (mapping.isReified) {
result.reifiedTypeParametersUsages.addUsedReifiedParameter(mapping.newName)
}
super.visitFormalTypeParameter(mapping.newName)
}
typeRemapper.registerTypeParameter(name)
super.visitFormalTypeParameter(name)
}
private fun getMappingByName(name: String): TypeParameterMapping? = mappings[name]
}
}
}
@@ -82,7 +82,7 @@ public class InliningContext {
@NotNull AnonymousObjectGeneration anonymousObjectGeneration
) {
return new RegeneratedClassContext(this, expressionMap, state, generator,
new TypeRemapper(typeRemapper, newTypeMappings),
TypeRemapper.createFrom(typeRemapper, newTypeMappings),
reifedTypeInliner, isInliningLambda, anonymousObjectGeneration);
}
@@ -97,7 +97,7 @@ public class InliningContext {
boolean isRegeneration
) {
return new InliningContext(this, expressionMap, state, generator,
new TypeRemapper(typeRemapper, additionalTypeMappings), reifedTypeInliner, isInliningLambda, isRegeneration);
TypeRemapper.createFrom(typeRemapper, additionalTypeMappings), reifedTypeInliner, isInliningLambda, isRegeneration);
}
public boolean isRoot() {
@@ -158,7 +158,7 @@ public class MethodInliner {
resultNode.access,
resultNode.desc,
resultNode,
new AsmTypeRemapper(remapper, inliningContext.getRoot().typeParameterMappings, result)
new AsmTypeRemapper(remapper, inliningContext.getRoot().typeParameterMappings == null, result)
);
final int markerShift = InlineCodegenUtil.calcMarkerShift(parameters, node);
@@ -232,6 +232,10 @@ class TypeParameterMappings() {
}
fun hasReifiedParameters() = mappingsByName.values.any { it.isReified }
internal inline fun forEach(l: (TypeParameterMapping) -> Unit) {
mappingsByName.values.forEach(l)
}
}
class TypeParameterMapping(
@@ -40,7 +40,7 @@ public class RootInliningContext extends InliningContext {
@NotNull ReifiedTypeInliner inliner,
@Nullable TypeParameterMappings typeParameterMappings
) {
super(null, map, state, nameGenerator, TypeRemapper.createEmpty(), inliner, false, false);
super(null, map, state, nameGenerator, TypeRemapper.createRoot(typeParameterMappings), inliner, false, false);
this.callElement = callElement;
this.startContext = startContext;
this.classNameToInline = classNameToInline;
@@ -14,69 +14,76 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.codegen.inline;
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.annotations.NotNull;
import java.util.HashMap
import java.util.HashMap;
import java.util.Map;
class TypeParameter(val oldName: String, val newName: String?, val isReified: Boolean, val signature: String?)
public class TypeRemapper {
//typeMapping field could be changed outside through method processing
private final Map<String, String> typeMapping;
//typeMapping data could be changed outside through method processing
class TypeRemapper private constructor(private val typeMapping: MutableMap<String, String>, val parent: TypeRemapper?) {
private Map<String, String> additionalMappings;
private var additionalMappings: MutableMap<String, String> = hashMapOf()
//typeMapping field could be changed outside through method processing
private TypeRemapper(@NotNull Map<String, String> typeMapping) {
this.typeMapping = typeMapping;
private val typeParametersMapping: MutableMap<String, TypeParameter> = hashMapOf()
fun addMapping(type: String, newType: String) {
typeMapping.put(type, newType)
}
public TypeRemapper(@NotNull TypeRemapper remapper, @NotNull Map<String, String> newTypeMappings) {
this(createNewAndMerge(remapper, newTypeMappings));
fun hasNoAdditionalMapping(type: String): Boolean {
return typeMapping.containsKey(type)
}
public static TypeRemapper createEmpty() {
return new TypeRemapper(new HashMap<String, String>());
fun map(type: String): String {
return typeMapping[type] ?: additionalMappings?.get(type) ?: type
}
public static TypeRemapper createFrom(Map<String, String> mappings) {
return new TypeRemapper(mappings);
fun addAdditionalMappings(oldName: String, newName: String) {
additionalMappings!!.put(oldName, newName)
}
@NotNull
private static Map<String, String> createNewAndMerge(@NotNull TypeRemapper remapper, @NotNull Map<String, String> additionalTypeMappings) {
Map<String, String> map = new HashMap<String, String>(remapper.typeMapping);
map.putAll(additionalTypeMappings);
return map;
}
public void addMapping(String type, String newType) {
typeMapping.put(type, newType);
}
public boolean hasNoAdditionalMapping(String type) {
return typeMapping.containsKey(type);
}
public String map(String type) {
String newType = typeMapping.get(type);
if (newType != null) {
return newType;
fun registerTypeParameter(name: String) {
assert(typeParametersMapping[name] == null) {
"Type parameter already registered $name"
}
typeParametersMapping[name] = TypeParameter(name, name, false, null)
}
if (additionalMappings != null) {
newType = additionalMappings.get(type);
if (newType != null) {
return newType;
fun registerTypeParameter(mapping: TypeParameterMapping) {
typeParametersMapping[mapping.name] = TypeParameter(mapping.name, mapping.newName, mapping.isReified, mapping.signature)
}
fun mapTypeParameter(name: String): TypeParameter? {
return typeParametersMapping[name] ?: parent?.mapTypeParameter(name)
}
companion object {
@JvmStatic
fun createRoot(formalTypeParameters: TypeParameterMappings?): TypeRemapper {
val typeRemapper = TypeRemapper(HashMap<String, String>(), null)
formalTypeParameters?.forEach {
typeRemapper.registerTypeParameter(it)
}
return typeRemapper
}
return type;
}
@JvmStatic
fun createFrom(mappings: MutableMap<String, String>): TypeRemapper {
return TypeRemapper(mappings, null)
}
public void addAdditionalMappings(String oldName, String newName) {
if (additionalMappings == null) additionalMappings = new HashMap<String, String>();
additionalMappings.put(oldName, newName);
@JvmStatic
fun createFrom(remapper: TypeRemapper, mappings: MutableMap<String, String>): TypeRemapper {
return TypeRemapper(createNewAndMerge(remapper, mappings), remapper)
}
private fun createNewAndMerge(remapper: TypeRemapper, additionalTypeMappings: Map<String, String>): MutableMap<String, String> {
val map = HashMap(remapper.typeMapping)
map += additionalTypeMappings
return map
}
}
}
@@ -0,0 +1,19 @@
// NO_CHECK_LAMBDA_INLINING
// FULL_JDK
import test.*
import java.util.*
fun box(): String {
val result = Test().callInline()
val method = result.javaClass.getMethod("aTest", Any::class.java)
val genericReturnType = method.genericReturnType
if (genericReturnType.toString() != "test.B<T>") return "fail 1: ${genericReturnType}"
val genericParameterTypes = method.genericParameterTypes
if (genericParameterTypes.size != 1) return "fail 2: ${genericParameterTypes.size}"
if (genericParameterTypes[0].toString() != "T") return "fail 3: ${genericParameterTypes[0]}"
return "OK"
}
@@ -0,0 +1,19 @@
package test
class B<T>
interface A {
fun <T> aTest(p: T): B<T>
}
open class Test {
inline fun <T> test(crossinline z: () -> Int) = object : A {
override fun <T> aTest(p: T): B<T> {
z()
return B<T>()
}
}
fun callInline() = test<String> { 1 }
}
@@ -0,0 +1,19 @@
// NO_CHECK_LAMBDA_INLINING
// FULL_JDK
import test.*
import java.util.*
fun box(): String {
val result = Test().callInline()
val method = result.javaClass.getMethod("aTest", Any::class.java)
val genericReturnType = method.genericReturnType
if (genericReturnType.toString() != "test.B<T>") return "fail 1: ${genericReturnType}"
val genericParameterTypes = method.genericParameterTypes
if (genericParameterTypes.size != 1) return "fail 2: ${genericParameterTypes.size}"
if (genericParameterTypes[0].toString() != "T") return "fail 3: ${genericParameterTypes[0]}"
return "OK"
}
@@ -0,0 +1,19 @@
package test
class B<T>
interface A {
fun <T> aTest(p: T): B<T>
}
open class Test {
inline fun <reified T> test(crossinline z: () -> Int) = object : A {
override fun <T> aTest(p: T): B<T> {
z()
return B<T>()
}
}
fun callInline() = test<String> { 1 }
}
@@ -0,0 +1,26 @@
//NO_CHECK_LAMBDA_INLINING
import test.*
import java.util.*
fun box(): String {
val comparable = CustomerService().comparator<String>()
val method = comparable.javaClass.getMethod("compare", Any::class.java, Any::class.java)
val genericParameterTypes = method.genericParameterTypes
if (genericParameterTypes.size != 2) return "fail 1: ${genericParameterTypes.size}"
if (genericParameterTypes[0].toString() != "T") return "fail 2: ${genericParameterTypes[0]}"
if (genericParameterTypes[1].toString() != "T") return "fail 3: ${genericParameterTypes[1]}"
val comparable2 = CustomerService().callInline()
val method2 = comparable2.javaClass.getMethod("compare", Any::class.java, Any::class.java)
val genericParameterTypes2 = method2.genericParameterTypes
if (genericParameterTypes2.size != 2) return "fail 4: ${genericParameterTypes2.size}"
var name = (genericParameterTypes2[0] as Class<*>).name
if (name != "java.lang.String") return "fail 5: ${name}"
name = (genericParameterTypes2[1] as Class<*>).name
if (name != "java.lang.String") return "fail 6: ${name}"
return "OK"
}
@@ -0,0 +1,24 @@
package test
import java.util.*
open class CustomerService {
fun <T> comparator() = object : Comparator<T> {
override fun compare(o1: T, o2: T): Int {
throw UnsupportedOperationException()
}
}
inline fun <T> comparator(crossinline z: () -> Int) = object : Comparator<T> {
override fun compare(o1: T, o2: T): Int {
return z()
}
}
fun callInline() = comparator<String> { 1 }
}
@@ -0,0 +1,25 @@
//NO_CHECK_LAMBDA_INLINING
import test.*
fun box(): String {
val comparable = CustomerService().comparator<String>()
val method = comparable.javaClass.getMethod("compare", Any::class.java, Any::class.java)
val genericParameterTypes = method.genericParameterTypes
if (genericParameterTypes.size != 2) return "fail 1: ${genericParameterTypes.size}"
if (genericParameterTypes[0].toString() != "T") return "fail 2: ${genericParameterTypes[0]}"
if (genericParameterTypes[1].toString() != "T") return "fail 3: ${genericParameterTypes[1]}"
val comparable2 = CustomerService().callInline()
val method2 = comparable2.javaClass.getMethod("compare", Any::class.java, Any::class.java)
val genericParameterTypes2 = method2.genericParameterTypes
if (genericParameterTypes2.size != 2) return "fail 1: ${genericParameterTypes2.size}"
var name = (genericParameterTypes2[0] as Class<*>).name
if (name != "java.lang.String") return "fail 5: ${name}"
name = (genericParameterTypes2[1] as Class<*>).name
if (name != "java.lang.String") return "fail 6: ${name}"
return "OK"
}
@@ -0,0 +1,25 @@
package test
interface MComparator<T> {
fun compare(o1: T, o2: T): Int
}
open class CustomerService {
fun <T> comparator() = object : MComparator<T> {
override fun compare(o1: T, o2: T): Int {
throw UnsupportedOperationException()
}
}
inline fun <T> comparator(crossinline z: () -> Int) = object : MComparator<T> {
override fun compare(o1: T, o2: T): Int {
return z()
}
}
fun callInline() = comparator<String> { 1 }
}
@@ -1382,6 +1382,39 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
}
}
@TestMetadata("compiler/testData/codegen/boxInline/signature")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Signature extends AbstractBlackBoxInlineCodegenTest {
public void testAllFilesPresentInSignature() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/signature"), Pattern.compile("^(.+)\\.1.kt$"), true);
}
@TestMetadata("sameFormalParameterName.1.kt")
public void testSameFormalParameterName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/sameFormalParameterName.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("sameReifiedFormalParameterName.1.kt")
public void testSameReifiedFormalParameterName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/sameReifiedFormalParameterName.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("typeParametersSubstitution.1.kt")
public void testTypeParametersSubstitution() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/typeParametersSubstitution.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
@TestMetadata("typeParametersSubstitution2.1.kt")
public void testTypeParametersSubstitution2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/typeParametersSubstitution2.1.kt");
doTestMultiFileWithInlineCheck(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/simple")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -1382,6 +1382,39 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
}
}
@TestMetadata("compiler/testData/codegen/boxInline/signature")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Signature extends AbstractCompileKotlinAgainstInlineKotlinTest {
public void testAllFilesPresentInSignature() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/signature"), Pattern.compile("^(.+)\\.1.kt$"), true);
}
@TestMetadata("sameFormalParameterName.1.kt")
public void testSameFormalParameterName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/sameFormalParameterName.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("sameReifiedFormalParameterName.1.kt")
public void testSameReifiedFormalParameterName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/sameReifiedFormalParameterName.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("typeParametersSubstitution.1.kt")
public void testTypeParametersSubstitution() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/typeParametersSubstitution.1.kt");
doBoxTestWithInlineCheck(fileName);
}
@TestMetadata("typeParametersSubstitution2.1.kt")
public void testTypeParametersSubstitution2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/signature/typeParametersSubstitution2.1.kt");
doBoxTestWithInlineCheck(fileName);
}
}
@TestMetadata("compiler/testData/codegen/boxInline/simple")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)