Implement codegen for bound class reference expressions
- Inline the usage of ExpressionCodegen#generateClassLiteralReference into ClosureCodegen, simplify - Support DoubleColonLHS.Expression in generateClassLiteralReference - Substantially simplify KClass.java intrinsic by reusing generateClassLiteralReference #KT-13075 Fixed #KT-12995 In Progress
This commit is contained in:
@@ -59,7 +59,6 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.ExpressionCodegen.generateClassLiteralReference;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConst;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLOSURE;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass;
|
||||
@@ -390,8 +389,8 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
|
||||
DeclarationDescriptor container = descriptor.getContainingDeclaration();
|
||||
if (container instanceof ClassDescriptor) {
|
||||
// TODO: getDefaultType() here is wrong and won't work for arrays
|
||||
StackValue value = generateClassLiteralReference(state.getTypeMapper(), ((ClassDescriptor) container).getDefaultType());
|
||||
value.put(K_CLASS_TYPE, iv);
|
||||
putJavaLangClassInstance(iv, state.getTypeMapper().mapType(((ClassDescriptor) container).getDefaultType()));
|
||||
wrapJavaClassIntoKClass(iv);
|
||||
}
|
||||
else if (container instanceof PackageFragmentDescriptor) {
|
||||
iv.aconst(state.getTypeMapper().mapOwner(descriptor));
|
||||
|
||||
@@ -92,6 +92,7 @@ import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeProjection;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS;
|
||||
import org.jetbrains.kotlin.types.typesApproximation.CapturedTypeApproximationKt;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
@@ -3209,13 +3210,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
@Override
|
||||
public StackValue visitClassLiteralExpression(@NotNull KtClassLiteralExpression expression, StackValue data) {
|
||||
KotlinType type = bindingContext.getType(expression);
|
||||
assert type != null;
|
||||
|
||||
assert state.getReflectionTypes().getKClass().getTypeConstructor().equals(type.getConstructor())
|
||||
: "::class expression should be type checked to a KClass: " + type;
|
||||
|
||||
return generateClassLiteralReference(typeMapper, CollectionsKt.single(type.getArguments()).getType(), this);
|
||||
KtExpression receiverExpression = expression.getReceiverExpression();
|
||||
assert receiverExpression != null : "Class literal expression should have a left-hand side";
|
||||
DoubleColonLHS lhs = bindingContext.get(DOUBLE_COLON_LHS, receiverExpression);
|
||||
assert lhs != null : "Class literal expression should have LHS resolved";
|
||||
return generateClassLiteralReference(lhs, receiverExpression, /* wrapIntoKClass = */ true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -3282,28 +3281,31 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static StackValue generateClassLiteralReference(@NotNull KotlinTypeMapper typeMapper, @NotNull KotlinType type) {
|
||||
return generateClassLiteralReference(typeMapper, type, null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static StackValue generateClassLiteralReference(@NotNull final KotlinTypeMapper typeMapper, @NotNull final KotlinType type, @Nullable final ExpressionCodegen codegen) {
|
||||
return StackValue.operation(K_CLASS_TYPE, new Function1<InstructionAdapter, Unit>() {
|
||||
public StackValue generateClassLiteralReference(
|
||||
@NotNull final DoubleColonLHS lhs,
|
||||
@Nullable final KtExpression receiverExpression,
|
||||
final boolean wrapIntoKClass
|
||||
) {
|
||||
return StackValue.operation(wrapIntoKClass ? K_CLASS_TYPE : JAVA_CLASS_TYPE, new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
Type classAsmType = typeMapper.mapType(type);
|
||||
ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
|
||||
if (descriptor instanceof TypeParameterDescriptor) {
|
||||
TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor;
|
||||
assert typeParameterDescriptor.isReified() :
|
||||
"Non-reified type parameter under ::class should be rejected by type checker: " + typeParameterDescriptor;
|
||||
assert codegen != null :
|
||||
"Reference to member of reified type should be rejected by type checker " + typeParameterDescriptor;
|
||||
codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.JAVA_CLASS);
|
||||
KotlinType type = lhs.getType();
|
||||
if (lhs instanceof DoubleColonLHS.Expression) {
|
||||
JavaClassProperty.INSTANCE.generateImpl(v, gen(receiverExpression));
|
||||
}
|
||||
else if (lhs instanceof DoubleColonLHS.Type) {
|
||||
if (TypeUtils.isTypeParameter(type)) {
|
||||
assert TypeUtils.isReifiedTypeParameter(type) :
|
||||
"Non-reified type parameter under ::class should be rejected by type checker: " + type;
|
||||
putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.JAVA_CLASS);
|
||||
}
|
||||
|
||||
putJavaLangClassInstance(v, typeMapper.mapType(type));
|
||||
}
|
||||
|
||||
putJavaLangClassInstance(v, classAsmType);
|
||||
wrapJavaClassIntoKClass(v);
|
||||
if (wrapIntoKClass) {
|
||||
wrapJavaClassIntoKClass(v);
|
||||
}
|
||||
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
|
||||
@@ -16,69 +16,21 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen.intrinsics
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.psi.KtClassLiteralExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class KClassJavaProperty : IntrinsicPropertyGetter() {
|
||||
override fun generate(resolvedCall: ResolvedCall<*>?, codegen: ExpressionCodegen, returnType: Type, receiver: StackValue): StackValue? {
|
||||
val receiverType = resolvedCall!!.extensionReceiver!!.type
|
||||
val type = getKClassTypeArgument(receiverType) ?: return null
|
||||
val asmType = codegen.state.typeMapper.mapType(type)
|
||||
|
||||
return when {
|
||||
isReifiedTypeParameter(type) -> {
|
||||
StackValue.operation(returnType) { iv ->
|
||||
codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.JAVA_CLASS)
|
||||
AsmUtil.putJavaLangClassInstance(iv, asmType)
|
||||
coerceToJavaLangClass(iv, returnType)
|
||||
}
|
||||
}
|
||||
isWithClassLiteralArgument(resolvedCall) -> {
|
||||
StackValue.operation(returnType) { iv ->
|
||||
if (AsmUtil.isPrimitive(asmType)) {
|
||||
iv.getstatic(AsmUtil.boxType(asmType).internalName, "TYPE", "Ljava/lang/Class;")
|
||||
}
|
||||
else {
|
||||
iv.tconst(asmType)
|
||||
}
|
||||
coerceToJavaLangClass(iv, returnType)
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getKClassTypeArgument(type: KotlinType): KotlinType? {
|
||||
val typeClassifier = type.constructor.declarationDescriptor
|
||||
return if (typeClassifier is ClassDescriptor && KotlinBuiltIns.isKClass(typeClassifier))
|
||||
type.arguments.singleOrNull()?.type
|
||||
else
|
||||
null
|
||||
}
|
||||
|
||||
private fun isReifiedTypeParameter(type: KotlinType): Boolean {
|
||||
val typeDescriptor = type.constructor.declarationDescriptor
|
||||
return typeDescriptor is TypeParameterDescriptor && typeDescriptor.isReified
|
||||
}
|
||||
|
||||
private fun isWithClassLiteralArgument(resolvedCall: ResolvedCall<*>): Boolean {
|
||||
val extensionReceiver = resolvedCall.extensionReceiver
|
||||
return extensionReceiver is ExpressionReceiver && extensionReceiver.expression is KtClassLiteralExpression
|
||||
}
|
||||
|
||||
private fun coerceToJavaLangClass(iv: InstructionAdapter, returnType: Type) {
|
||||
StackValue.coerce(AsmTypes.JAVA_CLASS_TYPE, returnType, iv)
|
||||
val receiverValue = resolvedCall!!.extensionReceiver as? ExpressionReceiver ?: return null
|
||||
val classLiteralExpression = receiverValue.expression as? KtClassLiteralExpression ?: return null
|
||||
val receiverExpression = classLiteralExpression.receiverExpression ?: return null
|
||||
val lhs = codegen.bindingContext.get(DOUBLE_COLON_LHS, receiverExpression) ?: return null
|
||||
val value = codegen.generateClassLiteralReference(lhs, receiverExpression, /* wrapIntoKClass = */ false)
|
||||
return StackValue.coercion(value, returnType)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user