[AA LC] Map unresolved types according to aliased imports

This commit is contained in:
Dmitriy Novozhilov
2022-12-16 12:54:41 +02:00
committed by Space Team
parent d5a76a1b3b
commit 36ae901b19
8 changed files with 201 additions and 128 deletions
@@ -19,6 +19,6 @@ internal class KtFirJvmTypeMapper(
) : KtJvmTypeMapper(), KtFirAnalysisSessionComponent { ) : KtJvmTypeMapper(), KtFirAnalysisSessionComponent {
override fun mapTypeToJvmType(type: KtType, mode: TypeMappingMode): Type { 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)
} }
} }
@@ -20,8 +20,8 @@ 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.classes.KtLightClassForFacade import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
import org.jetbrains.kotlin.asJava.elements.KtLightElement 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.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.java.JavaVisibilities 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.load.kotlin.getOptimalModeForValueParameter
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi import org.jetbrains.kotlin.psi
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.types.model.SimpleTypeMarker import org.jetbrains.kotlin.types.model.SimpleTypeMarker
import java.text.StringCharacterIterator import java.text.StringCharacterIterator
@@ -196,7 +197,14 @@ private fun ConeKotlinType.asPsiType(
val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.SKIP_CHECKS) val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.SKIP_CHECKS)
//TODO Check thread safety //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() val canonicalSignature = signatureWriter.toString()
require(!canonicalSignature.contains(SpecialNames.ANONYMOUS_STRING)) require(!canonicalSignature.contains(SpecialNames.ANONYMOUS_STRING))
@@ -213,6 +221,9 @@ private fun ConeKotlinType.asPsiType(
return typeElement.type return typeElement.type
} }
private val PsiElement.containingKtFile: KtFile?
get() = (this as? KtLightElement<*, *>)?.kotlinOrigin?.containingKtFile
private class AnonymousTypesSubstitutor( private class AnonymousTypesSubstitutor(
private val session: FirSession, private val session: FirSession,
) : AbstractConeSubstitutor(session.typeContext) { ) : AbstractConeSubstitutor(session.typeContext) {
@@ -258,6 +258,12 @@ public class SymbolLightClassesByPsiForLibraryTestGenerated extends AbstractSymb
runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/typeAnnotations.kt"); 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 @Test
@TestMetadata("wildcardOptimization.kt") @TestMetadata("wildcardOptimization.kt")
public void testWildcardOptimization() throws Exception { public void testWildcardOptimization() throws Exception {
@@ -258,6 +258,12 @@ public class SymbolLightClassesByPsiForSourceTestGenerated extends AbstractSymbo
runTest("compiler/testData/asJava/lightClasses/lightClassByPsi/typeAnnotations.kt"); 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 @Test
@TestMetadata("wildcardOptimization.kt") @TestMetadata("wildcardOptimization.kt")
public void testWildcardOptimization() throws Exception { public void testWildcardOptimization() throws Exception {
@@ -46,103 +46,169 @@ import org.jetbrains.kotlin.types.model.TypeParameterMarker
import org.jetbrains.kotlin.utils.addToStdlib.runUnless import org.jetbrains.kotlin.utils.addToStdlib.runUnless
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
class FirJvmTypeMapper(val session: FirSession) : TypeMappingContext<JvmSignatureWriter>, FirSessionComponent { class FirJvmTypeMapper(val session: FirSession) : FirSessionComponent {
companion object { companion object {
val NON_EXISTENT_ID = ClassId.topLevel(StandardNames.NON_EXISTENT_CLASS) val NON_EXISTENT_ID = ClassId.topLevel(StandardNames.NON_EXISTENT_CLASS)
private val typeForNonExistentClass = ConeClassLikeLookupTagImpl(NON_EXISTENT_ID) private val typeForNonExistentClass = ConeClassLikeLookupTagImpl(NON_EXISTENT_ID)
.constructClassType(emptyArray(), isNullable = false) .constructClassType(emptyArray(), isNullable = false)
} }
override val typeContext = ConeTypeSystemCommonBackendContextForTypeMapping(session.typeContext) fun mapType(
type: ConeKotlinType,
fun mapType(type: ConeKotlinType, mode: TypeMappingMode = TypeMappingMode.DEFAULT, sw: JvmSignatureWriter? = null): Type { mode: TypeMappingMode = TypeMappingMode.DEFAULT,
return AbstractTypeMapper.mapType(this, type, mode, sw) sw: JvmSignatureWriter? = null,
} unresolvedQualifierRemapper: ((String) -> String?)? = null
): Type {
override fun getClassInternalName(typeConstructor: TypeConstructorMarker): String { val context = if (unresolvedQualifierRemapper != null) {
require(typeConstructor is ConeClassLikeLookupTag) Context(unresolvedQualifierRemapper)
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)
} else { } else {
val outerType = innerTypesAsList[indexOfParameterizedType] defaultContext
writeOuterClassBegin(asmType, mapType(outerType.classifier?.fir?.defaultType() ?: typeForNonExistentClass).internalName)
writeGenericArguments(this, outerType, mode)
writeInnerParts(
innerTypesAsList,
this,
mode,
indexOfParameterizedType + 1
) // inner parts separated by `.`
} }
return AbstractTypeMapper.mapType(context, type, mode, sw)
writeClassEnd()
} }
private fun hasNothingInNonContravariantPosition(type: ConeKotlinType): Boolean = with(KotlinTypeMapper) { private val defaultContext = Context { null }
typeContext.hasNothingInNonContravariantPosition(type) val typeContext: TypeSystemCommonBackendContext
} get() = defaultContext.typeContext
private fun ConeKotlinType.buildPossiblyInnerType(): PossiblyInnerConeType { private inner class Context(unresolvedQualifierRemapper: (String) -> String?) : TypeMappingContext<JvmSignatureWriter> {
fun createForError(): PossiblyInnerConeType { private fun mapType(type: ConeKotlinType, mode: TypeMappingMode = TypeMappingMode.DEFAULT, sw: JvmSignatureWriter? = null): Type {
return PossiblyInnerConeType(classifier = null, typeArguments.toList(), outerType = null) 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)) { override fun getClassInternalName(typeConstructor: TypeConstructorMarker): String {
is FirRegularClassSymbol -> buildPossiblyInnerType(symbol, 0) require(typeConstructor is ConeClassLikeLookupTag)
is FirTypeAliasSymbol -> { return typeConstructor.classId.asString().replace(".", "$").replace("/", ".")
val expandedType = fullyExpandedType(session) as? ConeClassLikeType }
val classSymbol = expandedType?.lookupTag?.toSymbol(session) as? FirRegularClassSymbol
classSymbol?.let { expandedType.buildPossiblyInnerType(it, 0) } 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 possiblyInnerType = type.buildPossiblyInnerType()
val parentClassId = classId?.outerClassId ?: return null
return session.symbolProvider.getClassLikeSymbolByClassId(parentClassId) as? FirRegularClassSymbol?
}
private fun ConeClassLikeType.buildPossiblyInnerType(classifier: FirRegularClassSymbol?, index: Int): PossiblyInnerConeType? { val innerTypesAsList = possiblyInnerType.segments()
if (classifier == null) return null
val firClass = classifier.fir val indexOfParameterizedType = innerTypesAsList.indexOfFirst { innerPart -> innerPart.arguments.isNotEmpty() }
val toIndex = firClass.typeParameters.count { it is FirTypeParameter } + index if (indexOfParameterizedType < 0 || innerTypesAsList.size == 1) {
if (!firClass.isInner) { writeClassBegin(asmType)
assert(toIndex == typeArguments.size || firClass.isLocal) { writeGenericArguments(this, possiblyInnerType, mode)
"${typeArguments.size - toIndex} trailing arguments were found in this type: ${renderForDebugging()}" } 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) private fun hasNothingInNonContravariantPosition(type: ConeKotlinType): Boolean = with(KotlinTypeMapper) {
return PossiblyInnerConeType( typeContext.hasNothingInNonContravariantPosition(type)
classifier, argumentsSubList, }
buildPossiblyInnerType(firClass.defaultType().parentClassOrNull(), toIndex)
) 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<ConeTypeProjection>,
parameterSymbols: List<FirTypeParameterSymbol>,
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<PossiblyInnerConeType>,
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( private class PossiblyInnerConeType(
@@ -153,53 +219,7 @@ class FirJvmTypeMapper(val session: FirSession) : TypeMappingContext<JvmSignatur
fun segments(): List<PossiblyInnerConeType> = outerType?.segments().orEmpty() + this fun segments(): List<PossiblyInnerConeType> = outerType?.segments().orEmpty() + this
} }
private fun writeGenericArguments( fun getJvmShortName(klass: FirRegularClass): String {
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<ConeTypeProjection>,
parameterSymbols: List<FirTypeParameterSymbol>,
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<PossiblyInnerConeType>,
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 {
return getJvmShortName(klass.classId) return getJvmShortName(klass.classId)
} }
@@ -214,7 +234,8 @@ class FirJvmTypeMapper(val session: FirSession) : TypeMappingContext<JvmSignatur
val FirSession.jvmTypeMapper: FirJvmTypeMapper by FirSession.sessionComponentAccessor() val FirSession.jvmTypeMapper: FirJvmTypeMapper by FirSession.sessionComponentAccessor()
class ConeTypeSystemCommonBackendContextForTypeMapping( class ConeTypeSystemCommonBackendContextForTypeMapping(
val context: ConeTypeContext val context: ConeTypeContext,
val unresolvedQualifierRemapper: (String) -> String?
) : TypeSystemCommonBackendContext by context, TypeSystemCommonBackendContextForTypeMapping { ) : TypeSystemCommonBackendContext by context, TypeSystemCommonBackendContextForTypeMapping {
private val session = context.session private val session = context.session
private val symbolProvider = session.symbolProvider private val symbolProvider = session.symbolProvider
@@ -299,6 +320,6 @@ class ConeTypeSystemCommonBackendContextForTypeMapping(
is ConeUnresolvedTypeQualifierError -> diagnostic.qualifier is ConeUnresolvedTypeQualifierError -> diagnostic.qualifier
else -> null else -> null
} }
return result return result?.let { unresolvedQualifierRemapper(it) ?: it }
} }
} }
@@ -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)
}
@@ -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)
}
@@ -0,0 +1,11 @@
package some
import other.Unresolved as A
class Derived : A {
val x: A? = null
fun takeA(a: A) {}
}
// COMPILATION_ERRORS