[FIR] Fix calculating arguments of bare type with intersection type as base

This commit is contained in:
Dmitriy Novozhilov
2021-02-19 14:01:44 +03:00
committed by TeamCityServer
parent 56f9e3360f
commit d40777c28f
6 changed files with 87 additions and 16 deletions
@@ -3256,6 +3256,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
public void testCapturedParametersOfInnerClasses() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.kt");
}
@TestMetadata("castToBareType.kt")
public void testCastToBareType() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/types/castToBareType.kt");
}
}
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/visibility")
@@ -0,0 +1,21 @@
FILE: castToBareType.kt
public abstract interface FirDeclaration : R|kotlin/Any| {
}
public abstract interface FirSymbolOwner<E : R|FirSymbolOwner<E>|> : R|kotlin/Any| {
public abstract val symbol: R|AbstractFirBasedSymbol<E>|
public get(): R|AbstractFirBasedSymbol<E>|
}
public abstract interface FirFunction<F : R|FirFunction<F>|> : R|FirSymbolOwner<F>|, R|FirDeclaration| {
}
public abstract interface AbstractFirBasedSymbol<E : R|FirSymbolOwner<E>|, R|FirDeclaration|> : R|kotlin/Any| {
public abstract val fir: R|E|
public get(): R|E|
}
public final fun foo(firAdaptee: R|FirFunction<*>|): R|kotlin/Unit| {
}
public final fun test(symbol: R|AbstractFirBasedSymbol<*>|): R|kotlin/Unit| {
lval firAdaptee: R|FirFunction<out it(FirSymbolOwner<out it(FirSymbolOwner<out it(FirSymbolOwner<out it(FirSymbolOwner<out kotlin/Any?> & FirDeclaration)> & FirDeclaration)> & FirDeclaration)> & FirDeclaration)>| = (R|<local>/symbol|.R|SubstitutionOverride</AbstractFirBasedSymbol.fir: R|CapturedType(*)|>| as R|FirFunction<out it(FirSymbolOwner<out it(FirSymbolOwner<out it(FirSymbolOwner<out it(FirSymbolOwner<out kotlin/Any?> & FirDeclaration)> & FirDeclaration)> & FirDeclaration)> & FirDeclaration)>|)
R|/foo|(R|<local>/firAdaptee|)
}
@@ -0,0 +1,17 @@
interface FirDeclaration
interface FirSymbolOwner<E : FirSymbolOwner<E>> {
val symbol: AbstractFirBasedSymbol<E>
}
interface FirFunction<F : FirFunction<F>> : FirSymbolOwner<F>, FirDeclaration
interface AbstractFirBasedSymbol<E> where E : FirSymbolOwner<E>, E : FirDeclaration {
val fir: E
}
fun foo(firAdaptee: FirFunction<*>) {}
fun test(symbol: AbstractFirBasedSymbol<*>) {
val firAdaptee = symbol.fir as FirFunction
foo(firAdaptee)
}
@@ -3630,6 +3630,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
public void testCapturedParametersOfInnerClasses() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.kt");
}
@Test
@TestMetadata("castToBareType.kt")
public void testCastToBareType() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/types/castToBareType.kt");
}
}
@Nested
@@ -3681,6 +3681,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
public void testCapturedParametersOfInnerClasses() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/types/capturedParametersOfInnerClasses.kt");
}
@Test
@TestMetadata("castToBareType.kt")
public void testCastToBareType() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/types/castToBareType.kt");
}
}
@Nested
@@ -499,25 +499,41 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
val firClass = type.lookupTag.toSymbol(session)?.fir ?: return this
if (firClass !is FirTypeParameterRefsOwner || firClass.typeParameters.isEmpty()) return this
val baseType = argument.typeRef.coneTypeSafe<ConeKotlinType>()?.lowerBoundIfFlexible()?.fullyExpandedType(session) ?: return this
if (baseType !is ConeClassLikeType) return this
val baseFirClass = baseType.lookupTag.toSymbol(session)?.fir ?: return this
val newArguments = if (AbstractTypeChecker.isSubtypeOfClass(
session.typeContext.newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true), baseType.lookupTag, type.lookupTag)) {
// If actual type of declaration is more specific than bare type then we should just find
// corresponding supertype with proper arguments
with(session.typeContext) {
val superType = baseType.fastCorrespondingSupertypes(type.lookupTag)?.firstOrNull() as? ConeKotlinType?
superType?.typeArguments
}
} else {
type.inheritTypeArguments(baseFirClass, baseType.typeArguments)
} ?: return buildErrorTypeRef {
val originalType = argument.typeRef.coneTypeSafe<ConeKotlinType>() ?: return this
val newType = computeRepresentativeTypeForBareType(type, originalType) ?: return buildErrorTypeRef {
source = this@withTypeArgumentsForBareType.source
diagnostic = ConeWrongNumberOfTypeArgumentsError(firClass.typeParameters.size, firClass.symbol)
}
return if (newArguments.isEmpty()) this else withReplacedConeType(type.withArguments(newArguments))
return if (newType.typeArguments.isEmpty()) this else withReplacedConeType(newType)
}
private fun computeRepresentativeTypeForBareType(type: ConeClassLikeType, originalType: ConeKotlinType): ConeKotlinType? {
@Suppress("NAME_SHADOWING")
val originalType = originalType.lowerBoundIfFlexible().fullyExpandedType(session)
if (originalType is ConeIntersectionType) {
val candidatesFromIntersectedTypes = originalType.intersectedTypes.mapNotNull { computeRepresentativeTypeForBareType(type, it) }
candidatesFromIntersectedTypes.firstOrNull { it.typeArguments.isNotEmpty() }?.let { return it }
return candidatesFromIntersectedTypes.firstOrNull()
}
if (originalType !is ConeClassLikeType) return type
val baseFirClass = originalType.lookupTag.toSymbol(session)?.fir ?: return type
val isSubtype = AbstractTypeChecker.isSubtypeOfClass(
session.typeContext.newBaseTypeCheckerContext(errorTypesEqualToAnything = false, stubTypesEqualToAnything = true),
originalType.lookupTag,
type.lookupTag
)
val newArguments = if (isSubtype) {
// If actual type of declaration is more specific than bare type then we should just find
// corresponding supertype with proper arguments
with(session.typeContext) {
val superType = originalType.fastCorrespondingSupertypes(type.lookupTag)?.firstOrNull() as? ConeKotlinType?
superType?.typeArguments
}
} else {
type.inheritTypeArguments(baseFirClass, originalType.typeArguments)
} ?: return null
if (newArguments.isEmpty()) return type
return type.withArguments(newArguments)
}
override fun transformTypeOperatorCall(