[FIR] Fix inferring arguments of bare types in different situations
- argument type is flexible - supertype has flexible type argument - type of expression is more specific than bare type
This commit is contained in:
committed by
TeamCityServer
parent
b99f1a1512
commit
14108011ee
+10
@@ -39,6 +39,16 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/bareTypes.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/bareTypes.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("bareTypes2.kt")
|
||||||
|
public void testBareTypes2() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/bareTypes2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("bareTypesWithFlexibleArguments.kt")
|
||||||
|
public void testBareTypesWithFlexibleArguments() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/bareTypesWithFlexibleArguments.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("cast.kt")
|
@TestMetadata("cast.kt")
|
||||||
public void testCast() throws Exception {
|
public void testCast() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/cast.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/cast.kt");
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
FILE: bareTypes2.kt
|
||||||
|
public abstract interface A<D : R|A<D>|> : R|kotlin/Any| {
|
||||||
|
public abstract fun foo(): R|kotlin/Any|
|
||||||
|
|
||||||
|
public abstract val cond: R|kotlin/Boolean|
|
||||||
|
public get(): R|kotlin/Boolean|
|
||||||
|
|
||||||
|
public abstract val field: R|kotlin/Any|
|
||||||
|
public get(): R|kotlin/Any|
|
||||||
|
|
||||||
|
}
|
||||||
|
public abstract interface B<F : R|B<F>|> : R|A<F>| {
|
||||||
|
public abstract override fun foo(): R|kotlin/CharSequence|
|
||||||
|
|
||||||
|
}
|
||||||
|
public abstract interface C : R|B<C>| {
|
||||||
|
public abstract override fun foo(): R|kotlin/String|
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun test(x: R|A<*>|): R|kotlin/Unit| {
|
||||||
|
when ((R|<local>/x| as? R|C|)?.{ $subj$.R|/A.field| }) {
|
||||||
|
($subj$ is R|kotlin/String|) -> {
|
||||||
|
when () {
|
||||||
|
==((R|<local>/x| as? R|B<C>|)?.{ $subj$.R|/A.cond| }, Boolean(true)) -> {
|
||||||
|
R|<local>/x|.R|/C.foo|()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
interface A<D : A<D>> {
|
||||||
|
fun foo(): Any
|
||||||
|
|
||||||
|
val cond: Boolean
|
||||||
|
val field: Any
|
||||||
|
}
|
||||||
|
|
||||||
|
interface B<F : B<F>> : A<F> {
|
||||||
|
override fun foo(): CharSequence
|
||||||
|
}
|
||||||
|
|
||||||
|
interface C : B<C> {
|
||||||
|
override fun foo(): String
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test(x: A<*>) {
|
||||||
|
when ((x as? C)?.field) {
|
||||||
|
is String -> {
|
||||||
|
if ((x as? B)?.cond == true) {
|
||||||
|
x.foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
FILE: bareTypesWithFlexibleArguments.kt
|
||||||
|
public final fun <T> R|kotlin/collections/Collection<T>?|.concat(collection: R|kotlin/collections/Collection<T>|): R|kotlin/collections/Collection<T>?| {
|
||||||
|
when () {
|
||||||
|
(this@R|/concat| is R|kotlin/collections/LinkedHashSet<T>|) -> {
|
||||||
|
this@R|/concat|.R|SubstitutionOverride<java/util/LinkedHashSet.addAll: R|kotlin/Boolean|>|(R|<local>/collection|)
|
||||||
|
^concat this@R|/concat|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
^concat this@R|/concat|
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// WITH_STDLIB
|
||||||
|
// FULL_JDK
|
||||||
|
|
||||||
|
fun <T> Collection<T>?.concat(collection: Collection<T>): Collection<T>? {
|
||||||
|
if (this is LinkedHashSet) {
|
||||||
|
addAll(collection)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
+12
@@ -38,6 +38,18 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/bareTypes.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/bareTypes.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("bareTypes2.kt")
|
||||||
|
public void testBareTypes2() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/bareTypes2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("bareTypesWithFlexibleArguments.kt")
|
||||||
|
public void testBareTypesWithFlexibleArguments() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/bareTypesWithFlexibleArguments.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("cast.kt")
|
@TestMetadata("cast.kt")
|
||||||
public void testCast() throws Exception {
|
public void testCast() throws Exception {
|
||||||
|
|||||||
+12
@@ -39,6 +39,18 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/bareTypes.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/bareTypes.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("bareTypes2.kt")
|
||||||
|
public void testBareTypes2() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/bareTypes2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("bareTypesWithFlexibleArguments.kt")
|
||||||
|
public void testBareTypesWithFlexibleArguments() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/bareTypesWithFlexibleArguments.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("cast.kt")
|
@TestMetadata("cast.kt")
|
||||||
public void testCast() throws Exception {
|
public void testCast() throws Exception {
|
||||||
|
|||||||
+19
-6
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.fir.types.builder.*
|
|||||||
import org.jetbrains.kotlin.fir.visitors.*
|
import org.jetbrains.kotlin.fir.visitors.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||||
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||||
|
|
||||||
@@ -473,7 +474,10 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
|||||||
val type = typeRef.coneTypeSafe<ConeClassLikeType>() ?: return null
|
val type = typeRef.coneTypeSafe<ConeClassLikeType>() ?: return null
|
||||||
val indexMapping = typeParameters.map { parameter ->
|
val indexMapping = typeParameters.map { parameter ->
|
||||||
// TODO: if many, check consistency of the result
|
// TODO: if many, check consistency of the result
|
||||||
type.typeArguments.indexOfFirst { it is ConeTypeParameterType && it.lookupTag.typeParameterSymbol == parameter.symbol }
|
type.typeArguments.indexOfFirst {
|
||||||
|
val argument = (it as? ConeKotlinType)?.lowerBoundIfFlexible()
|
||||||
|
argument is ConeTypeParameterType && argument.lookupTag.typeParameterSymbol == parameter.symbol
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (indexMapping.any { it == -1 }) return null
|
if (indexMapping.any { it == -1 }) return null
|
||||||
|
|
||||||
@@ -488,14 +492,23 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
|||||||
val firClass = type.lookupTag.toSymbol(session)?.fir ?: return this
|
val firClass = type.lookupTag.toSymbol(session)?.fir ?: return this
|
||||||
if (firClass !is FirTypeParameterRefsOwner || firClass.typeParameters.isEmpty()) return this
|
if (firClass !is FirTypeParameterRefsOwner || firClass.typeParameters.isEmpty()) return this
|
||||||
|
|
||||||
val baseType = argument.typeRef.coneTypeSafe<ConeClassLikeType>()?.fullyExpandedType(session) ?: 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 baseFirClass = baseType.lookupTag.toSymbol(session)?.fir ?: return this
|
||||||
|
|
||||||
val newArguments = type.inheritTypeArguments(baseFirClass, baseType.typeArguments)
|
val newArguments = if (AbstractTypeChecker.isSubtypeOfClass(session.typeCheckerContext, baseType.lookupTag, type.lookupTag)) {
|
||||||
?: return buildErrorTypeRef {
|
// If actual type of declaration is more specific than bare type then we should just find
|
||||||
source = this@withTypeArgumentsForBareType.source
|
// corresponding supertype with proper arguments
|
||||||
diagnostic = ConeWrongNumberOfTypeArgumentsError(firClass.typeParameters.size, firClass.symbol)
|
with(session.typeContext) {
|
||||||
|
val superType = baseType.fastCorrespondingSupertypes(type.lookupTag)?.firstOrNull() as? ConeKotlinType?
|
||||||
|
superType?.typeArguments
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
type.inheritTypeArguments(baseFirClass, baseType.typeArguments)
|
||||||
|
} ?: 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 (newArguments.isEmpty()) this else withReplacedConeType(type.withArguments(newArguments))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user