diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirJvmTypeMapper.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirJvmTypeMapper.kt index 98e731980ee..db275e32b3b 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirJvmTypeMapper.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirJvmTypeMapper.kt @@ -19,6 +19,6 @@ internal class KtFirJvmTypeMapper( ) : KtJvmTypeMapper(), KtFirAnalysisSessionComponent { override fun mapTypeToJvmType(type: KtType, mode: TypeMappingMode): Type { - return analysisSession.useSiteSession.jvmTypeMapper.mapType(type.coneType, mode, sw = null) + return analysisSession.useSiteSession.jvmTypeMapper.mapType(type.coneType, mode, sw = null, unresolvedQualifierRemapper = null) } } diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirPsiTypeProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirPsiTypeProvider.kt index bb2f8962f67..4a6dea8e15a 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirPsiTypeProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirPsiTypeProvider.kt @@ -20,8 +20,8 @@ import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtTypeMappingMode import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade import org.jetbrains.kotlin.asJava.elements.KtLightElement +import org.jetbrains.kotlin.asJava.elements.KtLightParameter import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter -import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.java.JavaVisibilities @@ -37,6 +37,7 @@ import org.jetbrains.kotlin.load.kotlin.getOptimalModeForReturnType import org.jetbrains.kotlin.load.kotlin.getOptimalModeForValueParameter import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.psi +import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.types.model.SimpleTypeMarker import java.text.StringCharacterIterator @@ -196,7 +197,14 @@ private fun ConeKotlinType.asPsiType( val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.SKIP_CHECKS) //TODO Check thread safety - session.jvmTypeMapper.mapType(this, mode, signatureWriter) + session.jvmTypeMapper.mapType(this, mode, signatureWriter) { + val containingFile = useSitePosition.containingKtFile + // parameters for default setters does not have kotlin origin, but setter has + ?: (useSitePosition as? KtLightParameter)?.parent?.parent?.containingKtFile + ?: return@mapType null + val correspondingImport = containingFile.findImportByAlias(it) ?: return@mapType null + correspondingImport.importPath?.pathStr + } val canonicalSignature = signatureWriter.toString() require(!canonicalSignature.contains(SpecialNames.ANONYMOUS_STRING)) @@ -213,6 +221,9 @@ private fun ConeKotlinType.asPsiType( return typeElement.type } +private val PsiElement.containingKtFile: KtFile? + get() = (this as? KtLightElement<*, *>)?.kotlinOrigin?.containingKtFile + private class AnonymousTypesSubstitutor( private val session: FirSession, ) : AbstractConeSubstitutor(session.typeContext) { diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByPsiForLibraryTestGenerated.java b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByPsiForLibraryTestGenerated.java index a43a02892c8..a6df161663e 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByPsiForLibraryTestGenerated.java +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/decompiled/SymbolLightClassesByPsiForLibraryTestGenerated.java @@ -258,6 +258,12 @@ public class SymbolLightClassesByPsiForLibraryTestGenerated extends AbstractSymb runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/typeAnnotations.kt"); } + @Test + @TestMetadata("unresolvedWithAliasedImport.kt") + public void testUnresolvedWithAliasedImport() throws Exception { + runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/unresolvedWithAliasedImport.kt"); + } + @Test @TestMetadata("wildcardOptimization.kt") public void testWildcardOptimization() throws Exception { diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByPsiForSourceTestGenerated.java b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByPsiForSourceTestGenerated.java index ed0b6eb5146..1915fe34090 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByPsiForSourceTestGenerated.java +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/source/SymbolLightClassesByPsiForSourceTestGenerated.java @@ -258,6 +258,12 @@ public class SymbolLightClassesByPsiForSourceTestGenerated extends AbstractSymbo runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/typeAnnotations.kt"); } + @Test + @TestMetadata("unresolvedWithAliasedImport.kt") + public void testUnresolvedWithAliasedImport() throws Exception { + runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/unresolvedWithAliasedImport.kt"); + } + @Test @TestMetadata("wildcardOptimization.kt") public void testWildcardOptimization() throws Exception { diff --git a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmTypeMapper.kt b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmTypeMapper.kt index 589aef0fb4d..9f56d1584e1 100644 --- a/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmTypeMapper.kt +++ b/compiler/fir/fir2ir/jvm-backend/src/org/jetbrains/kotlin/fir/backend/jvm/FirJvmTypeMapper.kt @@ -46,103 +46,169 @@ import org.jetbrains.kotlin.types.model.TypeParameterMarker import org.jetbrains.kotlin.utils.addToStdlib.runUnless import org.jetbrains.org.objectweb.asm.Type -class FirJvmTypeMapper(val session: FirSession) : TypeMappingContext, FirSessionComponent { +class FirJvmTypeMapper(val session: FirSession) : FirSessionComponent { companion object { val NON_EXISTENT_ID = ClassId.topLevel(StandardNames.NON_EXISTENT_CLASS) private val typeForNonExistentClass = ConeClassLikeLookupTagImpl(NON_EXISTENT_ID) .constructClassType(emptyArray(), isNullable = false) } - override val typeContext = ConeTypeSystemCommonBackendContextForTypeMapping(session.typeContext) - - fun mapType(type: ConeKotlinType, mode: TypeMappingMode = TypeMappingMode.DEFAULT, sw: JvmSignatureWriter? = null): Type { - return AbstractTypeMapper.mapType(this, type, mode, sw) - } - - override fun getClassInternalName(typeConstructor: TypeConstructorMarker): String { - require(typeConstructor is ConeClassLikeLookupTag) - return typeConstructor.classId.asString().replace(".", "$").replace("/", ".") - } - - override fun getScriptInternalName(typeConstructor: TypeConstructorMarker): String = - TODO("Not yet implemented") - - override fun JvmSignatureWriter.writeGenericType(type: KotlinTypeMarker, asmType: Type, mode: TypeMappingMode) { - if (type !is ConeKotlinType) return - if (skipGenericSignature() || hasNothingInNonContravariantPosition(type) || type.typeArguments.isEmpty()) { - writeAsmType(asmType) - return - } - - val possiblyInnerType = type.buildPossiblyInnerType() - - val innerTypesAsList = possiblyInnerType.segments() - - val indexOfParameterizedType = innerTypesAsList.indexOfFirst { innerPart -> innerPart.arguments.isNotEmpty() } - if (indexOfParameterizedType < 0 || innerTypesAsList.size == 1) { - writeClassBegin(asmType) - writeGenericArguments(this, possiblyInnerType, mode) + fun mapType( + type: ConeKotlinType, + mode: TypeMappingMode = TypeMappingMode.DEFAULT, + sw: JvmSignatureWriter? = null, + unresolvedQualifierRemapper: ((String) -> String?)? = null + ): Type { + val context = if (unresolvedQualifierRemapper != null) { + Context(unresolvedQualifierRemapper) } else { - val outerType = innerTypesAsList[indexOfParameterizedType] - - writeOuterClassBegin(asmType, mapType(outerType.classifier?.fir?.defaultType() ?: typeForNonExistentClass).internalName) - writeGenericArguments(this, outerType, mode) - - writeInnerParts( - innerTypesAsList, - this, - mode, - indexOfParameterizedType + 1 - ) // inner parts separated by `.` + defaultContext } - - writeClassEnd() + return AbstractTypeMapper.mapType(context, type, mode, sw) } - private fun hasNothingInNonContravariantPosition(type: ConeKotlinType): Boolean = with(KotlinTypeMapper) { - typeContext.hasNothingInNonContravariantPosition(type) - } + private val defaultContext = Context { null } + val typeContext: TypeSystemCommonBackendContext + get() = defaultContext.typeContext - private fun ConeKotlinType.buildPossiblyInnerType(): PossiblyInnerConeType { - fun createForError(): PossiblyInnerConeType { - return PossiblyInnerConeType(classifier = null, typeArguments.toList(), outerType = null) + private inner class Context(unresolvedQualifierRemapper: (String) -> String?) : TypeMappingContext { + private fun mapType(type: ConeKotlinType, mode: TypeMappingMode = TypeMappingMode.DEFAULT, sw: JvmSignatureWriter? = null): Type { + return AbstractTypeMapper.mapType(this, type, mode, sw) } - if (this !is ConeClassLikeType) return createForError() + override val typeContext = ConeTypeSystemCommonBackendContextForTypeMapping(session.typeContext, unresolvedQualifierRemapper) - return when (val symbol = lookupTag.toSymbol(session)) { - is FirRegularClassSymbol -> buildPossiblyInnerType(symbol, 0) - is FirTypeAliasSymbol -> { - val expandedType = fullyExpandedType(session) as? ConeClassLikeType - val classSymbol = expandedType?.lookupTag?.toSymbol(session) as? FirRegularClassSymbol - classSymbol?.let { expandedType.buildPossiblyInnerType(it, 0) } + override fun getClassInternalName(typeConstructor: TypeConstructorMarker): String { + require(typeConstructor is ConeClassLikeLookupTag) + return typeConstructor.classId.asString().replace(".", "$").replace("/", ".") + } + + override fun getScriptInternalName(typeConstructor: TypeConstructorMarker): String = + TODO("Not yet implemented") + + override fun JvmSignatureWriter.writeGenericType(type: KotlinTypeMarker, asmType: Type, mode: TypeMappingMode) { + if (type !is ConeKotlinType) return + if (skipGenericSignature() || hasNothingInNonContravariantPosition(type) || type.typeArguments.isEmpty()) { + writeAsmType(asmType) + return } - else -> null - } ?: createForError() - } - private fun ConeClassLikeType.parentClassOrNull(): FirRegularClassSymbol? { - val parentClassId = classId?.outerClassId ?: return null - return session.symbolProvider.getClassLikeSymbolByClassId(parentClassId) as? FirRegularClassSymbol? - } + val possiblyInnerType = type.buildPossiblyInnerType() - private fun ConeClassLikeType.buildPossiblyInnerType(classifier: FirRegularClassSymbol?, index: Int): PossiblyInnerConeType? { - if (classifier == null) return null + val innerTypesAsList = possiblyInnerType.segments() - val firClass = classifier.fir - val toIndex = firClass.typeParameters.count { it is FirTypeParameter } + index - if (!firClass.isInner) { - assert(toIndex == typeArguments.size || firClass.isLocal) { - "${typeArguments.size - toIndex} trailing arguments were found in this type: ${renderForDebugging()}" + val indexOfParameterizedType = innerTypesAsList.indexOfFirst { innerPart -> innerPart.arguments.isNotEmpty() } + if (indexOfParameterizedType < 0 || innerTypesAsList.size == 1) { + writeClassBegin(asmType) + writeGenericArguments(this, possiblyInnerType, mode) + } else { + val outerType = innerTypesAsList[indexOfParameterizedType] + + writeOuterClassBegin(asmType, mapType(outerType.classifier?.fir?.defaultType() ?: typeForNonExistentClass).internalName) + writeGenericArguments(this, outerType, mode) + + writeInnerParts( + innerTypesAsList, + this, + mode, + indexOfParameterizedType + 1 + ) // inner parts separated by `.` } - return PossiblyInnerConeType(classifier, typeArguments.toList().subList(index, typeArguments.size), null) + + writeClassEnd() } - val argumentsSubList = typeArguments.toList().subList(index, toIndex) - return PossiblyInnerConeType( - classifier, argumentsSubList, - buildPossiblyInnerType(firClass.defaultType().parentClassOrNull(), toIndex) - ) + private fun hasNothingInNonContravariantPosition(type: ConeKotlinType): Boolean = with(KotlinTypeMapper) { + typeContext.hasNothingInNonContravariantPosition(type) + } + + private fun ConeKotlinType.buildPossiblyInnerType(): PossiblyInnerConeType { + fun createForError(): PossiblyInnerConeType { + return PossiblyInnerConeType(classifier = null, typeArguments.toList(), outerType = null) + } + + if (this !is ConeClassLikeType) return createForError() + + return when (val symbol = lookupTag.toSymbol(session)) { + is FirRegularClassSymbol -> buildPossiblyInnerType(symbol, 0) + is FirTypeAliasSymbol -> { + val expandedType = fullyExpandedType(session) as? ConeClassLikeType + val classSymbol = expandedType?.lookupTag?.toSymbol(session) as? FirRegularClassSymbol + classSymbol?.let { expandedType.buildPossiblyInnerType(it, 0) } + } + else -> null + } ?: createForError() + } + + private fun ConeClassLikeType.parentClassOrNull(): FirRegularClassSymbol? { + val parentClassId = classId?.outerClassId ?: return null + return session.symbolProvider.getClassLikeSymbolByClassId(parentClassId) as? FirRegularClassSymbol? + } + + private fun ConeClassLikeType.buildPossiblyInnerType(classifier: FirRegularClassSymbol?, index: Int): PossiblyInnerConeType? { + if (classifier == null) return null + + val firClass = classifier.fir + val toIndex = firClass.typeParameters.count { it is FirTypeParameter } + index + if (!firClass.isInner) { + assert(toIndex == typeArguments.size || firClass.isLocal) { + "${typeArguments.size - toIndex} trailing arguments were found in this type: ${renderForDebugging()}" + } + return PossiblyInnerConeType(classifier, typeArguments.toList().subList(index, typeArguments.size), null) + } + + val argumentsSubList = typeArguments.toList().subList(index, toIndex) + return PossiblyInnerConeType( + classifier, argumentsSubList, + buildPossiblyInnerType(firClass.defaultType().parentClassOrNull(), toIndex) + ) + } + + private fun writeGenericArguments( + sw: JvmSignatureWriter, + type: PossiblyInnerConeType, + mode: TypeMappingMode + ) { + val classifier = type.classifier?.fir + val defaultType = classifier?.defaultType() ?: typeForNonExistentClass + val parameters = classifier?.typeParameters.orEmpty().map { it.symbol } + val arguments = type.arguments + + if ((defaultType.isFunctionalType(session) && arguments.size > BuiltInFunctionArity.BIG_ARITY) + || defaultType.isKFunctionType(session) + ) { + writeGenericArguments(sw, listOf(arguments.last()), listOf(parameters.last()), mode) + return + } + + writeGenericArguments(sw, arguments, parameters, mode) + } + + private fun writeGenericArguments( + sw: JvmSignatureWriter, + arguments: List, + parameterSymbols: List, + mode: TypeMappingMode + ) { + with(KotlinTypeMapper) { + val parameters = parameterSymbols.map { ConeTypeParameterLookupTag(it) } + typeContext.writeGenericArguments(sw, arguments, parameters, mode) { type, sw, mode -> + mapType(type as ConeKotlinType, mode, sw) + } + } + } + + private fun writeInnerParts( + innerTypesAsList: List, + sw: JvmSignatureWriter, + mode: TypeMappingMode, + index: Int + ) { + for (innerPart in innerTypesAsList.subList(index, innerTypesAsList.size)) { + sw.writeInnerClass(getJvmShortName(innerPart.classifier?.classId ?: NON_EXISTENT_ID)) + writeGenericArguments(sw, innerPart, mode) + } + } } private class PossiblyInnerConeType( @@ -153,53 +219,7 @@ class FirJvmTypeMapper(val session: FirSession) : TypeMappingContext = outerType?.segments().orEmpty() + this } - private fun writeGenericArguments( - sw: JvmSignatureWriter, - type: PossiblyInnerConeType, - mode: TypeMappingMode - ) { - val classifier = type.classifier?.fir - val defaultType = classifier?.defaultType() ?: typeForNonExistentClass - val parameters = classifier?.typeParameters.orEmpty().map { it.symbol } - val arguments = type.arguments - - if ((defaultType.isFunctionalType(session) && arguments.size > BuiltInFunctionArity.BIG_ARITY) - || defaultType.isKFunctionType(session) - ) { - writeGenericArguments(sw, listOf(arguments.last()), listOf(parameters.last()), mode) - return - } - - writeGenericArguments(sw, arguments, parameters, mode) - } - - private fun writeGenericArguments( - sw: JvmSignatureWriter, - arguments: List, - parameterSymbols: List, - mode: TypeMappingMode - ) { - with(KotlinTypeMapper) { - val parameters = parameterSymbols.map { ConeTypeParameterLookupTag(it) } - typeContext.writeGenericArguments(sw, arguments, parameters, mode) { type, sw, mode -> - mapType(type as ConeKotlinType, mode, sw) - } - } - } - - private fun writeInnerParts( - innerTypesAsList: List, - sw: JvmSignatureWriter, - mode: TypeMappingMode, - index: Int - ) { - for (innerPart in innerTypesAsList.subList(index, innerTypesAsList.size)) { - sw.writeInnerClass(getJvmShortName(innerPart.classifier?.classId ?: NON_EXISTENT_ID)) - writeGenericArguments(sw, innerPart, mode) - } - } - - internal fun getJvmShortName(klass: FirRegularClass): String { + fun getJvmShortName(klass: FirRegularClass): String { return getJvmShortName(klass.classId) } @@ -214,7 +234,8 @@ class FirJvmTypeMapper(val session: FirSession) : TypeMappingContext String? ) : TypeSystemCommonBackendContext by context, TypeSystemCommonBackendContextForTypeMapping { private val session = context.session private val symbolProvider = session.symbolProvider @@ -299,6 +320,6 @@ class ConeTypeSystemCommonBackendContextForTypeMapping( is ConeUnresolvedTypeQualifierError -> diagnostic.qualifier else -> null } - return result + return result?.let { unresolvedQualifierRemapper(it) ?: it } } } diff --git a/compiler/testData/asJava/lightClasses/lightClassByPsi/unresolvedWithAliasedImport.fir.java b/compiler/testData/asJava/lightClasses/lightClassByPsi/unresolvedWithAliasedImport.fir.java new file mode 100644 index 00000000000..84ccbbce082 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/lightClassByPsi/unresolvedWithAliasedImport.fir.java @@ -0,0 +1,9 @@ +public final class Derived /* some.Derived*/ implements other.Unresolved { + private final other.Unresolved x = null /* initializer type: null */; + + public Derived();// .ctor() + + public final other.Unresolved getX();// getX() + + public final void takeA(other.Unresolved);// takeA(other.Unresolved) +} diff --git a/compiler/testData/asJava/lightClasses/lightClassByPsi/unresolvedWithAliasedImport.java b/compiler/testData/asJava/lightClasses/lightClassByPsi/unresolvedWithAliasedImport.java new file mode 100644 index 00000000000..f34d0072144 --- /dev/null +++ b/compiler/testData/asJava/lightClasses/lightClassByPsi/unresolvedWithAliasedImport.java @@ -0,0 +1,9 @@ +public final class Derived /* some.Derived*/ { + private final error.NonExistentClass x; + + public Derived();// .ctor() + + public final error.NonExistentClass getX();// getX() + + public final void takeA(error.NonExistentClass);// takeA(error.NonExistentClass) +} diff --git a/compiler/testData/asJava/lightClasses/lightClassByPsi/unresolvedWithAliasedImport.kt b/compiler/testData/asJava/lightClasses/lightClassByPsi/unresolvedWithAliasedImport.kt new file mode 100644 index 00000000000..4e86d2d604e --- /dev/null +++ b/compiler/testData/asJava/lightClasses/lightClassByPsi/unresolvedWithAliasedImport.kt @@ -0,0 +1,11 @@ +package some + +import other.Unresolved as A + +class Derived : A { + val x: A? = null + + fun takeA(a: A) {} +} + +// COMPILATION_ERRORS