[FIR] Add FINAL_UPPER_BOUND checker
This commit is contained in:
+5
-5
@@ -38,15 +38,15 @@ fun test(z: Int, c: Char) {}
|
|||||||
|
|
||||||
typealias BA = A
|
typealias BA = A
|
||||||
|
|
||||||
fun <T> kek(t: T) where T : (String) -> Any?, T : Char {}
|
fun <T> kek(t: T) where T : (String) -> Any?, T : <!FINAL_UPPER_BOUND!>Char<!> {}
|
||||||
fun <T> kek(t: T) where T : () -> Boolean, T : String {}
|
fun <T> kek(t: T) where T : () -> Boolean, T : <!FINAL_UPPER_BOUND!>String<!> {}
|
||||||
fun <T : Int> kek(t: T) {}
|
fun <T : <!FINAL_UPPER_BOUND!>Int<!>> kek(t: T) {}
|
||||||
|
|
||||||
fun lol(a: Array<Int>) {}
|
fun lol(a: Array<Int>) {}
|
||||||
fun lol(a: Array<Boolean>) {}
|
fun lol(a: Array<Boolean>) {}
|
||||||
|
|
||||||
<!CONFLICTING_OVERLOADS!>fun <T> mem(t: T)<!> where T : () -> Boolean, T : String {}
|
<!CONFLICTING_OVERLOADS!>fun <T> mem(t: T)<!> where T : () -> Boolean, T : <!FINAL_UPPER_BOUND!>String<!> {}
|
||||||
<!CONFLICTING_OVERLOADS!>fun <T> mem(t: T)<!> where T : String, T : () -> Boolean {}
|
<!CONFLICTING_OVERLOADS!>fun <T> mem(t: T)<!> where T : <!FINAL_UPPER_BOUND!>String<!>, T : () -> Boolean {}
|
||||||
|
|
||||||
class M {
|
class M {
|
||||||
companion <!REDECLARATION!>object<!> {}
|
companion <!REDECLARATION!>object<!> {}
|
||||||
|
|||||||
+4
-4
@@ -14,7 +14,7 @@ open class D() : B() {
|
|||||||
override var test: <!VAR_TYPE_MISMATCH_ON_OVERRIDE!>Char<!> = '\n'
|
override var test: <!VAR_TYPE_MISMATCH_ON_OVERRIDE!>Char<!> = '\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
class E<T : Double>(val value: T) : B() {
|
class E<T : <!FINAL_UPPER_BOUND!>Double<!>>(val value: T) : B() {
|
||||||
override var test: <!VAR_TYPE_MISMATCH_ON_OVERRIDE!>T<!> = value
|
override var test: <!VAR_TYPE_MISMATCH_ON_OVERRIDE!>T<!> = value
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,14 +22,14 @@ open class F<T : Number>(val value: T) {
|
|||||||
open var rest: T = value
|
open var rest: T = value
|
||||||
}
|
}
|
||||||
|
|
||||||
class G<E : Double>(val balue: E) : F<E>(balue) {
|
class G<E : <!FINAL_UPPER_BOUND!>Double<!>>(val balue: E) : F<E>(balue) {
|
||||||
override var rest: E = balue
|
override var rest: E = balue
|
||||||
}
|
}
|
||||||
|
|
||||||
class H<E : String>(val balue: E) : <!INAPPLICABLE_CANDIDATE!>F<E><!>(balue) {
|
class H<E : <!FINAL_UPPER_BOUND!>String<!>>(val balue: E) : <!INAPPLICABLE_CANDIDATE!>F<E><!>(balue) {
|
||||||
override var rest: E = balue // no report because of INAPPLICABLE_CANDIDATE
|
override var rest: E = balue // no report because of INAPPLICABLE_CANDIDATE
|
||||||
}
|
}
|
||||||
|
|
||||||
class M<E : String>(val balue: E) : F<Double>(3.14) {
|
class M<E : <!FINAL_UPPER_BOUND!>String<!>>(val balue: E) : F<Double>(3.14) {
|
||||||
override var rest: <!VAR_TYPE_MISMATCH_ON_OVERRIDE!>E<!> = balue
|
override var rest: <!VAR_TYPE_MISMATCH_ON_OVERRIDE!>E<!> = balue
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -15,7 +15,7 @@ open class D() : B() {
|
|||||||
override fun test(): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>Char<!> = '\n'
|
override fun test(): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>Char<!> = '\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
class E<T : Double>(val value: T) : B() {
|
class E<T : <!FINAL_UPPER_BOUND!>Double<!>>(val value: T) : B() {
|
||||||
override fun test(): T = value
|
override fun test(): T = value
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,15 +23,15 @@ open class F<T : Number>(val value: T) {
|
|||||||
open fun rest(): T = value
|
open fun rest(): T = value
|
||||||
}
|
}
|
||||||
|
|
||||||
class G<E : Double>(val balue: E) : F<E>(balue) {
|
class G<E : <!FINAL_UPPER_BOUND!>Double<!>>(val balue: E) : F<E>(balue) {
|
||||||
override fun rest(): E = balue
|
override fun rest(): E = balue
|
||||||
}
|
}
|
||||||
|
|
||||||
class H<E : String>(val balue: E) : <!INAPPLICABLE_CANDIDATE!>F<E><!>(balue) {
|
class H<E : <!FINAL_UPPER_BOUND!>String<!>>(val balue: E) : <!INAPPLICABLE_CANDIDATE!>F<E><!>(balue) {
|
||||||
override fun rest(): E = balue // no report because of INAPPLICABLE_CANDIDATE
|
override fun rest(): E = balue // no report because of INAPPLICABLE_CANDIDATE
|
||||||
}
|
}
|
||||||
|
|
||||||
class M<E : String>(val balue: E) : F<Double>(3.14) {
|
class M<E : <!FINAL_UPPER_BOUND!>String<!>>(val balue: E) : F<Double>(3.14) {
|
||||||
override fun rest(): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>E<!> = balue
|
override fun rest(): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>E<!> = balue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -35,6 +35,7 @@ fun main(args: Array<String>) {
|
|||||||
alias<FirRegularClass>("RegularClassChecker")
|
alias<FirRegularClass>("RegularClassChecker")
|
||||||
alias<FirConstructor>("ConstructorChecker")
|
alias<FirConstructor>("ConstructorChecker")
|
||||||
alias<FirFile>("FileChecker")
|
alias<FirFile>("FileChecker")
|
||||||
|
alias<FirTypeParameter>("FirTypeParameterChecker")
|
||||||
|
|
||||||
additional(
|
additional(
|
||||||
fieldName = "controlFlowAnalyserCheckers",
|
fieldName = "controlFlowAnalyserCheckers",
|
||||||
|
|||||||
+4
@@ -289,6 +289,10 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
|||||||
val TYPE_PARAMETER_AS_REIFIED by error<FirSourceElement, PsiElement> {
|
val TYPE_PARAMETER_AS_REIFIED by error<FirSourceElement, PsiElement> {
|
||||||
parameter<FirTypeParameterSymbol>("typeParameter")
|
parameter<FirTypeParameterSymbol>("typeParameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val FINAL_UPPER_BOUND by warning<FirSourceElement, PsiElement> {
|
||||||
|
parameter<ConeKotlinType>("type")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val REFLECTION by object : DiagnosticGroup("Reflection") {
|
val REFLECTION by object : DiagnosticGroup("Reflection") {
|
||||||
|
|||||||
+4
@@ -33,6 +33,8 @@ internal class ComposedDeclarationCheckers : DeclarationCheckers() {
|
|||||||
get() = _constructorCheckers
|
get() = _constructorCheckers
|
||||||
override val fileCheckers: Set<FirFileChecker>
|
override val fileCheckers: Set<FirFileChecker>
|
||||||
get() = _fileCheckers
|
get() = _fileCheckers
|
||||||
|
override val typeParameterCheckers: Set<FirTypeParameterChecker>
|
||||||
|
get() = _typeParameterCheckers
|
||||||
override val controlFlowAnalyserCheckers: Set<FirControlFlowChecker>
|
override val controlFlowAnalyserCheckers: Set<FirControlFlowChecker>
|
||||||
get() = _controlFlowAnalyserCheckers
|
get() = _controlFlowAnalyserCheckers
|
||||||
override val variableAssignmentCfaBasedCheckers: Set<AbstractFirPropertyInitializationChecker>
|
override val variableAssignmentCfaBasedCheckers: Set<AbstractFirPropertyInitializationChecker>
|
||||||
@@ -47,6 +49,7 @@ internal class ComposedDeclarationCheckers : DeclarationCheckers() {
|
|||||||
private val _regularClassCheckers: MutableSet<FirRegularClassChecker> = mutableSetOf()
|
private val _regularClassCheckers: MutableSet<FirRegularClassChecker> = mutableSetOf()
|
||||||
private val _constructorCheckers: MutableSet<FirConstructorChecker> = mutableSetOf()
|
private val _constructorCheckers: MutableSet<FirConstructorChecker> = mutableSetOf()
|
||||||
private val _fileCheckers: MutableSet<FirFileChecker> = mutableSetOf()
|
private val _fileCheckers: MutableSet<FirFileChecker> = mutableSetOf()
|
||||||
|
private val _typeParameterCheckers: MutableSet<FirTypeParameterChecker> = mutableSetOf()
|
||||||
private val _controlFlowAnalyserCheckers: MutableSet<FirControlFlowChecker> = mutableSetOf()
|
private val _controlFlowAnalyserCheckers: MutableSet<FirControlFlowChecker> = mutableSetOf()
|
||||||
private val _variableAssignmentCfaBasedCheckers: MutableSet<AbstractFirPropertyInitializationChecker> = mutableSetOf()
|
private val _variableAssignmentCfaBasedCheckers: MutableSet<AbstractFirPropertyInitializationChecker> = mutableSetOf()
|
||||||
|
|
||||||
@@ -61,6 +64,7 @@ internal class ComposedDeclarationCheckers : DeclarationCheckers() {
|
|||||||
_regularClassCheckers += checkers.regularClassCheckers
|
_regularClassCheckers += checkers.regularClassCheckers
|
||||||
_constructorCheckers += checkers.constructorCheckers
|
_constructorCheckers += checkers.constructorCheckers
|
||||||
_fileCheckers += checkers.fileCheckers
|
_fileCheckers += checkers.fileCheckers
|
||||||
|
_typeParameterCheckers += checkers.typeParameterCheckers
|
||||||
_controlFlowAnalyserCheckers += checkers.controlFlowAnalyserCheckers
|
_controlFlowAnalyserCheckers += checkers.controlFlowAnalyserCheckers
|
||||||
_variableAssignmentCfaBasedCheckers += checkers.variableAssignmentCfaBasedCheckers
|
_variableAssignmentCfaBasedCheckers += checkers.variableAssignmentCfaBasedCheckers
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -28,6 +28,7 @@ abstract class DeclarationCheckers {
|
|||||||
open val regularClassCheckers: Set<FirRegularClassChecker> = emptySet()
|
open val regularClassCheckers: Set<FirRegularClassChecker> = emptySet()
|
||||||
open val constructorCheckers: Set<FirConstructorChecker> = emptySet()
|
open val constructorCheckers: Set<FirConstructorChecker> = emptySet()
|
||||||
open val fileCheckers: Set<FirFileChecker> = emptySet()
|
open val fileCheckers: Set<FirFileChecker> = emptySet()
|
||||||
|
open val typeParameterCheckers: Set<FirTypeParameterChecker> = emptySet()
|
||||||
|
|
||||||
open val controlFlowAnalyserCheckers: Set<FirControlFlowChecker> = emptySet()
|
open val controlFlowAnalyserCheckers: Set<FirControlFlowChecker> = emptySet()
|
||||||
open val variableAssignmentCfaBasedCheckers: Set<AbstractFirPropertyInitializationChecker> = emptySet()
|
open val variableAssignmentCfaBasedCheckers: Set<AbstractFirPropertyInitializationChecker> = emptySet()
|
||||||
@@ -41,4 +42,5 @@ abstract class DeclarationCheckers {
|
|||||||
@CheckersComponentInternal internal val allRegularClassCheckers: Set<FirRegularClassChecker> get() = regularClassCheckers + memberDeclarationCheckers + basicDeclarationCheckers + classCheckers
|
@CheckersComponentInternal internal val allRegularClassCheckers: Set<FirRegularClassChecker> get() = regularClassCheckers + memberDeclarationCheckers + basicDeclarationCheckers + classCheckers
|
||||||
@CheckersComponentInternal internal val allConstructorCheckers: Set<FirConstructorChecker> get() = constructorCheckers + functionCheckers + basicDeclarationCheckers + memberDeclarationCheckers
|
@CheckersComponentInternal internal val allConstructorCheckers: Set<FirConstructorChecker> get() = constructorCheckers + functionCheckers + basicDeclarationCheckers + memberDeclarationCheckers
|
||||||
@CheckersComponentInternal internal val allFileCheckers: Set<FirFileChecker> get() = fileCheckers + basicDeclarationCheckers
|
@CheckersComponentInternal internal val allFileCheckers: Set<FirFileChecker> get() = fileCheckers + basicDeclarationCheckers
|
||||||
|
@CheckersComponentInternal internal val allTypeParameterCheckers: Set<FirTypeParameterChecker> get() = typeParameterCheckers + basicDeclarationCheckers
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
|
||||||
|
|
||||||
typealias FirBasicDeclarationChecker = FirDeclarationChecker<FirDeclaration>
|
typealias FirBasicDeclarationChecker = FirDeclarationChecker<FirDeclaration>
|
||||||
typealias FirMemberDeclarationChecker = FirDeclarationChecker<FirMemberDeclaration>
|
typealias FirMemberDeclarationChecker = FirDeclarationChecker<FirMemberDeclaration>
|
||||||
@@ -29,3 +30,4 @@ typealias FirClassChecker = FirDeclarationChecker<FirClass<*>>
|
|||||||
typealias FirRegularClassChecker = FirDeclarationChecker<FirRegularClass>
|
typealias FirRegularClassChecker = FirDeclarationChecker<FirRegularClass>
|
||||||
typealias FirConstructorChecker = FirDeclarationChecker<FirConstructor>
|
typealias FirConstructorChecker = FirDeclarationChecker<FirConstructor>
|
||||||
typealias FirFileChecker = FirDeclarationChecker<FirFile>
|
typealias FirFileChecker = FirDeclarationChecker<FirFile>
|
||||||
|
typealias FirTypeParameterChecker = FirDeclarationChecker<FirTypeParameter>
|
||||||
|
|||||||
@@ -214,6 +214,7 @@ object FirErrors {
|
|||||||
val INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS by error0<FirSourceElement, KtClassOrObject>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
val INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS by error0<FirSourceElement, KtClassOrObject>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||||
val KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE by error1<FirSourceElement, KtNamedDeclaration, FirTypeParameterSymbol>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
val KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE by error1<FirSourceElement, KtNamedDeclaration, FirTypeParameterSymbol>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||||
val TYPE_PARAMETER_AS_REIFIED by error1<FirSourceElement, PsiElement, FirTypeParameterSymbol>()
|
val TYPE_PARAMETER_AS_REIFIED by error1<FirSourceElement, PsiElement, FirTypeParameterSymbol>()
|
||||||
|
val FINAL_UPPER_BOUND by warning1<FirSourceElement, PsiElement, ConeKotlinType>()
|
||||||
|
|
||||||
// Reflection
|
// Reflection
|
||||||
val EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED by error1<FirSourceElement, KtExpression, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
val EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED by error1<FirSourceElement, KtExpression, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||||
|
|||||||
+1
-3
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.fir.BuiltinTypes
|
|||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
|
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.isSupertypeOf
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription
|
import org.jetbrains.kotlin.fir.contracts.FirResolvedContractDescription
|
||||||
@@ -199,9 +200,6 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
|
|||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KotlinTypeMarker.isSupertypeOf(context: TypeCheckerProviderContext, type: KotlinTypeMarker?) =
|
|
||||||
type != null && AbstractTypeChecker.isSubtypeOf(context, type, this)
|
|
||||||
|
|
||||||
private fun simpleTypeStatement(realVar: RealVariable, exactType: Boolean, type: ConeKotlinType): MutableTypeStatement {
|
private fun simpleTypeStatement(realVar: RealVariable, exactType: Boolean, type: ConeKotlinType): MutableTypeStatement {
|
||||||
return MutableTypeStatement(
|
return MutableTypeStatement(
|
||||||
realVar,
|
realVar,
|
||||||
|
|||||||
@@ -5,13 +5,11 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.analysis.checkers
|
package org.jetbrains.kotlin.fir.analysis.checkers
|
||||||
|
|
||||||
import org.jetbrains.kotlin.KtNodeTypes
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
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.fir.*
|
import org.jetbrains.kotlin.fir.*
|
||||||
import org.jetbrains.kotlin.fir.analysis.cfa.FirReturnsImpliesAnalyzer.isSupertypeOf
|
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.modalityModifier
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.modalityModifier
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.overrideModifier
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.overrideModifier
|
||||||
@@ -30,16 +28,16 @@ import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions
|
|||||||
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
|
||||||
import org.jetbrains.kotlin.fir.types.coneType
|
|
||||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.KtModifierList
|
import org.jetbrains.kotlin.psi.KtModifierList
|
||||||
import org.jetbrains.kotlin.psi.KtParameter
|
|
||||||
import org.jetbrains.kotlin.psi.KtParameter.VAL_VAR_TOKEN_SET
|
import org.jetbrains.kotlin.psi.KtParameter.VAL_VAR_TOKEN_SET
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType
|
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType
|
||||||
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||||
|
import org.jetbrains.kotlin.types.model.TypeCheckerProviderContext
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
internal fun FirClass<*>.unsubstitutedScope(context: CheckerContext) =
|
internal fun FirClass<*>.unsubstitutedScope(context: CheckerContext) =
|
||||||
@@ -321,3 +319,81 @@ val FirValueParameter.hasValOrVar: Boolean
|
|||||||
val source = this.source ?: return false
|
val source = this.source ?: return false
|
||||||
return source.getChild(VAL_VAR_TOKEN_SET) != null
|
return source.getChild(VAL_VAR_TOKEN_SET) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun KotlinTypeMarker.isSupertypeOf(context: TypeCheckerProviderContext, type: KotlinTypeMarker?) =
|
||||||
|
type != null && AbstractTypeChecker.isSubtypeOf(context, type, this)
|
||||||
|
|
||||||
|
fun KotlinTypeMarker.isSubtypeOf(context: TypeCheckerProviderContext, type: KotlinTypeMarker?) =
|
||||||
|
type != null && AbstractTypeChecker.isSubtypeOf(context, this, type)
|
||||||
|
|
||||||
|
fun ConeKotlinType.canHaveSubtypes(session: FirSession): Boolean {
|
||||||
|
if (this.isMarkedNullable) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
val clazz = toRegularClass(session) ?: return true
|
||||||
|
if (clazz.isEnumClass || clazz.isExpect || clazz.modality != Modality.FINAL) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
clazz.typeParameters.forEachIndexed { idx, typeParameterRef ->
|
||||||
|
val typeParameter = typeParameterRef.symbol.fir
|
||||||
|
val typeProjection = typeArguments[idx]
|
||||||
|
|
||||||
|
if (typeProjection.isStarProjection) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
val argument = typeProjection.type!! //safe because it is not a star
|
||||||
|
|
||||||
|
when (typeParameter.variance) {
|
||||||
|
Variance.INVARIANT ->
|
||||||
|
when (typeProjection.kind) {
|
||||||
|
ProjectionKind.INVARIANT ->
|
||||||
|
if (lowerThanBound(session.typeContext, argument, typeParameter) || argument.canHaveSubtypes(session)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
ProjectionKind.IN ->
|
||||||
|
if (lowerThanBound(session.typeContext, argument, typeParameter)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
ProjectionKind.OUT ->
|
||||||
|
if (argument.canHaveSubtypes(session)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
ProjectionKind.STAR ->
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
Variance.IN_VARIANCE ->
|
||||||
|
if (typeProjection.kind != ProjectionKind.OUT) {
|
||||||
|
if (lowerThanBound(session.typeContext, argument, typeParameter)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (argument.canHaveSubtypes(session)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Variance.OUT_VARIANCE ->
|
||||||
|
if (typeProjection.kind != ProjectionKind.IN) {
|
||||||
|
if (argument.canHaveSubtypes(session)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (lowerThanBound(session.typeContext, argument, typeParameter)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun lowerThanBound(context: ConeInferenceContext, argument: ConeKotlinType, typeParameter: FirTypeParameter): Boolean {
|
||||||
|
typeParameter.bounds.forEach { boundTypeRef ->
|
||||||
|
if (argument != boundTypeRef.coneType && argument.isSubtypeOf(context, boundTypeRef.coneType)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.canHaveSubtypes
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.coneType
|
||||||
|
|
||||||
|
object FirTypeParameterBoundsChecker : FirTypeParameterChecker() {
|
||||||
|
|
||||||
|
override fun check(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
val containingDeclaration = context.containingDeclarations.lastOrNull()
|
||||||
|
if (containingDeclaration is FirConstructor) return
|
||||||
|
if (containingDeclaration is FirSimpleFunction && containingDeclaration.isOverride) return
|
||||||
|
if (containingDeclaration is FirProperty && containingDeclaration.isOverride) return
|
||||||
|
|
||||||
|
declaration.symbol.fir.bounds.forEach { bound ->
|
||||||
|
if (!bound.coneType.canHaveSubtypes(context.session)) {
|
||||||
|
reporter.reportOn(bound.source, FirErrors.FINAL_UPPER_BOUND, bound.coneType, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -61,7 +61,7 @@ class DeclarationCheckersDiagnosticComponent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitTypeParameter(typeParameter: FirTypeParameter, data: CheckerContext) {
|
override fun visitTypeParameter(typeParameter: FirTypeParameter, data: CheckerContext) {
|
||||||
checkers.allBasicDeclarationCheckers.check(typeParameter, data, reporter)
|
checkers.allTypeParameterCheckers.check(typeParameter, data, reporter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitEnumEntry(enumEntry: FirEnumEntry, data: CheckerContext) {
|
override fun visitEnumEntry(enumEntry: FirEnumEntry, data: CheckerContext) {
|
||||||
|
|||||||
+6
@@ -91,6 +91,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPRESSION_OF_NUL
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXTENSION_PROPERTY_WITH_BACKING_FIELD
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXTENSION_PROPERTY_WITH_BACKING_FIELD
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FINAL_UPPER_BOUND
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FORBIDDEN_VARARG_PARAMETER_TYPE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FORBIDDEN_VARARG_PARAMETER_TYPE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUNCTION_DECLARATION_WITH_NO_NAME
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.FUNCTION_DECLARATION_WITH_NO_NAME
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.GENERIC_THROWABLE_SUBCLASS
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.GENERIC_THROWABLE_SUBCLASS
|
||||||
@@ -438,6 +439,11 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
|||||||
)
|
)
|
||||||
|
|
||||||
map.put(TYPE_PARAMETER_AS_REIFIED, "Cannot use ''{0}'' as reified type parameter. Use a class instead", SYMBOL)
|
map.put(TYPE_PARAMETER_AS_REIFIED, "Cannot use ''{0}'' as reified type parameter. Use a class instead", SYMBOL)
|
||||||
|
map.put(
|
||||||
|
FINAL_UPPER_BOUND,
|
||||||
|
"''{0}'' is a final type, and thus a value of the type parameter is predetermined",
|
||||||
|
RENDER_TYPE
|
||||||
|
)
|
||||||
|
|
||||||
// Reflection
|
// Reflection
|
||||||
map.put(
|
map.put(
|
||||||
|
|||||||
+4
@@ -87,4 +87,8 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
|||||||
override val variableAssignmentCfaBasedCheckers: Set<AbstractFirPropertyInitializationChecker> = setOf(
|
override val variableAssignmentCfaBasedCheckers: Set<AbstractFirPropertyInitializationChecker> = setOf(
|
||||||
FirPropertyInitializationAnalyzer,
|
FirPropertyInitializationAnalyzer,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override val typeParameterCheckers: Set<FirTypeParameterChecker> = setOf(
|
||||||
|
FirTypeParameterBoundsChecker,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -40,4 +40,4 @@ fun test() {
|
|||||||
|
|
||||||
fun <T : Any> foo() {}
|
fun <T : Any> foo() {}
|
||||||
fun <T : Int?> bar() {}
|
fun <T : Int?> bar() {}
|
||||||
fun <T : Int> Int.buzz() : Unit {}
|
fun <T : <!FINAL_UPPER_BOUND!>Int<!>> Int.buzz() : Unit {}
|
||||||
|
|||||||
@@ -43,12 +43,12 @@ fun test() {
|
|||||||
|
|
||||||
class Foo() {}
|
class Foo() {}
|
||||||
|
|
||||||
class Bar<T : Foo>
|
class Bar<T : <!FINAL_UPPER_BOUND!>Foo<!>>
|
||||||
|
|
||||||
class Buzz<T> where T : Bar<Int>, T : <!UNRESOLVED_REFERENCE!>nioho<!>
|
class Buzz<T> where T : <!FINAL_UPPER_BOUND!>Bar<Int><!>, T : <!UNRESOLVED_REFERENCE!>nioho<!>
|
||||||
|
|
||||||
class X<T : Foo>
|
class X<T : <!FINAL_UPPER_BOUND!>Foo<!>>
|
||||||
class Y<T> where T : Foo, T : Bar<Foo>
|
class Y<T> where T : <!FINAL_UPPER_BOUND!>Foo<!>, T : <!FINAL_UPPER_BOUND!>Bar<Foo><!>
|
||||||
|
|
||||||
fun <T> test2(t : T)
|
fun <T> test2(t : T)
|
||||||
where
|
where
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ fun <T> takeFun(f: (T) -> Unit) {}
|
|||||||
fun <T, R> callFun(f: (T) -> R): R = TODO()
|
fun <T, R> callFun(f: (T) -> R): R = TODO()
|
||||||
|
|
||||||
fun <T> foo(s: T) {}
|
fun <T> foo(s: T) {}
|
||||||
fun <T : Int> fooInt(s: T) {}
|
fun <T : <!FINAL_UPPER_BOUND!>Int<!>> fooInt(s: T) {}
|
||||||
|
|
||||||
open class Wrapper<T>(val value: T)
|
open class Wrapper<T>(val value: T)
|
||||||
fun <T, R : Wrapper<in T>> createWrapper(s: T): R = TODO()
|
fun <T, R : Wrapper<in T>> createWrapper(s: T): R = TODO()
|
||||||
|
|||||||
-97
@@ -1,97 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
|
||||||
// SKIP_TXT
|
|
||||||
// Issues: KT-25105
|
|
||||||
|
|
||||||
class Message1
|
|
||||||
class Task<T>
|
|
||||||
object Message2
|
|
||||||
enum class Message3
|
|
||||||
data class Message4(val x: Int)
|
|
||||||
|
|
||||||
sealed class Message5<T> {
|
|
||||||
open fun <A : T> execute() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Manager<T> {
|
|
||||||
fun <A : T> execute1(task: Task<A>) {}
|
|
||||||
fun <T : Int> execute2(task: T) {}
|
|
||||||
fun <T : Message2> execute3() {}
|
|
||||||
fun <A : T> execute4() {}
|
|
||||||
fun <A : T> execute5() {}
|
|
||||||
val <A : T> A.x get() = 10
|
|
||||||
var <A : T> A.y
|
|
||||||
get() = 10
|
|
||||||
set(value) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
object MessageManager1 : Manager<Message1> {
|
|
||||||
override fun <T : Message1> execute1(task: Task<T>) {}
|
|
||||||
override fun <T : Int> execute2(task: T) {}
|
|
||||||
override fun <T : Message2> execute3() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
object MessageManager2 : Manager<Message3> {
|
|
||||||
override fun <T : Message3> execute4() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
object MessageManager3 : Manager<Message4> {
|
|
||||||
override fun <T : Message4> execute5() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MessageManager4 : Manager<Message1> {
|
|
||||||
override fun <T : Message1> execute1(task: Task<T>) {}
|
|
||||||
override fun <T : Int> execute2(task: T) {}
|
|
||||||
override fun <T : Message2> execute3() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MessageManager5 : Manager<Message3> {
|
|
||||||
override fun <T : Message3> execute4() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MessageManager6 : Manager<Message4> {
|
|
||||||
override fun <T : Message4> execute5() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MessageManager7 : Manager<Message4> {
|
|
||||||
override fun <T : Message4> execute5() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MessageManager8 : Manager<Message1> {
|
|
||||||
override fun <T : Message1> execute1(task: Task<T>) {}
|
|
||||||
override fun <T : Int> execute2(task: T) {}
|
|
||||||
override fun <T : Message2> execute3() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MessageManager9 : Manager<Message3> {
|
|
||||||
override fun <T : Message3> execute4() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
object MessageManager10 : Message5<Int>() {
|
|
||||||
override fun <T : Int> execute() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MessageManager11<A> : Message5<Message5<A>>() {
|
|
||||||
override fun <T : Message5<A>> execute() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class MessageManager12(val x: Int) : Message5<Message2>() {
|
|
||||||
override fun <T : Message2> execute() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class MessageManager13<A> : Message5<A>() {
|
|
||||||
override fun <T : A> execute() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MessageManager14 : Manager<Message2> {
|
|
||||||
override val <T : Message2> T.x get() = 10
|
|
||||||
override var <T : Message2> T.y
|
|
||||||
get() = 10
|
|
||||||
set(value) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
object MessageManager15 : Manager<Int> {
|
|
||||||
override val <T : Int> T.x get() = 10
|
|
||||||
override var <T : Int> T.y
|
|
||||||
get() = 10
|
|
||||||
set(value) {}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
// SKIP_TXT
|
// SKIP_TXT
|
||||||
// Issues: KT-25105
|
// Issues: KT-25105
|
||||||
|
|||||||
+18
-18
@@ -10,9 +10,9 @@ data class Message4(val x: Int)
|
|||||||
interface Manager<T> {}
|
interface Manager<T> {}
|
||||||
|
|
||||||
object MessageManager1 : Manager<Message1> {
|
object MessageManager1 : Manager<Message1> {
|
||||||
fun <T : Message1> execute1(task: Task<T>) {}
|
fun <T : <!FINAL_UPPER_BOUND!>Message1<!>> execute1(task: Task<T>) {}
|
||||||
fun <T : Int> execute2(task: T) {}
|
fun <T : <!FINAL_UPPER_BOUND!>Int<!>> execute2(task: T) {}
|
||||||
fun <T : Message2> execute3() {}
|
fun <T : <!FINAL_UPPER_BOUND!>Message2<!>> execute3() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
object MessageManager2 : Manager<Message3> {
|
object MessageManager2 : Manager<Message3> {
|
||||||
@@ -20,13 +20,13 @@ object MessageManager2 : Manager<Message3> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object MessageManager3 : Manager<Message4> {
|
object MessageManager3 : Manager<Message4> {
|
||||||
fun <T : Message4> execute5() {}
|
fun <T : <!FINAL_UPPER_BOUND!>Message4<!>> execute5() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MessageManager4 : Manager<Message1> {
|
class MessageManager4 : Manager<Message1> {
|
||||||
fun <T : Message1> execute1(task: Task<T>) {}
|
fun <T : <!FINAL_UPPER_BOUND!>Message1<!>> execute1(task: Task<T>) {}
|
||||||
fun <T : Int> execute2(task: T) {}
|
fun <T : <!FINAL_UPPER_BOUND!>Int<!>> execute2(task: T) {}
|
||||||
fun <T : Message2> execute3() {}
|
fun <T : <!FINAL_UPPER_BOUND!>Message2<!>> execute3() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MessageManager5 : Manager<Message3> {
|
class MessageManager5 : Manager<Message3> {
|
||||||
@@ -34,17 +34,17 @@ class MessageManager5 : Manager<Message3> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MessageManager6 : Manager<Message4> {
|
class MessageManager6 : Manager<Message4> {
|
||||||
fun <T : Message4> execute5() {}
|
fun <T : <!FINAL_UPPER_BOUND!>Message4<!>> execute5() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MessageManager7 : Manager<Message4> {
|
interface MessageManager7 : Manager<Message4> {
|
||||||
fun <T : Message4> execute5() {}
|
fun <T : <!FINAL_UPPER_BOUND!>Message4<!>> execute5() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MessageManager8 : Manager<Message1> {
|
interface MessageManager8 : Manager<Message1> {
|
||||||
fun <T : Message1> execute1(task: Task<T>) {}
|
fun <T : <!FINAL_UPPER_BOUND!>Message1<!>> execute1(task: Task<T>) {}
|
||||||
fun <T : Int> execute2(task: T) {}
|
fun <T : <!FINAL_UPPER_BOUND!>Int<!>> execute2(task: T) {}
|
||||||
fun <T : Message2> execute3() {}
|
fun <T : <!FINAL_UPPER_BOUND!>Message2<!>> execute3() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MessageManager9 : Manager<Message3> {
|
interface MessageManager9 : Manager<Message3> {
|
||||||
@@ -52,7 +52,7 @@ interface MessageManager9 : Manager<Message3> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object MessageManager10 : <!UNRESOLVED_REFERENCE!>Message5<Int><!>() {
|
object MessageManager10 : <!UNRESOLVED_REFERENCE!>Message5<Int><!>() {
|
||||||
fun <T : Int> execute() {}
|
fun <T : <!FINAL_UPPER_BOUND!>Int<!>> execute() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MessageManager11<A> : <!UNRESOLVED_REFERENCE!>Message5<<!UNRESOLVED_REFERENCE!>Message5<A><!>><!>() {
|
class MessageManager11<A> : <!UNRESOLVED_REFERENCE!>Message5<<!UNRESOLVED_REFERENCE!>Message5<A><!>><!>() {
|
||||||
@@ -60,7 +60,7 @@ class MessageManager11<A> : <!UNRESOLVED_REFERENCE!>Message5<<!UNRESOLVED_REFERE
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class MessageManager12(val x: Int) : <!UNRESOLVED_REFERENCE!>Message5<Message2><!>() {
|
data class MessageManager12(val x: Int) : <!UNRESOLVED_REFERENCE!>Message5<Message2><!>() {
|
||||||
fun <T : Message2> execute() {}
|
fun <T : <!FINAL_UPPER_BOUND!>Message2<!>> execute() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class MessageManager13<A> : <!UNRESOLVED_REFERENCE!>Message5<A><!>() {
|
sealed class MessageManager13<A> : <!UNRESOLVED_REFERENCE!>Message5<A><!>() {
|
||||||
@@ -68,15 +68,15 @@ sealed class MessageManager13<A> : <!UNRESOLVED_REFERENCE!>Message5<A><!>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MessageManager14 : Manager<Message2> {
|
class MessageManager14 : Manager<Message2> {
|
||||||
val <T : Message2> T.x get() = 10
|
val <T : <!FINAL_UPPER_BOUND!>Message2<!>> T.x get() = 10
|
||||||
var <T : Message2> T.y
|
var <T : <!FINAL_UPPER_BOUND!>Message2<!>> T.y
|
||||||
get() = 10
|
get() = 10
|
||||||
set(value) {}
|
set(value) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
object MessageManager15 : Manager<Int> {
|
object MessageManager15 : Manager<Int> {
|
||||||
val <T : Int> T.x get() = 10
|
val <T : <!FINAL_UPPER_BOUND!>Int<!>> T.x get() = 10
|
||||||
var <T : Int> T.y
|
var <T : <!FINAL_UPPER_BOUND!>Int<!>> T.y
|
||||||
get() = 10
|
get() = 10
|
||||||
set(value) {}
|
set(value) {}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -53,7 +53,7 @@ fun testCaptured(cSub: SubInv<out Number>, cInv: Inv<out Number>) {
|
|||||||
|
|
||||||
fun testVariableWithBound() {
|
fun testVariableWithBound() {
|
||||||
fun <K : Number> createWithNumberBound(): Inv<K> = TODO()
|
fun <K : Number> createWithNumberBound(): Inv<K> = TODO()
|
||||||
fun <K : Int> createWithIntBound(): Inv<K> = TODO()
|
fun <K : <!FINAL_UPPER_BOUND!>Int<!>> createWithIntBound(): Inv<K> = TODO()
|
||||||
|
|
||||||
val c1 = select(SubInv<Int>(), createWithNumberBound())
|
val c1 = select(SubInv<Int>(), createWithNumberBound())
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -15,4 +15,4 @@ enum class E1
|
|||||||
class A5<T> where T : C1, T : E1
|
class A5<T> where T : C1, T : E1
|
||||||
|
|
||||||
object O1
|
object O1
|
||||||
class A6<T> where T : O1, T : C2
|
class A6<T> where T : <!FINAL_UPPER_BOUND!>O1<!>, T : C2
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@ fun <A : Array<Any>> f1() {}
|
|||||||
fun <T, A : Array<out T>> f2() {}
|
fun <T, A : Array<out T>> f2() {}
|
||||||
fun <S, T : S, A> f3() where A : Array<out S>, A : Array<out T> {}
|
fun <S, T : S, A> f3() where A : Array<out S>, A : Array<out T> {}
|
||||||
|
|
||||||
fun <T : IntArray> f4() {}
|
fun <T : <!FINAL_UPPER_BOUND!>IntArray<!>> f4() {}
|
||||||
|
|
||||||
fun <T> f5() where T : Array<Any> {}
|
fun <T> f5() where T : Array<Any> {}
|
||||||
|
|
||||||
|
|||||||
Vendored
+5
-5
@@ -110,15 +110,15 @@ fun <T : Number> T.case_19_4(): Boolean? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TESTCASE NUMBER: 20
|
// TESTCASE NUMBER: 20
|
||||||
fun <T : String> T?.case_20_1(): Boolean {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_20_1(): Boolean {
|
||||||
contract { returns(true) implies (this@case_20_1 != null) }
|
contract { returns(true) implies (this@case_20_1 != null) }
|
||||||
return this@case_20_1 != null
|
return this@case_20_1 != null
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_20_2(): Boolean {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_20_2(): Boolean {
|
||||||
contract { returns(true) implies (this@case_20_2 == null) }
|
contract { returns(true) implies (this@case_20_2 == null) }
|
||||||
return this@case_20_2 == null
|
return this@case_20_2 == null
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_20_3(): Boolean {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_20_3(): Boolean {
|
||||||
contract { returns(false) implies (this@case_20_3 != null) }
|
contract { returns(false) implies (this@case_20_3 != null) }
|
||||||
return !(this@case_20_3 != null)
|
return !(this@case_20_3 != null)
|
||||||
}
|
}
|
||||||
@@ -132,11 +132,11 @@ fun <T : String?> T.case_21_2(): Boolean {
|
|||||||
contract { returns(true) implies (this@case_21_2 == null) }
|
contract { returns(true) implies (this@case_21_2 == null) }
|
||||||
return this@case_21_2 == null
|
return this@case_21_2 == null
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_21_5(): Boolean? {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_21_5(): Boolean? {
|
||||||
contract { returnsNotNull() implies (this@case_21_5 != null) }
|
contract { returnsNotNull() implies (this@case_21_5 != null) }
|
||||||
return if (this@case_21_5 != null) true else null
|
return if (this@case_21_5 != null) true else null
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_21_7(): Boolean? {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_21_7(): Boolean? {
|
||||||
contract { returns(null) implies (this@case_21_7 != null) }
|
contract { returns(null) implies (this@case_21_7 != null) }
|
||||||
return if (this@case_21_7 != null) null else true
|
return if (this@case_21_7 != null) null else true
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+6
-6
@@ -20,11 +20,11 @@ fun <T : Number> T.case_2() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TESTCASE NUMBER: 3
|
// TESTCASE NUMBER: 3
|
||||||
fun <T : String> T?.case_3_1() {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_3_1() {
|
||||||
contract { returns() implies (this@case_3_1 == null) }
|
contract { returns() implies (this@case_3_1 == null) }
|
||||||
if (!(this@case_3_1 == null)) throw Exception()
|
if (!(this@case_3_1 == null)) throw Exception()
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_3_2() {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_3_2() {
|
||||||
contract { returns() implies (this@case_3_2 != null) }
|
contract { returns() implies (this@case_3_2 != null) }
|
||||||
if (!(this@case_3_2 != null)) throw Exception()
|
if (!(this@case_3_2 != null)) throw Exception()
|
||||||
}
|
}
|
||||||
@@ -76,19 +76,19 @@ fun <T : Number> T.case_6_4(): Boolean? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TESTCASE NUMBER: 7
|
// TESTCASE NUMBER: 7
|
||||||
fun <T : String> T?.case_7_1(): Boolean {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_7_1(): Boolean {
|
||||||
contract { returns(true) implies (this@case_7_1 == null) }
|
contract { returns(true) implies (this@case_7_1 == null) }
|
||||||
return this@case_7_1 == null
|
return this@case_7_1 == null
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_7_2(): Boolean {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_7_2(): Boolean {
|
||||||
contract { returns(false) implies (this@case_7_2 != null) }
|
contract { returns(false) implies (this@case_7_2 != null) }
|
||||||
return !(this@case_7_2 != null)
|
return !(this@case_7_2 != null)
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_7_3(): Boolean? {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_7_3(): Boolean? {
|
||||||
contract { returnsNotNull() implies (this@case_7_3 != null) }
|
contract { returnsNotNull() implies (this@case_7_3 != null) }
|
||||||
return if (this@case_7_3 != null) true else null
|
return if (this@case_7_3 != null) true else null
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_7_4(): Boolean? {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_7_4(): Boolean? {
|
||||||
contract { returns(null) implies (this@case_7_4 != null) }
|
contract { returns(null) implies (this@case_7_4 != null) }
|
||||||
return if (this@case_7_4 != null) null else true
|
return if (this@case_7_4 != null) null else true
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+13
-13
@@ -20,11 +20,11 @@ fun <T : Number> T.case_2() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TESTCASE NUMBER: 3
|
// TESTCASE NUMBER: 3
|
||||||
fun <T : String> T?.case_3_1() {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_3_1() {
|
||||||
contract { returns() implies (this@case_3_1 != null) }
|
contract { returns() implies (this@case_3_1 != null) }
|
||||||
if (!(this@case_3_1 != null)) throw Exception()
|
if (!(this@case_3_1 != null)) throw Exception()
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_3_2() {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_3_2() {
|
||||||
contract { returns() implies (this@case_3_2 == null) }
|
contract { returns() implies (this@case_3_2 == null) }
|
||||||
if (!(this@case_3_2 == null)) throw Exception()
|
if (!(this@case_3_2 == null)) throw Exception()
|
||||||
}
|
}
|
||||||
@@ -76,47 +76,47 @@ fun <T : Number> T.case_6_4(): Boolean? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TESTCASE NUMBER: 7
|
// TESTCASE NUMBER: 7
|
||||||
fun <T : String> T?.case_7_1(): Boolean {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_7_1(): Boolean {
|
||||||
contract { returns(true) implies (this@case_7_1 != null) }
|
contract { returns(true) implies (this@case_7_1 != null) }
|
||||||
return this@case_7_1 != null
|
return this@case_7_1 != null
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_7_2(): Boolean {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_7_2(): Boolean {
|
||||||
contract { returns(true) implies (this@case_7_2 == null) }
|
contract { returns(true) implies (this@case_7_2 == null) }
|
||||||
return this@case_7_2 == null
|
return this@case_7_2 == null
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_7_3(): Boolean? {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_7_3(): Boolean? {
|
||||||
contract { returnsNotNull() implies (this@case_7_3 == null) }
|
contract { returnsNotNull() implies (this@case_7_3 == null) }
|
||||||
return if (this@case_7_3 == null) true else null
|
return if (this@case_7_3 == null) true else null
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_7_4(): Boolean? {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_7_4(): Boolean? {
|
||||||
contract { returns(null) implies (this@case_7_4 == null) }
|
contract { returns(null) implies (this@case_7_4 == null) }
|
||||||
return if (this@case_7_4 == null) null else true
|
return if (this@case_7_4 == null) null else true
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_7_5(): Boolean {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_7_5(): Boolean {
|
||||||
contract { returns(false) implies (this@case_7_5 == null) }
|
contract { returns(false) implies (this@case_7_5 == null) }
|
||||||
return !(this@case_7_5 == null)
|
return !(this@case_7_5 == null)
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_7_6(): Boolean? {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_7_6(): Boolean? {
|
||||||
contract { returnsNotNull() implies (this@case_7_6 != null) }
|
contract { returnsNotNull() implies (this@case_7_6 != null) }
|
||||||
return if (this@case_7_6 != null) true else null
|
return if (this@case_7_6 != null) true else null
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_7_7(): Boolean? {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_7_7(): Boolean? {
|
||||||
contract { returns(null) implies (this@case_7_7 != null) }
|
contract { returns(null) implies (this@case_7_7 != null) }
|
||||||
return if (this@case_7_7 != null) null else true
|
return if (this@case_7_7 != null) null else true
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_7_8(): Boolean {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_7_8(): Boolean {
|
||||||
contract { returns(false) implies (this@case_7_8 != null) }
|
contract { returns(false) implies (this@case_7_8 != null) }
|
||||||
return !(this@case_7_8 != null)
|
return !(this@case_7_8 != null)
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_7_9(): Boolean {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_7_9(): Boolean {
|
||||||
contract { returns(false) implies (this@case_7_9 == null) }
|
contract { returns(false) implies (this@case_7_9 == null) }
|
||||||
return !(this@case_7_9 == null)
|
return !(this@case_7_9 == null)
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_7_10(): Boolean? {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_7_10(): Boolean? {
|
||||||
contract { returnsNotNull() implies (this@case_7_10 == null) }
|
contract { returnsNotNull() implies (this@case_7_10 == null) }
|
||||||
return if (this@case_7_10 == null) true else null
|
return if (this@case_7_10 == null) true else null
|
||||||
}
|
}
|
||||||
fun <T : String> T?.case_7_11(): Boolean? {
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_7_11(): Boolean? {
|
||||||
contract { returns(null) implies (this@case_7_11 == null) }
|
contract { returns(null) implies (this@case_7_11 == null) }
|
||||||
return if (this@case_7_11 == null) null else true
|
return if (this@case_7_11 == null) null else true
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
import kotlin.contracts.*
|
import kotlin.contracts.*
|
||||||
|
|
||||||
// TESTCASE NUMBER: 1
|
// TESTCASE NUMBER: 1
|
||||||
fun <T : Boolean>T.case_1(): Boolean? {
|
fun <T : <!FINAL_UPPER_BOUND!>Boolean<!>>T.case_1(): Boolean? {
|
||||||
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns(null) implies (!this@case_1)<!> }
|
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns(null) implies (!this@case_1)<!> }
|
||||||
return if (!this) null else true
|
return if (!this) null else true
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ fun Boolean?.case_1(): Boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TESTCASE NUMBER: 2
|
// TESTCASE NUMBER: 2
|
||||||
fun <T : Boolean>T?.case_2(): Boolean {
|
fun <T : <!FINAL_UPPER_BOUND!>Boolean<!>>T?.case_2(): Boolean {
|
||||||
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns(true) implies (this@case_2 != null && this@case_2 !is Nothing && this@case_2)<!> }
|
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns(true) implies (this@case_2 != null && this@case_2 !is Nothing && this@case_2)<!> }
|
||||||
return this != null && this !is Nothing && this
|
return this != null && this !is Nothing && this
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ fun <T : Number?> T.case_1() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TESTCASE NUMBER: 2
|
// TESTCASE NUMBER: 2
|
||||||
fun <T : Number, K : String> T?.case_2(value_1: K?) {
|
fun <T : Number, K : <!FINAL_UPPER_BOUND!>String<!>> T?.case_2(value_1: K?) {
|
||||||
contract { returns() implies (this@case_2 is T && value_1 is K) }
|
contract { returns() implies (this@case_2 is T && value_1 is K) }
|
||||||
if (!(this@case_2 is T && value_1 is K)) throw Exception()
|
if (!(this@case_2 is T && value_1 is K)) throw Exception()
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ class case_4 : ClassLevel3() {
|
|||||||
return this == null
|
return this == null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Boolean>T.case_4_2() {
|
fun <T : <!FINAL_UPPER_BOUND!>Boolean<!>>T.case_4_2() {
|
||||||
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (!this@case_4_2)<!> }
|
contract { <!ERROR_IN_CONTRACT_DESCRIPTION!>returns() implies (!this@case_4_2)<!> }
|
||||||
if (this) throw Exception()
|
if (this) throw Exception()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ inline fun <reified T>case_3(x: Any?) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TESTCASE NUMBER: 4
|
// TESTCASE NUMBER: 4
|
||||||
inline fun <reified T : Boolean>case_4(x: Any?) {
|
inline fun <reified T : <!FINAL_UPPER_BOUND!>Boolean<!>>case_4(x: Any?) {
|
||||||
if (x is Int is T == null) {
|
if (x is Int is T == null) {
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>.<!UNRESOLVED_REFERENCE!>inv<!>()
|
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>.<!UNRESOLVED_REFERENCE!>inv<!>()
|
||||||
|
|||||||
@@ -97,8 +97,8 @@ fun case_9() {
|
|||||||
* UNEXPECTED BEHAVIOUR
|
* UNEXPECTED BEHAVIOUR
|
||||||
* ISSUES: KT-22175
|
* ISSUES: KT-22175
|
||||||
*/
|
*/
|
||||||
fun <T : String> T?.case_10() = this
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_10() = this
|
||||||
fun <T : Int> T?.case_10() = this
|
fun <T : <!FINAL_UPPER_BOUND!>Int<!>> T?.case_10() = this
|
||||||
fun case_10() {
|
fun case_10() {
|
||||||
var x: Int? = 10
|
var x: Int? = 10
|
||||||
x = null
|
x = null
|
||||||
@@ -106,7 +106,7 @@ fun case_10() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TESTCASE NUMBER: 11
|
// TESTCASE NUMBER: 11
|
||||||
fun <T : String> T?.case_11() = this
|
fun <T : <!FINAL_UPPER_BOUND!>String<!>> T?.case_11() = this
|
||||||
fun case_11() {
|
fun case_11() {
|
||||||
var x: Int? = 10
|
var x: Int? = 10
|
||||||
x = null
|
x = null
|
||||||
|
|||||||
+7
@@ -881,6 +881,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.FINAL_UPPER_BOUND) { firDiagnostic ->
|
||||||
|
FinalUpperBoundImpl(
|
||||||
|
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
|
||||||
|
firDiagnostic as FirPsiDiagnostic<*>,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED) { firDiagnostic ->
|
add(FirErrors.EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED) { firDiagnostic ->
|
||||||
ExtensionInClassReferenceNotAllowedImpl(
|
ExtensionInClassReferenceNotAllowedImpl(
|
||||||
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a as FirCallableDeclaration),
|
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a as FirCallableDeclaration),
|
||||||
|
|||||||
+5
@@ -628,6 +628,11 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
abstract val typeParameter: KtTypeParameterSymbol
|
abstract val typeParameter: KtTypeParameterSymbol
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class FinalUpperBound : KtFirDiagnostic<PsiElement>() {
|
||||||
|
override val diagnosticClass get() = FinalUpperBound::class
|
||||||
|
abstract val type: KtType
|
||||||
|
}
|
||||||
|
|
||||||
abstract class ExtensionInClassReferenceNotAllowed : KtFirDiagnostic<KtExpression>() {
|
abstract class ExtensionInClassReferenceNotAllowed : KtFirDiagnostic<KtExpression>() {
|
||||||
override val diagnosticClass get() = ExtensionInClassReferenceNotAllowed::class
|
override val diagnosticClass get() = ExtensionInClassReferenceNotAllowed::class
|
||||||
abstract val referencedDeclaration: KtCallableSymbol
|
abstract val referencedDeclaration: KtCallableSymbol
|
||||||
|
|||||||
+8
@@ -1010,6 +1010,14 @@ internal class TypeParameterAsReifiedImpl(
|
|||||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class FinalUpperBoundImpl(
|
||||||
|
override val type: KtType,
|
||||||
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.FinalUpperBound(), KtAbstractFirDiagnostic<PsiElement> {
|
||||||
|
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||||
|
}
|
||||||
|
|
||||||
internal class ExtensionInClassReferenceNotAllowedImpl(
|
internal class ExtensionInClassReferenceNotAllowedImpl(
|
||||||
override val referencedDeclaration: KtCallableSymbol,
|
override val referencedDeclaration: KtCallableSymbol,
|
||||||
firDiagnostic: FirPsiDiagnostic<*>,
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
|
|||||||
Reference in New Issue
Block a user