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.SUPER_TYPE -> TypeMappingMode.SUPER_TYPE
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 ->
typeMapper.typeContext.getOptimalModeForReturnType(type.fe10Type, isAnnotationMethod)
KtTypeMappingMode.VALUE_PARAMETER ->
@@ -76,6 +76,7 @@ internal class KtFirPsiTypeProvider(
KtTypeMappingMode.GENERIC_ARGUMENT -> TypeMappingMode.GENERIC_ARGUMENT
KtTypeMappingMode.SUPER_TYPE -> TypeMappingMode.SUPER_TYPE
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 ->
rootModuleSession.jvmTypeMapper.typeContext.getOptimalModeForReturnType(type.coneType, isAnnotationMethod)
KtTypeMappingMode.VALUE_PARAMETER ->
@@ -33,6 +33,11 @@ public enum class KtTypeMappingMode {
*/
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.
*/
@@ -238,10 +238,19 @@ internal class SymbolLightAccessorMethod private constructor(
if (!isGetter) return@lazyPub PsiType.VOID
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,
allowErrorTypes = true,
KtTypeMappingMode.RETURN_TYPE,
typeMappingMode,
containingClass.isAnnotationType,
)
} ?: nonExistentType()
@@ -11,6 +11,8 @@ import kotlinx.collections.immutable.mutate
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.annotations.hasAnnotation
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.KtTypeMappingMode
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
@@ -177,6 +179,25 @@ internal class SymbolLightSimpleMethod(
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 _returnedType: PsiType by lazyPub {
@@ -187,10 +208,12 @@ internal class SymbolLightSimpleMethod(
functionSymbol.returnType.takeUnless { it.isVoidType } ?: return@withFunctionSymbol PsiType.VOID
}
val typeMappingMode = if (forceBoxedReturnType()) KtTypeMappingMode.RETURN_TYPE_BOXED else KtTypeMappingMode.RETURN_TYPE
ktType.asPsiTypeElement(
this@SymbolLightSimpleMethod,
allowErrorTypes = true,
KtTypeMappingMode.RETURN_TYPE,
typeMappingMode,
this@SymbolLightSimpleMethod.containingClass.isAnnotationType,
)?.let {
annotateByKtType(it.type, ktType, it, modifierList)
@@ -2,10 +2,10 @@ public final class C /* C*/ implements Tr {
private final int v;
@java.lang.Override()
public int foo();// foo()
public java.lang.Integer foo();// foo()
@java.lang.Override()
public int getV();// getV()
public java.lang.Integer getV();// getV()
public C();// .ctor()
}