SLC: force boxed return type when needed

e.g., when overriding a function whose return type is not primitive

^KT-57579 Fixed
This commit is contained in:
Jinseong Jeon
2023-03-26 00:30:38 -07:00
committed by Dmitrii Gridin
parent 19dbe69651
commit 1b3b554084
6 changed files with 44 additions and 5 deletions
@@ -62,6 +62,7 @@ internal class KtFe10PsiTypeProvider(
KtTypeMappingMode.GENERIC_ARGUMENT -> TypeMappingMode.GENERIC_ARGUMENT KtTypeMappingMode.GENERIC_ARGUMENT -> TypeMappingMode.GENERIC_ARGUMENT
KtTypeMappingMode.SUPER_TYPE -> TypeMappingMode.SUPER_TYPE KtTypeMappingMode.SUPER_TYPE -> TypeMappingMode.SUPER_TYPE
KtTypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS -> TypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS KtTypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS -> TypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS
KtTypeMappingMode.RETURN_TYPE_BOXED -> TypeMappingMode.RETURN_TYPE_BOXED
KtTypeMappingMode.RETURN_TYPE -> KtTypeMappingMode.RETURN_TYPE ->
typeMapper.typeContext.getOptimalModeForReturnType(type.fe10Type, isAnnotationMethod) typeMapper.typeContext.getOptimalModeForReturnType(type.fe10Type, isAnnotationMethod)
KtTypeMappingMode.VALUE_PARAMETER -> KtTypeMappingMode.VALUE_PARAMETER ->
@@ -76,6 +76,7 @@ internal class KtFirPsiTypeProvider(
KtTypeMappingMode.GENERIC_ARGUMENT -> TypeMappingMode.GENERIC_ARGUMENT KtTypeMappingMode.GENERIC_ARGUMENT -> TypeMappingMode.GENERIC_ARGUMENT
KtTypeMappingMode.SUPER_TYPE -> TypeMappingMode.SUPER_TYPE KtTypeMappingMode.SUPER_TYPE -> TypeMappingMode.SUPER_TYPE
KtTypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS -> TypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS KtTypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS -> TypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS
KtTypeMappingMode.RETURN_TYPE_BOXED -> TypeMappingMode.RETURN_TYPE_BOXED
KtTypeMappingMode.RETURN_TYPE -> KtTypeMappingMode.RETURN_TYPE ->
rootModuleSession.jvmTypeMapper.typeContext.getOptimalModeForReturnType(type.coneType, isAnnotationMethod) rootModuleSession.jvmTypeMapper.typeContext.getOptimalModeForReturnType(type.coneType, isAnnotationMethod)
KtTypeMappingMode.VALUE_PARAMETER -> KtTypeMappingMode.VALUE_PARAMETER ->
@@ -33,6 +33,11 @@ public enum class KtTypeMappingMode {
*/ */
SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS, SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS,
/**
* When method return type should be boxed (e.g., kotlin.Int to Ljava/lang/Integer;)
*/
RETURN_TYPE_BOXED,
/** /**
* Optimal mode to convert the return type of declarations if it's part of signature. * Optimal mode to convert the return type of declarations if it's part of signature.
*/ */
@@ -238,10 +238,19 @@ internal class SymbolLightAccessorMethod private constructor(
if (!isGetter) return@lazyPub PsiType.VOID if (!isGetter) return@lazyPub PsiType.VOID
containingPropertySymbolPointer.withSymbol(ktModule) { propertySymbol -> containingPropertySymbolPointer.withSymbol(ktModule) { propertySymbol ->
propertySymbol.returnType.asPsiType( val ktType = propertySymbol.returnType
val forceBoxedReturnType = ktType.isPrimitive &&
propertySymbol.getAllOverriddenSymbols().any { overriddenSymbol ->
!overriddenSymbol.returnType.isPrimitive
}
val typeMappingMode = if (forceBoxedReturnType) KtTypeMappingMode.RETURN_TYPE_BOXED else KtTypeMappingMode.RETURN_TYPE
ktType.asPsiType(
this@SymbolLightAccessorMethod, this@SymbolLightAccessorMethod,
allowErrorTypes = true, allowErrorTypes = true,
KtTypeMappingMode.RETURN_TYPE, typeMappingMode,
containingClass.isAnnotationType, containingClass.isAnnotationType,
) )
} ?: nonExistentType() } ?: nonExistentType()
@@ -11,6 +11,8 @@ import kotlinx.collections.immutable.mutate
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.annotations.hasAnnotation import org.jetbrains.kotlin.analysis.api.annotations.hasAnnotation
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.types.KtNonErrorClassType
import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.api.types.KtTypeMappingMode import org.jetbrains.kotlin.analysis.api.types.KtTypeMappingMode
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
@@ -177,6 +179,25 @@ internal class SymbolLightSimpleMethod(
if (isTopLevel) false else withFunctionSymbol { it.isOverride } if (isTopLevel) false else withFunctionSymbol { it.isOverride }
} }
// Inspired by KotlinTypeMapper#forceBoxedReturnType
private fun forceBoxedReturnType(): Boolean {
return withFunctionSymbol { functionSymbol ->
val returnType = functionSymbol.returnType
// 'invoke' methods for lambdas, function literals, and callable references
// implicitly override generic 'invoke' from a corresponding base class.
if (functionSymbol.isBuiltinFunctionInvoke && returnType.isInlineClassType)
return@withFunctionSymbol true
returnType.isPrimitive &&
functionSymbol.getAllOverriddenSymbols().any { overriddenSymbol ->
!overriddenSymbol.returnType.isPrimitive
}
}
}
private val KtType.isInlineClassType: Boolean
get() = ((this as? KtNonErrorClassType)?.classSymbol as? KtNamedClassOrObjectSymbol)?.isInline == true
private val KtType.isVoidType: Boolean get() = isUnit && nullabilityType != NullabilityType.Nullable private val KtType.isVoidType: Boolean get() = isUnit && nullabilityType != NullabilityType.Nullable
private val _returnedType: PsiType by lazyPub { private val _returnedType: PsiType by lazyPub {
@@ -187,10 +208,12 @@ internal class SymbolLightSimpleMethod(
functionSymbol.returnType.takeUnless { it.isVoidType } ?: return@withFunctionSymbol PsiType.VOID functionSymbol.returnType.takeUnless { it.isVoidType } ?: return@withFunctionSymbol PsiType.VOID
} }
val typeMappingMode = if (forceBoxedReturnType()) KtTypeMappingMode.RETURN_TYPE_BOXED else KtTypeMappingMode.RETURN_TYPE
ktType.asPsiTypeElement( ktType.asPsiTypeElement(
this@SymbolLightSimpleMethod, this@SymbolLightSimpleMethod,
allowErrorTypes = true, allowErrorTypes = true,
KtTypeMappingMode.RETURN_TYPE, typeMappingMode,
this@SymbolLightSimpleMethod.containingClass.isAnnotationType, this@SymbolLightSimpleMethod.containingClass.isAnnotationType,
)?.let { )?.let {
annotateByKtType(it.type, ktType, it, modifierList) annotateByKtType(it.type, ktType, it, modifierList)
@@ -2,10 +2,10 @@ public final class C /* C*/ implements Tr {
private final int v; private final int v;
@java.lang.Override() @java.lang.Override()
public int foo();// foo() public java.lang.Integer foo();// foo()
@java.lang.Override() @java.lang.Override()
public int getV();// getV() public java.lang.Integer getV();// getV()
public C();// .ctor() public C();// .ctor()
} }