[FE][PSI2IR] Generalized SamType

Operations regarding <fun interface> are common for all backends
This commit is contained in:
Igor Chevdar
2021-02-25 10:43:58 +05:00
parent 56bec6997c
commit 246a907753
14 changed files with 123 additions and 127 deletions
@@ -0,0 +1,90 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.common
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.resolve.sam.getAbstractMembers
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithNothing
class SamType constructor(val type: KotlinType) {
val classDescriptor: ClassDescriptor
get() = type.constructor.declarationDescriptor as? ClassDescriptor ?: error("Sam/Fun interface not a class descriptor: $type")
val kotlinFunctionType: KotlinType
get() = classDescriptor.defaultFunctionTypeForSamInterface!!
val originalAbstractMethod: SimpleFunctionDescriptor
get() = getAbstractMembers(classDescriptor)[0] as SimpleFunctionDescriptor
override fun equals(other: Any?): Boolean {
return other is SamType && type == other.type
}
override fun hashCode(): Int {
return type.hashCode()
}
override fun toString(): String {
return "SamType($type)"
}
}
open class SamTypeFactory {
fun createByValueParameter(valueParameter: ValueParameterDescriptor): SamType? {
val singleArgumentType: KotlinType
val originalSingleArgumentType: KotlinType?
val varargElementType = valueParameter.varargElementType
if (varargElementType != null) {
singleArgumentType = varargElementType
originalSingleArgumentType = valueParameter.original.varargElementType
assert(originalSingleArgumentType != null) {
"Value parameter and original value parameter have inconsistent varargs: " +
valueParameter + "; " + valueParameter.original
}
} else {
singleArgumentType = valueParameter.type
originalSingleArgumentType = valueParameter.original.type
}
if (singleArgumentType.isError || originalSingleArgumentType!!.isError) {
return null
}
// This can be true in case when the value parameter is in the method of a generic type with out-projection.
// We approximate Inv<Captured#1> to Nothing, while Inv itself can be a SAM interface safe to call here
// (see testData genericSamProjectedOut.kt for details)
// In such a case we can't have a proper supertype since wildcards are not allowed there,
// so we use Nothing arguments instead that leads to a raw type used for a SAM wrapper.
// See org.jetbrains.kotlin.codegen.state.KotlinTypeMapper#writeGenericType to understand how
// raw types and Nothing arguments relate.
val originalTypeToUse =
if (KotlinBuiltIns.isNothing(singleArgumentType))
originalSingleArgumentType.replaceArgumentsWithNothing()
else singleArgumentType
return create(originalTypeToUse.removeExternalProjections())
}
open fun isSamType(type: KotlinType): Boolean {
val descriptor = type.constructor.declarationDescriptor
return descriptor is ClassDescriptor && descriptor.isFun
}
fun create(originalType: KotlinType): SamType? {
return if (isSamType(originalType)) SamType(originalType) else null
}
private fun KotlinType.removeExternalProjections(): KotlinType {
val newArguments = arguments.map { TypeProjectionImpl(Variance.INVARIANT, it.type) }
return replace(newArguments)
}
companion object {
val INSTANCE = SamTypeFactory()
}
}
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver;
import org.jetbrains.kotlin.serialization.DescriptorSerializer;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.SimpleType;
import org.jetbrains.kotlin.backend.common.SamType;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils;
import org.jetbrains.kotlin.util.OperatorNameConventions;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
@@ -92,6 +92,7 @@ import org.jetbrains.kotlin.types.model.KotlinTypeMarker;
import org.jetbrains.kotlin.types.model.TypeParameterMarker;
import org.jetbrains.kotlin.types.typesApproximation.CapturedTypeApproximationKt;
import org.jetbrains.kotlin.util.OperatorNameConventions;
import org.jetbrains.kotlin.backend.common.SamType;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
import org.jetbrains.org.objectweb.asm.Opcodes;
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.load.java.sam.JavaSingleAbstractMethodUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.backend.common.SamTypeFactory
object JvmSamTypeFactory : SamTypeFactory() {
override fun isSamType(type: KotlinType) = JavaSingleAbstractMethodUtils.isSamType(type)
}
@@ -1,117 +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 org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.codegen.state.TypeMapperUtilsKt;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor;
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
import org.jetbrains.kotlin.load.java.sam.JavaSingleAbstractMethodUtils;
import org.jetbrains.kotlin.resolve.sam.SamConversionResolverImplKt;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.KotlinTypeKt;
import org.jetbrains.kotlin.types.typeUtil.TypeUtilsKt;
public class SamType {
@Nullable
public static SamType createByValueParameter(@NotNull ValueParameterDescriptor valueParameter) {
KotlinType singleArgumentType;
KotlinType originalSingleArgumentType;
KotlinType varargElementType = valueParameter.getVarargElementType();
if (varargElementType != null) {
singleArgumentType = varargElementType;
originalSingleArgumentType = valueParameter.getOriginal().getVarargElementType();
assert originalSingleArgumentType != null :
"Value parameter and original value parameter have inconsistent varargs: " +
valueParameter + "; " + valueParameter.getOriginal();
} else {
singleArgumentType = valueParameter.getType();
originalSingleArgumentType = valueParameter.getOriginal().getType();
}
if (KotlinTypeKt.isError(singleArgumentType) || KotlinTypeKt.isError(originalSingleArgumentType)) {
return null;
}
KotlinType originalTypeToUse =
// This can be true in case when the value parameter is in the method of a generic type with out-projection.
// We approximate Inv<Captured#1> to Nothing, while Inv itself can be a SAM interface safe to call here
// (see testData genericSamProjectedOut.kt for details)
KotlinBuiltIns.isNothing(singleArgumentType)
// In such a case we can't have a proper supertype since wildcards are not allowed there,
// so we use Nothing arguments instead that leads to a raw type used for a SAM wrapper.
// See org.jetbrains.kotlin.codegen.state.KotlinTypeMapper#writeGenericType to understand how
// raw types and Nothing arguments relate.
? TypeUtilsKt.replaceArgumentsWithNothing(originalSingleArgumentType)
: singleArgumentType;
return create(TypeMapperUtilsKt.removeExternalProjections(originalTypeToUse));
}
public static SamType create(@NotNull KotlinType originalType) {
if (!JavaSingleAbstractMethodUtils.isSamType(originalType)) return null;
return new SamType(originalType);
}
private final KotlinType type;
private SamType(@NotNull KotlinType type) {
this.type = type;
}
@NotNull
public KotlinType getType() {
return type;
}
@NotNull
public ClassDescriptor getClassDescriptor() {
ClassifierDescriptor classifier = type.getConstructor().getDeclarationDescriptor();
assert classifier instanceof ClassDescriptor : "Sam/Fun interface not a class descriptor: " + classifier;
return (ClassDescriptor) classifier;
}
@NotNull
public KotlinType getKotlinFunctionType() {
ClassDescriptor descriptor = getClassDescriptor();
//noinspection ConstantConditions
return descriptor.getDefaultFunctionTypeForSamInterface();
}
@NotNull
public SimpleFunctionDescriptor getOriginalAbstractMethod() {
return (SimpleFunctionDescriptor) SamConversionResolverImplKt.getAbstractMembers(getClassDescriptor()).get(0);
}
@Override
public boolean equals(Object o) {
return o instanceof SamType && type.equals(((SamType) o).type);
}
@Override
public int hashCode() {
return type.hashCode();
}
@Override
public String toString() {
return "SamType(" + type + ")";
}
}
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.kotlin.backend.common.SamType
class SamWrapperClasses(private val state: GenerationState) {
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.backend.common.SamType;
import org.jetbrains.kotlin.util.OperatorNameConventions;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
@@ -56,6 +56,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.backend.common.SamType;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import org.jetbrains.org.objectweb.asm.Type;
@@ -861,7 +862,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
if (valueArguments == null) return;
for (ValueParameterDescriptor valueParameter : valueParametersWithSAMConversion) {
SamType samType = SamType.createByValueParameter(valueParameter);
SamType samType = JvmSamTypeFactory.INSTANCE.createByValueParameter(valueParameter);
if (samType == null) continue;
ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex());
@@ -873,7 +874,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
}
private void recordSamTypeOnArgumentExpression(ValueParameterDescriptor valueParameter, ValueArgument valueArgument) {
SamType samType = SamType.createByValueParameter(valueParameter);
SamType samType = JvmSamTypeFactory.INSTANCE.createByValueParameter(valueParameter);
if (samType == null) return;
recordSamTypeOnArgumentExpression(samType, valueArgument);
@@ -955,7 +956,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
bindingTrace.record(SAM_CONSTRUCTOR_TO_ARGUMENT, expression, argumentExpression);
//noinspection ConstantConditions
SamType samType = SamType.create(callableDescriptor.getReturnType());
SamType samType = JvmSamTypeFactory.INSTANCE.create(callableDescriptor.getReturnType());
bindingTrace.record(SAM_VALUE, argumentExpression, samType);
}
@@ -972,7 +973,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
FunctionDescriptor original = SamCodegenUtil.getOriginalIfSamAdapter((FunctionDescriptor) operationDescriptor);
if (original == null) return;
SamType samType = SamType.createByValueParameter(original.getValueParameters().get(0));
SamType samType = JvmSamTypeFactory.INSTANCE.createByValueParameter(original.getValueParameters().get(0));
if (samType == null) return;
IElementType token = expression.getOperationToken();
@@ -1001,7 +1002,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
List<KtExpression> indexExpressions = expression.getIndexExpressions();
List<ValueParameterDescriptor> parameters = original.getValueParameters();
for (ValueParameterDescriptor valueParameter : parameters) {
SamType samType = SamType.createByValueParameter(valueParameter);
SamType samType = JvmSamTypeFactory.INSTANCE.createByValueParameter(valueParameter);
if (samType == null) continue;
if (isSetter && valueParameter.getIndex() == parameters.size() - 1) {
@@ -12,7 +12,7 @@ import kotlin.collections.CollectionsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.JvmCodegenUtil;
import org.jetbrains.kotlin.codegen.SamType;
import org.jetbrains.kotlin.backend.common.SamType;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.when.WhenByEnumsMapping;
import org.jetbrains.kotlin.descriptors.*;
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.backend.common.SamType
import org.jetbrains.kotlin.utils.sure
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.MethodVisitor
@@ -75,6 +75,7 @@ import org.jetbrains.kotlin.types.checker.SimpleClassicTypeSystemContext
import org.jetbrains.kotlin.types.checker.convertVariance
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*
import org.jetbrains.kotlin.types.model.*
import org.jetbrains.kotlin.backend.common.SamType
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.org.objectweb.asm.Type
@@ -52,4 +52,4 @@ fun getEffectiveVariance(parameterVariance: Variance, projectionKind: Variance):
// In<out X> = In<*>
// Out<in X> = Out<*>
return Variance.OUT_VARIANCE
}
}
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.ir.createParameterDeclarations
import org.jetbrains.kotlin.codegen.SamType
import org.jetbrains.kotlin.codegen.JvmSamTypeFactory
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.FilteredAnnotations
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
@@ -60,7 +60,7 @@ open class JvmGeneratorExtensionsImpl(private val generateFacades: Boolean = tru
JavaSingleAbstractMethodUtils.isSamType(type)
override fun getSamTypeForValueParameter(valueParameter: ValueParameterDescriptor): KotlinType? =
SamType.createByValueParameter(valueParameter)?.type
JvmSamTypeFactory.createByValueParameter(valueParameter)?.type
companion object Instance : JvmSamConversion()
}
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.util.StubGeneratorExtensions
import org.jetbrains.kotlin.psi.KtPureClassOrObject
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.backend.common.SamTypeFactory
open class GeneratorExtensions : StubGeneratorExtensions() {
open val samConversion: SamConversion
@@ -23,7 +24,8 @@ open class GeneratorExtensions : StubGeneratorExtensions() {
open class SamConversion {
open fun isPlatformSamType(type: KotlinType): Boolean = false
open fun getSamTypeForValueParameter(valueParameter: ValueParameterDescriptor): KotlinType? = null
open fun getSamTypeForValueParameter(valueParameter: ValueParameterDescriptor): KotlinType? =
SamTypeFactory.INSTANCE.createByValueParameter(valueParameter)?.type
companion object Instance : SamConversion()
}