FIR: Weaken some UPPER_BOUND_VIOLATED restrictions
See test data at starProjectionInsteadOutCaptured.kt ^KT-49412 Fixed ^KT-50230 Relates ^KT-48044 Fixed
This commit is contained in:
+18
@@ -13881,6 +13881,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
||||
runTest("compiler/testData/diagnostics/tests/inference/underscoredTypeInForbiddenPositions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unsoundness1.kt")
|
||||
public void testUnsoundness1() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/unsoundness1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unsoundness2.kt")
|
||||
public void testUnsoundness2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/unsoundness2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("useFunctionLiteralsToInferType.kt")
|
||||
public void testUseFunctionLiteralsToInferType() throws Exception {
|
||||
@@ -31083,6 +31095,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/repeatedBound.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("starProjectionInsteadOutCaptured.kt")
|
||||
public void testStarProjectionInsteadOutCaptured() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/starProjectionInsteadOutCaptured.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("upperBoundCannotBeArray.kt")
|
||||
public void testUpperBoundCannotBeArray() throws Exception {
|
||||
|
||||
+18
@@ -140,3 +140,21 @@ FILE: upperBoundViolated.kt
|
||||
|
||||
}
|
||||
public final typealias Alias<V1> = R|(Class<V1>) -> kotlin/Boolean|
|
||||
public abstract class Base<T : R|Base<T>|> : R|kotlin/Any| {
|
||||
public constructor<T : R|Base<T>|>(): R|Base<T>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final class DerivedOut<out O : R|Base<out O>|> : R|kotlin/Any| {
|
||||
public constructor<out O : R|Base<out O>|>(): R|DerivedOut<O>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final class DerivedIn<in I : R|Base<in I>|> : R|kotlin/Any| {
|
||||
public constructor<in I : R|Base<in I>|>(): R|DerivedIn<I>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-3
@@ -55,7 +55,7 @@ class Test1<S1 : Test1<S1, K>, K : Any>
|
||||
class Test2<S2 : Test1<S2, *>>
|
||||
|
||||
class Test3<S3 : Test3<S3, in K>, K : Any>
|
||||
class Test4<S4 : Test3<<!UPPER_BOUND_VIOLATED!>S4<!>, out Any>>
|
||||
class Test4<S4 : Test3<S4, out Any>>
|
||||
|
||||
class Test5<S5 : Test5<S5, in K>, K : Any>
|
||||
class Test6<S6 : Test5<S6, in Any>>
|
||||
@@ -66,9 +66,8 @@ class Test8<S8 : Test7<S8, <!UPPER_BOUND_VIOLATED!>in Any<!>>>
|
||||
class Class<V : Any>
|
||||
typealias Alias <V1> = (Class<V1>) -> Boolean
|
||||
|
||||
/* TODO: Should not be errors. Uncomment after fixing of https://youtrack.jetbrains.com/issue/KT-48044
|
||||
abstract class Base<T : Base<T>> {}
|
||||
class DerivedOut<out O : Base<out O>> {}
|
||||
class DerivedIn<in I : Base<in I>> {}*/
|
||||
class DerivedIn<in I : Base<in I>> {}
|
||||
|
||||
|
||||
|
||||
+18
@@ -13881,6 +13881,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/inference/underscoredTypeInForbiddenPositions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unsoundness1.kt")
|
||||
public void testUnsoundness1() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/unsoundness1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unsoundness2.kt")
|
||||
public void testUnsoundness2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/unsoundness2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("useFunctionLiteralsToInferType.kt")
|
||||
public void testUseFunctionLiteralsToInferType() throws Exception {
|
||||
@@ -31083,6 +31095,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/repeatedBound.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("starProjectionInsteadOutCaptured.kt")
|
||||
public void testStarProjectionInsteadOutCaptured() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/starProjectionInsteadOutCaptured.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("upperBoundCannotBeArray.kt")
|
||||
public void testUpperBoundCannotBeArray() throws Exception {
|
||||
|
||||
+18
@@ -13881,6 +13881,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/inference/underscoredTypeInForbiddenPositions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unsoundness1.kt")
|
||||
public void testUnsoundness1() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/unsoundness1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unsoundness2.kt")
|
||||
public void testUnsoundness2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/unsoundness2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("useFunctionLiteralsToInferType.kt")
|
||||
public void testUseFunctionLiteralsToInferType() throws Exception {
|
||||
@@ -31083,6 +31095,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/repeatedBound.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("starProjectionInsteadOutCaptured.kt")
|
||||
public void testStarProjectionInsteadOutCaptured() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/starProjectionInsteadOutCaptured.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("upperBoundCannotBeArray.kt")
|
||||
public void testUpperBoundCannotBeArray() throws Exception {
|
||||
|
||||
+7
-3
@@ -6,10 +6,10 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers
|
||||
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutorByMap
|
||||
@@ -70,7 +70,11 @@ private fun buildDeepSubstitutionMultimap(
|
||||
for (index in 0 until count) {
|
||||
val typeArgument = typeArguments[index]
|
||||
|
||||
val substitutedArgument = ConeSubstitutorByMap(substitution, session).substituteArgument(typeArgument) ?: typeArgument
|
||||
val substitutedArgument = ConeSubstitutorByMap(substitution, session).substituteArgument(
|
||||
typeArgument,
|
||||
classSymbol.toLookupTag(),
|
||||
index
|
||||
) ?: typeArgument
|
||||
val substitutedType = substitutedArgument.type ?: continue
|
||||
|
||||
val typeParameterSymbol = typeParameterSymbols[index]
|
||||
|
||||
+91
-17
@@ -8,16 +8,23 @@ package org.jetbrains.kotlin.fir.analysis.checkers
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.withCombinedAttributesFrom
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Recursively analyzes type parameters and reports the diagnostic on the given source calculated using typeRef
|
||||
@@ -44,23 +51,9 @@ fun checkUpperBoundViolated(
|
||||
return
|
||||
}
|
||||
|
||||
val count = minOf(typeParameterSymbols.size, type.typeArguments.size)
|
||||
val substitution = mutableMapOf<FirTypeParameterSymbol, ConeKotlinType>()
|
||||
val substitution = typeParameterSymbols.zip(type.typeArguments).toMap()
|
||||
val substitutor = FE10LikeConeSubstitutor(substitution, context.session)
|
||||
|
||||
for (index in 0 until count) {
|
||||
val typeArgument = type.typeArguments[index]
|
||||
val typeParameterSymbol = typeParameterSymbols[index]
|
||||
|
||||
val typeArgumentType = typeArgument.type
|
||||
if (typeArgumentType != null) {
|
||||
substitution[typeParameterSymbol] = typeArgumentType
|
||||
} else {
|
||||
substitution[typeParameterSymbol] =
|
||||
ConeStubTypeForTypeVariableInSubtyping(ConeTypeVariable("", typeParameterSymbol.toLookupTag()), ConeNullability.NOT_NULL)
|
||||
}
|
||||
}
|
||||
|
||||
val substitutor = substitutorByMap(substitution, context.session)
|
||||
val typeRefAndSourcesForArguments = extractArgumentsTypeRefAndSource(typeRef) ?: return
|
||||
val typeArgumentsWithSourceInfo = type.typeArguments.withIndex().map { (index, projection) ->
|
||||
val (argTypeRef, source) =
|
||||
@@ -80,6 +73,87 @@ fun checkUpperBoundViolated(
|
||||
)
|
||||
}
|
||||
|
||||
private class FE10LikeConeSubstitutor(
|
||||
private val substitution: Map<FirTypeParameterSymbol, ConeTypeProjection>,
|
||||
private val useSiteSession: FirSession
|
||||
) : AbstractConeSubstitutor(useSiteSession.typeContext) {
|
||||
override fun substituteType(type: ConeKotlinType): ConeKotlinType? {
|
||||
if (type !is ConeTypeParameterType) return null
|
||||
val projection = substitution[type.lookupTag.symbol] ?: return null
|
||||
|
||||
if (projection.isStarProjection) {
|
||||
return StandardClassIds.Any.constructClassLikeType(emptyArray(), isNullable = true).withProjection(projection)
|
||||
}
|
||||
|
||||
val result =
|
||||
projection.type!!.updateNullabilityIfNeeded(type)
|
||||
?.withCombinedAttributesFrom(type, useSiteSession.typeContext)
|
||||
?: return null
|
||||
|
||||
if (type.isUnsafeVarianceType(useSiteSession)) {
|
||||
useSiteSession.typeApproximator.approximateToSuperType(
|
||||
result, TypeApproximatorConfiguration.FinalApproximationAfterResolutionAndInference
|
||||
)?.let {
|
||||
return it.withProjection(projection)
|
||||
}
|
||||
}
|
||||
|
||||
return result.withProjection(projection)
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.withProjection(projection: ConeTypeProjection): ConeKotlinType {
|
||||
if (projection.kind == ProjectionKind.INVARIANT) return this
|
||||
return withAttributes(ConeAttributes.create(listOf(OriginalProjectionTypeAttribute(projection))), useSiteSession.typeContext)
|
||||
}
|
||||
|
||||
override fun substituteArgument(projection: ConeTypeProjection, lookupTag: ConeClassLikeLookupTag, index: Int): ConeTypeProjection? {
|
||||
val substitutedProjection = super.substituteArgument(projection, lookupTag, index) ?: return null
|
||||
if (substitutedProjection.isStarProjection) return null
|
||||
|
||||
val type = substitutedProjection.type!!
|
||||
|
||||
val projectionFromType = type.attributes.originalProjection?.data ?: type
|
||||
val projectionKindFromType = projectionFromType.kind
|
||||
|
||||
if (projectionKindFromType == ProjectionKind.STAR) return ConeStarProjection
|
||||
|
||||
if (projectionKindFromType == ProjectionKind.INVARIANT || projectionKindFromType == projection.kind) {
|
||||
return substitutedProjection
|
||||
}
|
||||
|
||||
if (projection.kind == ProjectionKind.INVARIANT) {
|
||||
return wrapProjection(projectionFromType, type)
|
||||
}
|
||||
|
||||
return ConeStarProjection
|
||||
}
|
||||
}
|
||||
|
||||
private class OriginalProjectionTypeAttribute(val data: ConeTypeProjection) : ConeAttribute<OriginalProjectionTypeAttribute>() {
|
||||
override fun union(other: OriginalProjectionTypeAttribute?): OriginalProjectionTypeAttribute? {
|
||||
return other
|
||||
}
|
||||
|
||||
override fun intersect(other: OriginalProjectionTypeAttribute?): OriginalProjectionTypeAttribute? {
|
||||
return other
|
||||
}
|
||||
|
||||
override fun add(other: OriginalProjectionTypeAttribute?): OriginalProjectionTypeAttribute? {
|
||||
return other
|
||||
}
|
||||
|
||||
override fun isSubtypeOf(other: OriginalProjectionTypeAttribute?): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun toString() = "OriginalProjectionTypeAttribute: $data"
|
||||
|
||||
override val key: KClass<out OriginalProjectionTypeAttribute>
|
||||
get() = OriginalProjectionTypeAttribute::class
|
||||
}
|
||||
|
||||
private val ConeAttributes.originalProjection: OriginalProjectionTypeAttribute? by ConeAttributes.attributeAccessor<OriginalProjectionTypeAttribute>()
|
||||
|
||||
class TypeArgumentWithSourceInfo(
|
||||
val coneTypeProjection: ConeTypeProjection,
|
||||
val typeRef: FirTypeRef?,
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeAlias
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
@@ -115,10 +116,18 @@ private fun mapTypeAliasArguments(
|
||||
return null
|
||||
}
|
||||
|
||||
override fun substituteArgument(projection: ConeTypeProjection): ConeTypeProjection? {
|
||||
override fun substituteArgument(
|
||||
projection: ConeTypeProjection,
|
||||
lookupTag: ConeClassLikeLookupTag,
|
||||
index: Int
|
||||
): ConeTypeProjection? {
|
||||
val type = (projection as? ConeKotlinTypeProjection)?.type ?: return null
|
||||
val symbol = (type as? ConeTypeParameterType)?.lookupTag?.symbol ?: return super.substituteArgument(projection)
|
||||
val mappedProjection = typeAliasMap[symbol] ?: return super.substituteArgument(projection)
|
||||
val symbol = (type as? ConeTypeParameterType)?.lookupTag?.symbol ?: return super.substituteArgument(
|
||||
projection,
|
||||
lookupTag,
|
||||
index
|
||||
)
|
||||
val mappedProjection = typeAliasMap[symbol] ?: return super.substituteArgument(projection, lookupTag, index)
|
||||
var mappedType = (mappedProjection as? ConeKotlinTypeProjection)?.type.updateNullabilityIfNeeded(type)
|
||||
mappedType = when (mappedType) {
|
||||
is ConeClassErrorType,
|
||||
|
||||
+8
-5
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve.substitution
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.resolve.withCombinedAttributesFrom
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
@@ -17,7 +18,7 @@ import org.jetbrains.kotlin.types.model.TypeVariableMarker
|
||||
import org.jetbrains.kotlin.types.model.typeConstructor
|
||||
|
||||
abstract class AbstractConeSubstitutor(protected val typeContext: ConeTypeContext) : ConeSubstitutor() {
|
||||
private fun wrapProjection(old: ConeTypeProjection, newType: ConeKotlinType): ConeTypeProjection {
|
||||
protected fun wrapProjection(old: ConeTypeProjection, newType: ConeKotlinType): ConeTypeProjection {
|
||||
return when (old) {
|
||||
is ConeStarProjection -> old
|
||||
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(newType)
|
||||
@@ -29,7 +30,7 @@ abstract class AbstractConeSubstitutor(protected val typeContext: ConeTypeContex
|
||||
}
|
||||
|
||||
abstract fun substituteType(type: ConeKotlinType): ConeKotlinType?
|
||||
open fun substituteArgument(projection: ConeTypeProjection): ConeTypeProjection? {
|
||||
open fun substituteArgument(projection: ConeTypeProjection, lookupTag: ConeClassLikeLookupTag, index: Int): ConeTypeProjection? {
|
||||
val type = (projection as? ConeKotlinTypeProjection)?.type ?: return null
|
||||
val newType = substituteOrNull(type) ?: return null
|
||||
return wrapProjection(projection, newType)
|
||||
@@ -124,8 +125,11 @@ abstract class AbstractConeSubstitutor(protected val typeContext: ConeTypeContex
|
||||
private fun ConeKotlinType.substituteArguments(): ConeKotlinType? {
|
||||
val newArguments by lazy { arrayOfNulls<ConeTypeProjection>(typeArguments.size) }
|
||||
var initialized = false
|
||||
|
||||
require(this is ConeClassLikeType) { "Unknown type to substitute: $this, ${this::class}" }
|
||||
|
||||
for ((index, typeArgument) in this.typeArguments.withIndex()) {
|
||||
newArguments[index] = substituteArgument(typeArgument)?.also {
|
||||
newArguments[index] = substituteArgument(typeArgument, lookupTag, index)?.also {
|
||||
initialized = true
|
||||
}
|
||||
}
|
||||
@@ -144,8 +148,7 @@ abstract class AbstractConeSubstitutor(protected val typeContext: ConeTypeContex
|
||||
nullability.isNullable,
|
||||
attributes
|
||||
)
|
||||
is ConeClassLikeType -> error("Unknown class-like type to substitute: $this, ${this::class}")
|
||||
else -> error("Unknown type to substitute: $this, ${this::class}")
|
||||
else -> error("Unknown class-like type to substitute: $this, ${this::class}")
|
||||
}
|
||||
}
|
||||
return null
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
// IGNORE_BACKEND: JVM
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// FIR status: UPPER_BOUND_VIOLATED at Service<out T>
|
||||
|
||||
inline fun <
|
||||
reified TService : Service<TService, TEvent>,
|
||||
@@ -25,4 +23,4 @@ class SomeService : Service<SomeService, SomeService.SomeEvent> {
|
||||
fun box(): String {
|
||||
event { someEvent: SomeService.SomeEvent -> } // REIFIED_TYPE_FORBIDDEN_SUBSTITUTION
|
||||
return "OK"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// SKIP_TXT
|
||||
// !LANGUAGE: +ProperTypeInferenceConstraintsProcessing
|
||||
|
||||
class A<T, F : T>
|
||||
fun foo(a: A<*, in CharSequence>) {}
|
||||
fun <T, U> coerce(t: T): U {
|
||||
val constrain: Constrain<U, *, in T>? = null
|
||||
val bind = Bind(constrain)
|
||||
return bind.upcast(t)
|
||||
}
|
||||
|
||||
class Constrain<A, B : A, C : B>
|
||||
|
||||
class Bind<A, B : A, C : B>(val constrain: Constrain<A, B, C>?) {
|
||||
fun upcast(c: C): A = c
|
||||
}
|
||||
|
||||
fun <T, U> coerce2(t: T): U {
|
||||
// We might report an error on unsound type reference Constrain<U, *, T>?, too
|
||||
val constrain: Constrain<U, *, T>? = null
|
||||
val bind = Bind(<!ARGUMENT_TYPE_MISMATCH!>constrain<!>) // WARNING: Type mismatch: inferred type is T but U was expected
|
||||
return bind.upcast(t)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// SKIP_TXT
|
||||
// !LANGUAGE: +ProperTypeInferenceConstraintsProcessing
|
||||
|
||||
class A<T, F : T>
|
||||
fun foo(a: A<*, in CharSequence>) {}
|
||||
fun <T, U> coerce(t: T): U {
|
||||
val constrain: Constrain<U, *, in T>? = null
|
||||
val bind = Bind(constrain)
|
||||
return bind.upcast(t)
|
||||
}
|
||||
|
||||
class Constrain<A, B : A, C : B>
|
||||
|
||||
class Bind<A, B : A, C : B>(val constrain: Constrain<A, B, C>?) {
|
||||
fun upcast(c: C): A = c
|
||||
}
|
||||
|
||||
fun <T, U> coerce2(t: T): U {
|
||||
// We might report an error on unsound type reference Constrain<U, *, T>?, too
|
||||
val constrain: Constrain<U, *, T>? = null
|
||||
val bind = Bind(<!TYPE_MISMATCH, TYPE_MISMATCH!>constrain<!>) // WARNING: Type mismatch: inferred type is T but U was expected
|
||||
return bind.upcast(t)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// FIR_IDENTICAL
|
||||
// SKIP_TXT
|
||||
// !LANGUAGE: +ProperTypeInferenceConstraintsProcessing
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val zero = coerce<Int, String>(0)
|
||||
}
|
||||
|
||||
fun <T, U> coerce(t: T): U {
|
||||
// Should be an error somewhere because this code leads to unsoundness
|
||||
// We may report that `Constrain<U, *, in T>?` type definition is unsound or the call `Bind(constrain)`
|
||||
// See KT-50230
|
||||
val constrain: Constrain<U, *, in T>? = null
|
||||
val bind = Bind(constrain)
|
||||
return bind.upcast(t)
|
||||
}
|
||||
|
||||
class Constrain<A, B : A, C : B>
|
||||
|
||||
class Bind<A, B : A, C : B>(val constrain: Constrain<A, B, C>?) {
|
||||
fun upcast(c: C): A = c
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// FIR_IDENTICAL
|
||||
// SKIP_TXT
|
||||
interface A
|
||||
interface B<X : A>
|
||||
interface C<E : A, F : B<E>>
|
||||
|
||||
fun foo1(c: C<out A, out B<*>>) {}
|
||||
|
||||
fun foo2(c: C<*, B<*>>) {}
|
||||
fun <T : B<*>> foo3(c: C<*, T>) {}
|
||||
fun <T : B<*>> foo4(c: C<out A, T>) {}
|
||||
Generated
+18
@@ -13887,6 +13887,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/underscoredTypeInForbiddenPositions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unsoundness1.kt")
|
||||
public void testUnsoundness1() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/unsoundness1.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("unsoundness2.kt")
|
||||
public void testUnsoundness2() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/unsoundness2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("useFunctionLiteralsToInferType.kt")
|
||||
public void testUseFunctionLiteralsToInferType() throws Exception {
|
||||
@@ -31173,6 +31185,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/repeatedBound.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("starProjectionInsteadOutCaptured.kt")
|
||||
public void testStarProjectionInsteadOutCaptured() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/starProjectionInsteadOutCaptured.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("upperBoundCannotBeArray.kt")
|
||||
public void testUpperBoundCannotBeArray() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user