Supported nested reified parameter declarations
Also switched to using type names as identifiers instead of their indices
This commit is contained in:
@@ -207,28 +207,24 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
);
|
||||
literalCodegen.generate();
|
||||
|
||||
if (containsReifiedParametersInSupertypes(classDescriptor)) {
|
||||
literalCodegen.setWereReifierMarkers(true);
|
||||
}
|
||||
addReifiedParametersFromSignature(literalCodegen, classDescriptor);
|
||||
propagateChildReifiedTypeParametersUsages(literalCodegen.getReifiedTypeParametersUsages());
|
||||
|
||||
if (literalCodegen.wereReifierMarkers()) {
|
||||
getParentCodegen().setWereReifierMarkers(true);
|
||||
}
|
||||
|
||||
return new ObjectLiteralResult(literalCodegen.wereReifierMarkers(), classDescriptor);
|
||||
return new ObjectLiteralResult(
|
||||
literalCodegen.getReifiedTypeParametersUsages().wereUsedReifiedParameters(),
|
||||
classDescriptor
|
||||
);
|
||||
}
|
||||
|
||||
private static boolean containsReifiedParametersInSupertypes(@NotNull ClassDescriptor descriptor) {
|
||||
private static void addReifiedParametersFromSignature(@NotNull MemberCodegen member, @NotNull ClassDescriptor descriptor) {
|
||||
for (JetType type : descriptor.getTypeConstructor().getSupertypes()) {
|
||||
for (TypeProjection supertypeArgument : type.getArguments()) {
|
||||
TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(supertypeArgument.getType());
|
||||
if (parameterDescriptor != null && parameterDescriptor.isReified()) {
|
||||
return true;
|
||||
member.getReifiedTypeParametersUsages().addUsedReifiedParameter(parameterDescriptor.getName().asString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class ObjectLiteralResult {
|
||||
@@ -1404,8 +1400,9 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
|
||||
closureCodegen.generate();
|
||||
|
||||
if (closureCodegen.wereReifierMarkers()) {
|
||||
if (closureCodegen.getReifiedTypeParametersUsages().wereUsedReifiedParameters()) {
|
||||
ReifiedTypeInliner.putNeedClassReificationMarker(v);
|
||||
propagateChildReifiedTypeParametersUsages(closureCodegen.getReifiedTypeParametersUsages());
|
||||
}
|
||||
|
||||
return closureCodegen.putInstanceOnStack(this);
|
||||
@@ -2304,7 +2301,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
@NotNull
|
||||
private CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
Map<TypeParameterDescriptor, JetType> typeArguments = resolvedCall.getTypeArguments();
|
||||
ReifiedTypeParameterMappings mappings = new ReifiedTypeParameterMappings(typeArguments.size());
|
||||
ReifiedTypeParameterMappings mappings = new ReifiedTypeParameterMappings();
|
||||
for (Map.Entry<TypeParameterDescriptor, JetType> entry : typeArguments.entrySet()) {
|
||||
TypeParameterDescriptor key = entry.getKey();
|
||||
if (!key.isReified()) continue;
|
||||
@@ -2314,16 +2311,13 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
// type is not generic
|
||||
// boxType call needed because inlined method is compiled for T as java/lang/Object
|
||||
mappings.addParameterMappingToType(
|
||||
key.getIndex(),
|
||||
key.getName().getIdentifier(),
|
||||
boxType(asmType(entry.getValue()))
|
||||
);
|
||||
}
|
||||
else {
|
||||
mappings.addParameterMappingToNewParameter(
|
||||
key.getIndex(),
|
||||
key.getName().getIdentifier(),
|
||||
parameterDescriptor.getIndex(),
|
||||
parameterDescriptor.getName().getIdentifier()
|
||||
);
|
||||
}
|
||||
@@ -3901,15 +3895,23 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
public void putReifierMarkerIfTypeIsReifiedParameter(@NotNull JetType type, @NotNull String markerMethodName) {
|
||||
TypeParameterDescriptor typeParameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(type);
|
||||
if (typeParameterDescriptor != null && typeParameterDescriptor.isReified()) {
|
||||
parentCodegen.setWereReifierMarkers(true);
|
||||
v.iconst(typeParameterDescriptor.getIndex());
|
||||
if (typeParameterDescriptor.getContainingDeclaration() != context.getContextDescriptor()) {
|
||||
parentCodegen.getReifiedTypeParametersUsages().
|
||||
addUsedReifiedParameter(typeParameterDescriptor.getName().asString());
|
||||
}
|
||||
|
||||
v.visitLdcInsn(typeParameterDescriptor.getName().asString());
|
||||
v.invokestatic(
|
||||
IntrinsicMethods.INTRINSICS_CLASS_NAME, markerMethodName,
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE), false
|
||||
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class)), false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void propagateChildReifiedTypeParametersUsages(@NotNull ReifiedTypeParametersUsages usages) {
|
||||
parentCodegen.getReifiedTypeParametersUsages().propagateChildUsagesWithinContext(usages, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackValue visitWhenExpression(@NotNull JetWhenExpression expression, StackValue receiver) {
|
||||
return generateWhenExpression(expression, false);
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.jetbrains.jet.codegen.context.CodegenContext;
|
||||
import org.jetbrains.jet.codegen.context.FieldOwnerContext;
|
||||
import org.jetbrains.jet.codegen.inline.InlineCodegenUtil;
|
||||
import org.jetbrains.jet.codegen.inline.NameGenerator;
|
||||
import org.jetbrains.jet.codegen.inline.ReifiedTypeParametersUsages;
|
||||
import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
|
||||
@@ -46,9 +47,7 @@ import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.codegen.AsmUtil.isPrimitive;
|
||||
import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
|
||||
@@ -69,7 +68,7 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
||||
|
||||
protected ExpressionCodegen clInit;
|
||||
private NameGenerator inlineNameGenerator;
|
||||
private boolean wereReifierMarkers;
|
||||
private final ReifiedTypeParametersUsages reifiedTypeParametersUsages = new ReifiedTypeParametersUsages();
|
||||
|
||||
public MemberCodegen(
|
||||
@NotNull GenerationState state,
|
||||
@@ -385,11 +384,8 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
||||
return context;
|
||||
}
|
||||
|
||||
public boolean wereReifierMarkers() {
|
||||
return wereReifierMarkers;
|
||||
}
|
||||
|
||||
public void setWereReifierMarkers(boolean wereReifierMarkers) {
|
||||
this.wereReifierMarkers = wereReifierMarkers;
|
||||
@NotNull
|
||||
public ReifiedTypeParametersUsages getReifiedTypeParametersUsages() {
|
||||
return reifiedTypeParametersUsages;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -90,7 +90,7 @@ public class AnonymousObjectTransformer {
|
||||
if (signature != null) {
|
||||
ReifiedTypeInliner.SignatureReificationResult signatureResult = inliningContext.reifedTypeInliner.reifySignature(signature);
|
||||
signature = signatureResult.getNewSignature();
|
||||
result.markAsNeededFurtherReificationIf(signatureResult.getNeedFurtherReification());
|
||||
result.getReifiedTypeParametersUsages().mergeAll(signatureResult.getTypeParametersUsages());
|
||||
}
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
@@ -148,7 +148,7 @@ public class AnonymousObjectTransformer {
|
||||
MethodVisitor visitor = newMethod(classBuilder, next);
|
||||
InlineResult funResult = inlineMethod(anonymousObjectGen, parentRemapper, visitor, next, allCapturedParamBuilder);
|
||||
result.addAllClassesToRemove(funResult);
|
||||
result.markAsNeededFurtherReificationIf(funResult.needFurtherReification());
|
||||
result.getReifiedTypeParametersUsages().mergeAll(funResult.getReifiedTypeParametersUsages());
|
||||
}
|
||||
|
||||
InlineResult constructorResult =
|
||||
@@ -170,7 +170,7 @@ public class AnonymousObjectTransformer {
|
||||
@NotNull MethodNode sourceNode,
|
||||
@NotNull ParametersBuilder capturedBuilder
|
||||
) {
|
||||
boolean neededFurtherReification = inliningContext.reifedTypeInliner.reifyInstructions(sourceNode.instructions);
|
||||
ReifiedTypeParametersUsages typeParametersToReify = inliningContext.reifedTypeInliner.reifyInstructions(sourceNode.instructions);
|
||||
Parameters parameters = getMethodParametersWithCaptured(capturedBuilder, sourceNode);
|
||||
|
||||
RegeneratedLambdaFieldRemapper remapper =
|
||||
@@ -182,7 +182,7 @@ public class AnonymousObjectTransformer {
|
||||
remapper, isSameModule, "Transformer for " + anonymousObjectGen.getOwnerInternalName());
|
||||
|
||||
InlineResult result = inliner.doInline(resultVisitor, new LocalVarRemapper(parameters, 0), false, LabelOwner.NOT_APPLICABLE);
|
||||
result.markAsNeededFurtherReificationIf(neededFurtherReification);
|
||||
result.getReifiedTypeParametersUsages().mergeAll(typeParametersToReify);
|
||||
resultVisitor.visitMaxs(-1, -1);
|
||||
resultVisitor.visitEnd();
|
||||
return result;
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.jetbrains.jet.codegen.state.GenerationState;
|
||||
import org.jetbrains.jet.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedSimpleFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
|
||||
@@ -142,6 +141,8 @@ public class InlineCodegen implements CallGenerator {
|
||||
private void endCall(@NotNull InlineResult result) {
|
||||
leaveTemps();
|
||||
|
||||
codegen.propagateChildReifiedTypeParametersUsages(result.getReifiedTypeParametersUsages());
|
||||
|
||||
state.getFactory().removeInlinedClasses(result.getClassesToRemove());
|
||||
}
|
||||
|
||||
@@ -201,7 +202,7 @@ public class InlineCodegen implements CallGenerator {
|
||||
}
|
||||
|
||||
private InlineResult inlineCall(MethodNode node) {
|
||||
reifiedTypeInliner.reifyInstructions(node.instructions);
|
||||
ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node.instructions);
|
||||
generateClosuresBodies();
|
||||
|
||||
//through generation captured parameters will be added to invocationParamBuilder
|
||||
@@ -226,6 +227,7 @@ public class InlineCodegen implements CallGenerator {
|
||||
|
||||
MethodNode adapter = InlineCodegenUtil.createEmptyMethodNode();
|
||||
InlineResult result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL);
|
||||
result.getReifiedTypeParametersUsages().mergeAll(reificationResult);
|
||||
|
||||
LabelOwner labelOwner = new LabelOwner() {
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.Set;
|
||||
public class InlineResult {
|
||||
|
||||
private final Set<String> classesToRemove = new HashSet<String>();
|
||||
private boolean needFurtherReification = false;
|
||||
private final ReifiedTypeParametersUsages reifiedTypeParametersUsages = new ReifiedTypeParametersUsages();
|
||||
|
||||
private InlineResult() {
|
||||
|
||||
@@ -50,11 +50,8 @@ public class InlineResult {
|
||||
return classesToRemove;
|
||||
}
|
||||
|
||||
public boolean needFurtherReification() {
|
||||
return needFurtherReification;
|
||||
}
|
||||
|
||||
public void markAsNeededFurtherReificationIf(boolean condtition) {
|
||||
this.needFurtherReification |= condtition;
|
||||
@NotNull
|
||||
public ReifiedTypeParametersUsages getReifiedTypeParametersUsages() {
|
||||
return reifiedTypeParametersUsages;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,9 +172,9 @@ public class MethodInliner {
|
||||
result.addClassToRemove(anonymousObjectGen.getOwnerInternalName());
|
||||
}
|
||||
|
||||
if (transformResult.needFurtherReification()) {
|
||||
if (transformResult.getReifiedTypeParametersUsages().wereUsedReifiedParameters()) {
|
||||
ReifiedTypeInliner.putNeedClassReificationMarker(mv);
|
||||
result.markAsNeededFurtherReificationIf(true);
|
||||
result.getReifiedTypeParametersUsages().mergeAll(transformResult.getReifiedTypeParametersUsages());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ import org.jetbrains.org.objectweb.asm.signature.SignatureReader
|
||||
import org.jetbrains.org.objectweb.asm.signature.SignatureWriter
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import org.jetbrains.jet.codegen.context.MethodContext
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
||||
|
||||
public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParameterMappings?) {
|
||||
|
||||
@@ -70,34 +72,35 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if there is something need to be reified further
|
||||
* @return set of type parameters' identifiers contained in markers that should be reified further
|
||||
* e.g. when we're generating inline function containing reified T
|
||||
* and another function containing reifiable parts is inlined into that function
|
||||
*/
|
||||
public fun reifyInstructions(instructions: InsnList): Boolean {
|
||||
if (parametersMapping == null) return false
|
||||
var needFurtherReification = false
|
||||
public fun reifyInstructions(instructions: InsnList): ReifiedTypeParametersUsages {
|
||||
if (parametersMapping == null) return ReifiedTypeParametersUsages()
|
||||
var result = ReifiedTypeParametersUsages()
|
||||
for (insn in instructions.toArray()) {
|
||||
if (isParametrisedReifiedMarker(insn)) {
|
||||
if (processReifyMarker(insn as MethodInsnNode, instructions)) {
|
||||
needFurtherReification = true
|
||||
val newName: String? = processReifyMarker(insn as MethodInsnNode, instructions)
|
||||
if (newName != null) {
|
||||
result.addUsedReifiedParameter(newName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return needFurtherReification
|
||||
return result
|
||||
}
|
||||
|
||||
public fun reifySignature(oldSignature: String): SignatureReificationResult {
|
||||
if (parametersMapping == null) return SignatureReificationResult(oldSignature, false)
|
||||
if (parametersMapping == null) return SignatureReificationResult(oldSignature, ReifiedTypeParametersUsages())
|
||||
|
||||
val signatureRemapper = object : SignatureWriter() {
|
||||
var needFurtherReification = false
|
||||
var typeParamsToReify = ReifiedTypeParametersUsages()
|
||||
override fun visitTypeVariable(name: String?) {
|
||||
val mapping = getMappingByName(name) ?:
|
||||
return super.visitTypeArgument()
|
||||
return super.visitTypeVariable(name)
|
||||
if (mapping.newName != null) {
|
||||
needFurtherReification = true
|
||||
typeParamsToReify.addUsedReifiedParameter(mapping.newName)
|
||||
return super.visitTypeVariable(mapping.newName)
|
||||
}
|
||||
|
||||
@@ -110,7 +113,7 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
|
||||
val mapping = getMappingByName(name) ?:
|
||||
return super.visitFormalTypeParameter(name)
|
||||
if (mapping.newName != null) {
|
||||
needFurtherReification = true
|
||||
typeParamsToReify.addUsedReifiedParameter(mapping.newName)
|
||||
super.visitFormalTypeParameter(mapping.newName)
|
||||
}
|
||||
}
|
||||
@@ -120,35 +123,38 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
|
||||
|
||||
SignatureReader(oldSignature).accept(signatureRemapper)
|
||||
|
||||
return SignatureReificationResult(signatureRemapper.toString(), signatureRemapper.needFurtherReification)
|
||||
return SignatureReificationResult(signatureRemapper.toString(), signatureRemapper.typeParamsToReify)
|
||||
}
|
||||
|
||||
data class SignatureReificationResult(val newSignature: String, val needFurtherReification: Boolean)
|
||||
data class SignatureReificationResult(val newSignature: String, val typeParametersUsages: ReifiedTypeParametersUsages)
|
||||
|
||||
/**
|
||||
* @return true if this marker should be reified further
|
||||
* @return new type parameter identifier if this marker should be reified further
|
||||
* or null if it shouldn't
|
||||
*/
|
||||
private fun processReifyMarker(insn: MethodInsnNode, instructions: InsnList): Boolean {
|
||||
val mapping = getTypeParameterMapping(insn) ?: return false
|
||||
private fun processReifyMarker(insn: MethodInsnNode, instructions: InsnList): String? {
|
||||
val mapping = getTypeParameterMapping(insn) ?: return null
|
||||
|
||||
val asmType = mapping.asmType
|
||||
if (asmType != null) {
|
||||
if (!when (insn.name) {
|
||||
// process* methods return false if marker should be reified further
|
||||
// or it's invalid (may be emitted explicitly in code)
|
||||
// they return true if instruction is reified and marker can be deleted
|
||||
if (when (insn.name) {
|
||||
NEW_ARRAY_MARKER_METHOD_NAME -> processNewArray(insn, asmType)
|
||||
CHECKCAST_MARKER_METHOD_NAME -> processCheckcast(insn, asmType)
|
||||
INSTANCEOF_MARKER_METHOD_NAME -> processInstanceof(insn, asmType)
|
||||
JAVA_CLASS_MARKER_METHOD_NAME -> processJavaClass(insn, asmType)
|
||||
else -> false
|
||||
}) {
|
||||
return false
|
||||
instructions.remove(insn.getPrevious()!!)
|
||||
instructions.remove(insn)
|
||||
}
|
||||
instructions.remove(insn.getPrevious()!!)
|
||||
instructions.remove(insn)
|
||||
|
||||
return false
|
||||
return null
|
||||
} else {
|
||||
instructions.set(insn.getPrevious()!!, iconstInsn(mapping.newIndex!!))
|
||||
return true
|
||||
instructions.set(insn.getPrevious()!!, LdcInsnNode(mapping.newName))
|
||||
return mapping.newName
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,51 +180,61 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getParameterIndex(insn: MethodInsnNode): Int? {
|
||||
private fun getParameterName(insn: MethodInsnNode): String? {
|
||||
val prev = insn.getPrevious()!!
|
||||
|
||||
return when (prev.getOpcode()) {
|
||||
Opcodes.ICONST_0 -> 0
|
||||
Opcodes.ICONST_1 -> 1
|
||||
Opcodes.ICONST_2 -> 2
|
||||
Opcodes.ICONST_3 -> 3
|
||||
Opcodes.ICONST_4 -> 4
|
||||
Opcodes.ICONST_5 -> 5
|
||||
Opcodes.BIPUSH, Opcodes.SIPUSH -> (prev as IntInsnNode).operand
|
||||
Opcodes.LDC -> (prev as LdcInsnNode).cst as Int
|
||||
else -> throw AssertionError("Unexpected opcode ${prev.getOpcode()}")
|
||||
Opcodes.LDC -> (prev as LdcInsnNode).cst as String
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTypeParameterMapping(insn: MethodInsnNode): ReifiedTypeParameterMapping? {
|
||||
return parametersMapping?.get(getParameterIndex(insn) ?: return null)
|
||||
return parametersMapping?.get(getParameterName(insn) ?: return null)
|
||||
}
|
||||
}
|
||||
|
||||
public class ReifiedTypeParameterMappings(private val size: Int) {
|
||||
private val mappingsByIndex = arrayOfNulls<ReifiedTypeParameterMapping>(size)
|
||||
private val indexByParameterName = hashMapOf<String, Int>()
|
||||
public class ReifiedTypeParameterMappings() {
|
||||
private val mappingsByName = hashMapOf<String, ReifiedTypeParameterMapping>()
|
||||
|
||||
public fun addParameterMappingToType(index: Int, name: String, asmType: Type) {
|
||||
mappingsByIndex[index] = ReifiedTypeParameterMapping(name, asmType, null, null)
|
||||
indexByParameterName[name] = index
|
||||
public fun addParameterMappingToType(name: String, asmType: Type) {
|
||||
mappingsByName[name] = ReifiedTypeParameterMapping(name, asmType, null)
|
||||
}
|
||||
|
||||
public fun addParameterMappingToNewParameter(index: Int, name: String, newIndex: Int, newName: String) {
|
||||
mappingsByIndex[index] = ReifiedTypeParameterMapping(name, null, newIndex, newName)
|
||||
indexByParameterName[name] = index
|
||||
public fun addParameterMappingToNewParameter(name: String, newName: String) {
|
||||
mappingsByName[name] = ReifiedTypeParameterMapping(name, null, newName)
|
||||
}
|
||||
|
||||
fun get(index: Int) = mappingsByIndex[index]
|
||||
fun get(name: String): ReifiedTypeParameterMapping? {
|
||||
return this[indexByParameterName[name] ?: return null]
|
||||
return mappingsByName[name]
|
||||
}
|
||||
}
|
||||
|
||||
public class ReifiedTypeParameterMapping(val name: String, val asmType: Type?, val newIndex: Int?, val newName: String?)
|
||||
public class ReifiedTypeParameterMapping(val name: String, val asmType: Type?, val newName: String?)
|
||||
|
||||
private fun iconstInsn(n: Int): AbstractInsnNode {
|
||||
val node = MethodNode()
|
||||
InstructionAdapter(node).iconst(n)
|
||||
return node.instructions.getFirst()!!
|
||||
public class ReifiedTypeParametersUsages {
|
||||
val usedTypeParameters: MutableSet<String> = hashSetOf()
|
||||
|
||||
public fun wereUsedReifiedParameters(): Boolean = usedTypeParameters.isNotEmpty()
|
||||
|
||||
public fun addUsedReifiedParameter(name: String) {
|
||||
usedTypeParameters.add(name)
|
||||
}
|
||||
|
||||
public fun propagateChildUsagesWithinContext(child: ReifiedTypeParametersUsages, context: MethodContext) {
|
||||
if (!child.wereUsedReifiedParameters()) return
|
||||
// used for propagating reified TP usages from children member codegen to parent's
|
||||
// mark enclosing object-literal/lambda as needed reification iff
|
||||
// 1. at least one of it's method contains operations to reify
|
||||
// 2. reified type parameter of these operations is not from current method signature
|
||||
// i.e. from outer scope
|
||||
child.usedTypeParameters.filterNot {
|
||||
DescriptorUtils.containsReifiedTypeParameterWithName(context.getContextDescriptor(), it)
|
||||
}.forEach { usedTypeParameters.add(it) }
|
||||
}
|
||||
|
||||
public fun mergeAll(other: ReifiedTypeParametersUsages) {
|
||||
if (!other.wereUsedReifiedParameters()) return
|
||||
usedTypeParameters.addAll(other.usedTypeParameters)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
trait A {
|
||||
fun f1(): String
|
||||
fun f2(): String
|
||||
fun f3(): String
|
||||
}
|
||||
|
||||
fun doWork(block: () -> String) = block()
|
||||
inline fun doWorkInline(block: () -> String) = block()
|
||||
|
||||
fun box(): String {
|
||||
val x = object {
|
||||
inline fun <reified T> bar1(): A = object : A {
|
||||
override fun f1(): String = javaClass<T>().getName()
|
||||
override fun f2(): String = doWork { javaClass<T>().getName() }
|
||||
override fun f3(): String = doWorkInline { javaClass<T>().getName() }
|
||||
}
|
||||
|
||||
inline fun <reified T> bar2() = javaClass<T>().getName()
|
||||
inline fun <reified T> bar3() = doWork { javaClass<T>().getName() }
|
||||
inline fun <reified T> bar4() = doWorkInline { javaClass<T>().getName() }
|
||||
}
|
||||
|
||||
val y: A = x.bar1<String>()
|
||||
assertEquals("java.lang.String", y.f1())
|
||||
assertEquals("java.lang.String", y.f2())
|
||||
assertEquals("java.lang.String", y.f3())
|
||||
|
||||
|
||||
assertEquals("java.lang.Integer", x.bar2<Int>())
|
||||
assertEquals("java.lang.Double", x.bar3<Double>())
|
||||
assertEquals("java.lang.Long", x.bar4<Long>())
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
inline fun <reified T, reified R> foo(): Array<String> {
|
||||
val x = object {
|
||||
inline fun <reified T1, reified T> bar(): Array<String> = array(
|
||||
javaClass<T1>().getName(), javaClass<T>().getName(), javaClass<R>().getName()
|
||||
)
|
||||
fun f1() = bar<T, R>()
|
||||
fun f2() = bar<R, T>()
|
||||
fun f3() = bar<Boolean, T>()
|
||||
fun f4() = bar<T, Boolean>()
|
||||
}
|
||||
|
||||
val x1 = x.f1()
|
||||
val x2 = x.f2()
|
||||
val x3 = x.f3()
|
||||
val x4 = x.f4()
|
||||
|
||||
return array(
|
||||
x1[0], x1[1], x1[2],
|
||||
x2[0], x2[1], x2[2],
|
||||
x3[0], x3[1], x3[2],
|
||||
x4[0], x4[1], x4[2]
|
||||
)
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val result = foo<Double, Int>()
|
||||
|
||||
val expected = array(
|
||||
"java.lang.Double", "java.lang.Integer", "java.lang.Integer",
|
||||
"java.lang.Integer", "java.lang.Double", "java.lang.Integer",
|
||||
"java.lang.Boolean", "java.lang.Double", "java.lang.Integer",
|
||||
"java.lang.Double", "java.lang.Boolean", "java.lang.Integer"
|
||||
)
|
||||
|
||||
for (i in expected.indices) {
|
||||
assertEquals(expected[i], result[i], "$i-th element")
|
||||
}
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
open class A<T1, T2, T3>
|
||||
|
||||
inline fun <reified T, reified R> foo(): Array<A<*,*,*>> {
|
||||
val x = object {
|
||||
inline fun <reified T1, reified T> bar(): A<*,*,*> = object : A<T1,T,R>() {}
|
||||
fun f1() = bar<T, R>()
|
||||
fun f2() = bar<R, T>()
|
||||
fun f3() = bar<Boolean, T>()
|
||||
fun f4() = bar<T, Boolean>()
|
||||
}
|
||||
|
||||
return array(x.f1(), x.f2(), x.f3(), x.f4())
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val result = foo<Double, Int>()
|
||||
|
||||
val expected = array(
|
||||
Triple("java.lang.Double", "java.lang.Integer", "java.lang.Integer"),
|
||||
Triple("java.lang.Integer", "java.lang.Double", "java.lang.Integer"),
|
||||
Triple("java.lang.Boolean", "java.lang.Double", "java.lang.Integer"),
|
||||
Triple("java.lang.Double", "java.lang.Boolean", "java.lang.Integer")
|
||||
).map { "A<${it.first}, ${it.second}, ${it.third}>" }
|
||||
|
||||
for (i in expected.indices) {
|
||||
assertEquals(expected[i], result[i].javaClass.getGenericSuperclass()?.toString(), "$i-th element")
|
||||
}
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
fun foo(block: () -> String) = block()
|
||||
|
||||
trait A {
|
||||
fun f(): String
|
||||
fun g(): String
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val x: A = object : A {
|
||||
private inline fun <reified T> localClassName(): String = javaClass<T>().getName()
|
||||
override fun f(): String = foo { localClassName<String>() }
|
||||
override fun g(): String = foo { localClassName<Int>() }
|
||||
}
|
||||
|
||||
assertEquals("java.lang.String", x.f())
|
||||
assertEquals("java.lang.Integer", x.g())
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
fun foo(block: () -> String) = block()
|
||||
|
||||
inline fun <reified T> className(): String = javaClass<T>().getName()
|
||||
|
||||
inline fun <reified T> lambdaShouldBeReified(): String = foo { className<T>() }
|
||||
|
||||
trait A {
|
||||
fun f(): String
|
||||
fun g(): String
|
||||
}
|
||||
inline fun<reified T1, reified T2> AFactory(): A = object : A {
|
||||
override fun f(): String = className<T1>()
|
||||
override fun g(): String = foo { className<T2>() }
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
assertEquals("java.lang.String", lambdaShouldBeReified<String>())
|
||||
assertEquals("java.lang.Integer", lambdaShouldBeReified<Int>())
|
||||
|
||||
val x: A = AFactory<String, Int>()
|
||||
|
||||
assertEquals("java.lang.String", x.f())
|
||||
assertEquals("java.lang.Integer", x.g())
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+30
@@ -2640,6 +2640,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("anonymousObjectNoPropagate.kt")
|
||||
public void testAnonymousObjectNoPropagate() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/anonymousObjectNoPropagate.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("anonymousObjectReifiedSupertype.kt")
|
||||
public void testAnonymousObjectReifiedSupertype() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/anonymousObjectReifiedSupertype.kt");
|
||||
@@ -2688,6 +2694,18 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nestedReified.kt")
|
||||
public void testNestedReified() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/nestedReified.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("nestedReifiedSignature.kt")
|
||||
public void testNestedReifiedSignature() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/nestedReifiedSignature.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("newArrayInt.kt")
|
||||
public void testNewArrayInt() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/newArrayInt.kt");
|
||||
@@ -2718,6 +2736,18 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("reifiedInlineFunOfObject.kt")
|
||||
public void testReifiedInlineFunOfObject() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/reifiedInlineFunOfObject.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("reifiedInlineFunOfObjectWithinReified.kt")
|
||||
public void testReifiedInlineFunOfObjectWithinReified() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/reifiedInlineFunOfObjectWithinReified.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("reifiedInlineIntoNonInlineableLambda.kt")
|
||||
public void testReifiedInlineIntoNonInlineableLambda() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/reifiedInlineIntoNonInlineableLambda.kt");
|
||||
|
||||
@@ -442,4 +442,12 @@ public class DescriptorUtils {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean containsReifiedTypeParameterWithName(@NotNull CallableDescriptor descriptor, @NotNull String name) {
|
||||
for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) {
|
||||
if (typeParameterDescriptor.isReified() && typeParameterDescriptor.getName().asString().equals(name)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,19 +109,19 @@ public class Intrinsics {
|
||||
throw new UnsupportedOperationException("You should not use functions with reified parameter without inline");
|
||||
}
|
||||
|
||||
public static void reifyNewArray(int parameterTypeIndex) {
|
||||
public static void reifyNewArray(String typeParameterIdentifier) {
|
||||
throwUndefinedForReified();
|
||||
}
|
||||
|
||||
public static void reifyCheckcast(int parameterTypeIndex) {
|
||||
public static void reifyCheckcast(String typeParameterIdentifier) {
|
||||
throwUndefinedForReified();
|
||||
}
|
||||
|
||||
public static void reifyInstanceof(int parameterTypeIndex) {
|
||||
public static void reifyInstanceof(String typeParameterIdentifier) {
|
||||
throwUndefinedForReified();
|
||||
}
|
||||
|
||||
public static void reifyJavaClass(int parameterTypeIndex) {
|
||||
public static void reifyJavaClass(String typeParameterIdentifier) {
|
||||
throwUndefinedForReified();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user