[kotlin] k2: create extension property from usage

^KTIJ-32925 fixed

GitOrigin-RevId: 73f7c9ccaf4b2b1c154ab317d5671ade8946def6
This commit is contained in:
Anna Kozlova
2025-02-04 23:50:25 +00:00
committed by intellij-monorepo-bot
parent 6cde64989f
commit 912e587e77
30 changed files with 188 additions and 57 deletions
@@ -17,7 +17,7 @@ val PsiClass.classIdIfNonLocal: ClassId?
if (this is KtLightClass) {
return this.kotlinOrigin?.getClassId()
}
val packageName = (containingFile as? PsiJavaFile)?.packageName ?: return null
val packageName = (containingFile as? PsiClassOwner)?.packageName ?: return null
val packageFqName = FqName(packageName)
val classesNames = parentsOfType<PsiClass>().map { it.name }.toList().asReversed()
@@ -15,5 +15,6 @@ abstract class K2CreateVariableFromUsageTest : K2AbstractCreateFromUsageTest("cr
class Property : K2CreateVariableFromUsageTest() {
class Abstract: K2CreateVariableFromUsageTest()
class FieldFromJava: K2CreateVariableFromUsageTest()
class Extension: K2CreateVariableFromUsageTest()
}
}
@@ -10,9 +10,15 @@ import com.intellij.lang.jvm.types.JvmSubstitutor
import com.intellij.psi.PsiJvmSubstitutor
import com.intellij.psi.PsiSubstitutor
import com.intellij.psi.createSmartPointer
import org.jetbrains.kotlin.analysis.api.KaExperimentalApi
import org.jetbrains.kotlin.analysis.api.analyze
import org.jetbrains.kotlin.analysis.api.renderer.types.KaTypeRenderer
import org.jetbrains.kotlin.analysis.api.renderer.types.impl.KaTypeRendererForSource
import org.jetbrains.kotlin.analysis.api.types.KaType
import org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreateFunctionFromUsageUtil.convertToJvmType
import org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreateFunctionFromUsageUtil.getExpectedKotlinType
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.types.Variance
/**
* A request to create Kotlin property from the usage in Kotlin.
@@ -20,19 +26,38 @@ import org.jetbrains.kotlin.psi.KtNameReferenceExpression
internal class CreatePropertyFromKotlinUsageRequest (
referenceExpression: KtNameReferenceExpression,
private val modifiers: Collection<JvmModifier>,
private val receiverType: KaType?,
val isExtension: Boolean
) : CreateFieldRequest {
private val referencePointer = referenceExpression.createSmartPointer()
private val returnType: List<ExpectedType> = initializeReturnType(referenceExpression)
@OptIn(KaExperimentalApi::class)
val receiverTypeString: String? = getReceiverTypeString(referenceExpression, K2CreateFunctionFromUsageUtil.WITH_TYPE_NAMES_FOR_CREATE_ELEMENTS)
@OptIn(KaExperimentalApi::class)
val receiverTypeNameString: String? = getReceiverTypeString(referenceExpression, KaTypeRendererForSource.WITH_SHORT_NAMES)
private fun initializeReturnType(referenceExpression: KtNameReferenceExpression): List<ExpectedType> {
return analyze(referenceExpression) {
val returnJvmType = referenceExpression.getExpectedKotlinType() ?: return emptyList()
val returnJvmType = referenceExpression.getExpectedKotlinType()
if (returnJvmType == null) {
val expectedType = builtinTypes.any
val jvmType = expectedType.convertToJvmType(referenceExpression) ?: return emptyList()
return listOf(ExpectedKotlinType(expectedType, jvmType))
}
listOf(returnJvmType)
}
}
@OptIn(KaExperimentalApi::class)
private fun getReceiverTypeString(
referenceExpression: KtNameReferenceExpression, renderer: KaTypeRenderer
): String? {
return analyze(referenceExpression) {
receiverType?.render(renderer, position = Variance.IN_VARIANCE)
}
}
override fun isValid(): Boolean = referencePointer.element?.getReferencedName() != null
override fun getFieldName(): String = referencePointer.element?.getReferencedName() ?: ""
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.idea.base.analysis.api.utils.hasApplicableAllowedTar
import org.jetbrains.kotlin.idea.base.analysis.api.utils.isApplicableTargetSet
import org.jetbrains.kotlin.idea.base.analysis.api.utils.shortenReferences
import org.jetbrains.kotlin.idea.base.codeInsight.ShortenReferencesFacility
import org.jetbrains.kotlin.idea.base.psi.classIdIfNonLocal
import org.jetbrains.kotlin.idea.base.psi.getOrCreateCompanionObject
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
import org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreateFunctionFromUsageUtil.resolveExpression
@@ -109,26 +110,37 @@ object K2CreatePropertyFromUsageBuilder {
else -> return emptyList()
}
val receiverType = receiverExpression?.expressionType
val lightClass = (defaultContainerPsi as? KtClassOrObject)?.toLightClass() ?: defaultContainerPsi as? PsiClass
val isAbstract = lightClass?.hasModifier(JvmModifier.ABSTRACT)
val containingKtFile = ref.containingKtFile
val wrapperForKtFile = JvmClassWrapperForKtClass(containingKtFile)
if (defaultContainerPsi != null) {
if (defaultContainerPsi.manager.isInProject(defaultContainerPsi)) {
val jvmModifiers = createModifiers(ref, defaultContainerPsi, isExtension = false, static, isAbstract == true)
if (lightClass != null) {
val jvmModifiers = createModifiers(ref, defaultContainerPsi, isExtension = false, static = static, isAbstract = isAbstract == true)
if (static || isAbstract!!.not()) {
requests.add(lightClass to CreatePropertyFromKotlinUsageRequest(ref, jvmModifiers, false))
requests.add(lightClass to CreatePropertyFromKotlinUsageRequest(ref, jvmModifiers, receiverType, isExtension = false))
}
if (lightClass.hasModifier(JvmModifier.ABSTRACT)) {
requests.add(lightClass to CreatePropertyFromKotlinUsageRequest(ref, jvmModifiers + JvmModifier.ABSTRACT, false))
requests.add(lightClass to CreatePropertyFromKotlinUsageRequest(ref, jvmModifiers + JvmModifier.ABSTRACT, receiverType, isExtension = false))
}
}
val jvmModifiers = createModifiers(ref, containingKtFile, isExtension = true, static = true, false)
val classId =
(defaultContainerPsi as? KtClassOrObject)?.classIdIfNonLocal ?: (defaultContainerPsi as? PsiClass)?.classIdIfNonLocal
if (classId != null) {
val targetClassType = buildClassType(if (static) ClassId.fromString(classId.asFqNameString() + ".Companion") else classId)
requests.add(wrapperForKtFile to CreatePropertyFromKotlinUsageRequest(ref, jvmModifiers, targetClassType, isExtension = true))
}
} else {
val jvmModifiers = createModifiers(ref, containingKtFile, isExtension = true, static = true, false)
requests.add(wrapperForKtFile to CreatePropertyFromKotlinUsageRequest(ref, jvmModifiers, receiverType, isExtension = true))
}
} else {
val containingKtFile = ref.containingKtFile
val jvmModifiers = createModifiers(ref, containingKtFile, isExtension = receiverExpression != null, static, false)
containingKtFile.toLightElements().firstOrNull()?.let { lightElement ->
if (lightElement is JvmClass) requests.add(lightElement to CreatePropertyFromKotlinUsageRequest(ref, jvmModifiers, receiverExpression != null))
}
val jvmModifiers = createModifiers(ref, containingKtFile, isExtension = receiverExpression != null, static = true, isAbstract = false)
requests.add(wrapperForKtFile to CreatePropertyFromKotlinUsageRequest(ref, jvmModifiers, receiverType, isExtension = receiverExpression != null))
}
return requests
}
@@ -184,7 +196,7 @@ object K2CreatePropertyFromUsageBuilder {
.filter { it != JvmModifier.PUBLIC && it != JvmModifier.ABSTRACT }
.mapNotNullTo(this, CreateFromUsageUtil::jvmModifierToKotlin)
if (lateinit) {
if (lateinit && !(request is CreatePropertyFromKotlinUsageRequest && request.isExtension)) {
this += KtTokens.LATEINIT_KEYWORD
} else if (request.isConstant) {
this += KtTokens.CONST_KEYWORD
@@ -193,8 +205,9 @@ object K2CreatePropertyFromUsageBuilder {
override fun getText(): String {
return if (request is CreatePropertyFromKotlinUsageRequest) {
if (request.isExtension && false) {
KotlinBundle.message("fix.create.from.usage.extension.property", """$classOrFileName.${request.fieldName}""")
if (request.isExtension) {
val receiverType = request.receiverTypeNameString?.let { "$it." } ?: ""
KotlinBundle.message("fix.create.from.usage.extension.property", """$receiverType${request.fieldName}""")
} else {
val key = if (JvmModifier.ABSTRACT in request.modifiers) {
"fix.create.from.usage.abstract.property"
@@ -233,12 +246,18 @@ object K2CreatePropertyFromUsageBuilder {
append(varVal)
append(" ")
if (request is CreatePropertyFromKotlinUsageRequest && request.isExtension) {
(request.receiverTypeString)?.let { append(it).append(".") }
}
append(request.fieldName.quoteIfNeeded())
append(": ")
analyze(container) {
val psiType = request.fieldType.firstOrNull()?.theType as? PsiType
val type = psiType?.asKaType(container)
val expectedType = request.fieldType.firstOrNull()
val type = when (expectedType) {
is ExpectedKotlinType -> expectedType.ktType
else -> (expectedType?.theType as? PsiType)?.asKaType(container)
}
type?.render(KaTypeRendererForSource.WITH_QUALIFIED_NAMES, Variance.IN_VARIANCE)
}?.let { append(it) }
@@ -0,0 +1,13 @@
// "Create extension property 'A.foo'" "true"
// ERROR: Unresolved reference: foo
import package1.A
private val package2.A.foo: Any
class X {
init {
val y = package2.A()
val foo = y.foo
}
}
@@ -0,0 +1,10 @@
private val A.Companion.foo: Int
// "Create extension property 'A.Companion.foo'" "true"
class A<T>(val n: T)
fun test() {
val a: Int = A.foo
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -4,4 +4,5 @@ class A<T>(val n: T)
fun test() {
val a: Int = A.<caret>foo
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -11,4 +11,5 @@ class A<T>(val n: T) {
fun test() {
val a: Int = A.foo
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -0,0 +1,10 @@
private val A.Companion.foo: Int
// "Create extension property 'A.Companion.foo'" "true"
class A
fun test() {
val a: Int = A.foo
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -4,4 +4,5 @@ class A
fun test() {
val a: Int = A.<caret>foo
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -11,4 +11,5 @@ class A {
fun test() {
val a: Int = A.foo
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -0,0 +1,8 @@
// "Create extension property 'A.foo'" "true"
// ERROR: Unresolved reference: foo
private val A.foo: String?
fun test(): String? {
return A().foo
}
@@ -0,0 +1,8 @@
// "Create extension property 'A.foo'" "true"
// ERROR: Unresolved reference: foo
private val A.foo: String?
fun test(): String? {
return A().foo
}
@@ -4,4 +4,6 @@ fun consume(n: Int) {}
fun <T> foo(t: T) {
consume(t.<caret>bar)
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// KTIJ-32974
// IGNORE_K2
@@ -9,4 +9,6 @@ fun consume(n: Int) {}
fun <T> foo(t: T) {
consume(t.bar)
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// KTIJ-32974
// IGNORE_K2
@@ -0,0 +1,10 @@
private val String?.notExistingVal: Int
// "Create extension property 'String?.notExistingVal'" "true"
fun foo(n: Int) {}
fun context(p: String?) {
foo(p.notExistingVal)
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -4,4 +4,5 @@ fun foo(n: Int) {}
fun context(p: String?) {
foo(p.<caret>notExistingVal)
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -9,4 +9,5 @@ fun foo(n: Int) {}
fun context(p: String?) {
foo(p.notExistingVal)
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -0,0 +1,11 @@
// "Create extension property 'Unit.foo'" "true"
// WITH_STDLIB
private val Unit.foo: Int
fun test() {
val a: Int = Unit.foo
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -5,4 +5,5 @@ fun test() {
val a: Int = Unit.<caret>foo
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -10,4 +10,5 @@ fun test() {
val a: Int = Unit.foo
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -0,0 +1,13 @@
// "Create extension property 'Int.foo'" "true"
// WITH_STDLIB
private val Int.foo: A<Int>
class A<T>(val n: T)
fun test() {
val a: A<Int> = 2.foo
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -7,4 +7,5 @@ fun test() {
val a: A<Int> = 2.<caret>foo
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -12,4 +12,5 @@ fun test() {
val a: A<Int> = 2.foo
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -0,0 +1,13 @@
// "Create extension property 'Int.foo'" "true"
// WITH_STDLIB
private var Int.foo: A<String>
class A<T>(val n: T)
fun test() {
2.foo = A("2")
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -7,4 +7,5 @@ fun test() {
2.<caret>foo = A("2")
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -13,4 +13,5 @@ fun test() {
2.foo = A("2")
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateExtensionCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -1,13 +0,0 @@
import kotlin.properties.ReadOnlyProperty
// "Create property 'foo'" "true"
// ERROR: Property must be initialized or be abstract
// ERROR: Variable 'foo' must be initialized
class A<T> {
private val foo: ReadOnlyProperty<A<T>?, A<Int>>
val x: A<Int> by foo
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -1,13 +0,0 @@
import kotlin.properties.ReadWriteProperty
// "Create property 'foo'" "true"
// ERROR: Property must be initialized or be abstract
// ERROR: Variable 'foo' must be initialized
class A<T> {
private val foo: ReadWriteProperty<A<T>?, A<Int>>
var x: A<Int> by foo
}
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable.CreateCallableFromUsageFix
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.k2.codeinsight.quickFixes.createFromUsage.K2CreatePropertyFromUsageBuilder$CreatePropertyFromUsageAction
@@ -3,7 +3,7 @@
// ERROR: Property must be initialized or be abstract
class A<T>(val n: T) {
val foo: A<Int>
val foo: A<Int>?
}
fun test() {