[FIR] Add checker for EXPANSIVE_INHERITANCE
^KT-59402 Fixed
This commit is contained in:
+1
-2
@@ -461,8 +461,7 @@ internal class KtSymbolByFirBuilder constructor(
|
|||||||
// TODO this is a temporary hack to prevent FIR IDE from crashing on builder inference, see KT-50916
|
// TODO this is a temporary hack to prevent FIR IDE from crashing on builder inference, see KT-50916
|
||||||
val typeVariable = coneType.constructor.variable as? ConeTypeParameterBasedTypeVariable
|
val typeVariable = coneType.constructor.variable as? ConeTypeParameterBasedTypeVariable
|
||||||
val typeParameterSymbol = typeVariable?.typeParameterSymbol ?: throwUnexpectedElementError(coneType)
|
val typeParameterSymbol = typeVariable?.typeParameterSymbol ?: throwUnexpectedElementError(coneType)
|
||||||
val coneTypeParameterType = (typeParameterSymbol.toConeType() as ConeTypeParameterType)
|
val coneTypeParameterType = typeParameterSymbol.toConeType(coneType.nullability.isNullable)
|
||||||
.withNullability(coneType.nullability, rootSession.typeContext)
|
|
||||||
|
|
||||||
KtFirTypeParameterType(coneTypeParameterType, this@KtSymbolByFirBuilder)
|
KtFirTypeParameterType(coneTypeParameterType, this@KtSymbolByFirBuilder)
|
||||||
}
|
}
|
||||||
|
|||||||
+15
@@ -2427,6 +2427,21 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.EXPANSIVE_INHERITANCE) { firDiagnostic ->
|
||||||
|
ExpansiveInheritanceImpl(
|
||||||
|
firDiagnostic as KtPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
add(FirErrors.EXPANSIVE_INHERITANCE_IN_JAVA) { firDiagnostic ->
|
||||||
|
ExpansiveInheritanceInJavaImpl(
|
||||||
|
firDiagnostic.a.map { firBasedSymbol ->
|
||||||
|
firSymbolBuilder.buildSymbol(firBasedSymbol)
|
||||||
|
},
|
||||||
|
firDiagnostic as KtPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.DEPRECATED_TYPE_PARAMETER_SYNTAX) { firDiagnostic ->
|
add(FirErrors.DEPRECATED_TYPE_PARAMETER_SYNTAX) { firDiagnostic ->
|
||||||
DeprecatedTypeParameterSyntaxImpl(
|
DeprecatedTypeParameterSyntaxImpl(
|
||||||
firDiagnostic as KtPsiDiagnostic,
|
firDiagnostic as KtPsiDiagnostic,
|
||||||
|
|||||||
+9
@@ -1723,6 +1723,15 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
val containingTypes: List<KtSymbol>
|
val containingTypes: List<KtSymbol>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ExpansiveInheritance : KtFirDiagnostic<PsiElement> {
|
||||||
|
override val diagnosticClass get() = ExpansiveInheritance::class
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExpansiveInheritanceInJava : KtFirDiagnostic<PsiElement> {
|
||||||
|
override val diagnosticClass get() = ExpansiveInheritanceInJava::class
|
||||||
|
val containingTypes: List<KtSymbol>
|
||||||
|
}
|
||||||
|
|
||||||
interface DeprecatedTypeParameterSyntax : KtFirDiagnostic<KtDeclaration> {
|
interface DeprecatedTypeParameterSyntax : KtFirDiagnostic<KtDeclaration> {
|
||||||
override val diagnosticClass get() = DeprecatedTypeParameterSyntax::class
|
override val diagnosticClass get() = DeprecatedTypeParameterSyntax::class
|
||||||
}
|
}
|
||||||
|
|||||||
+11
@@ -2072,6 +2072,17 @@ internal class FiniteBoundsViolationInJavaImpl(
|
|||||||
token: KtLifetimeToken,
|
token: KtLifetimeToken,
|
||||||
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.FiniteBoundsViolationInJava
|
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.FiniteBoundsViolationInJava
|
||||||
|
|
||||||
|
internal class ExpansiveInheritanceImpl(
|
||||||
|
firDiagnostic: KtPsiDiagnostic,
|
||||||
|
token: KtLifetimeToken,
|
||||||
|
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.ExpansiveInheritance
|
||||||
|
|
||||||
|
internal class ExpansiveInheritanceInJavaImpl(
|
||||||
|
override val containingTypes: List<KtSymbol>,
|
||||||
|
firDiagnostic: KtPsiDiagnostic,
|
||||||
|
token: KtLifetimeToken,
|
||||||
|
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.ExpansiveInheritanceInJava
|
||||||
|
|
||||||
internal class DeprecatedTypeParameterSyntaxImpl(
|
internal class DeprecatedTypeParameterSyntaxImpl(
|
||||||
firDiagnostic: KtPsiDiagnostic,
|
firDiagnostic: KtPsiDiagnostic,
|
||||||
token: KtLifetimeToken,
|
token: KtLifetimeToken,
|
||||||
|
|||||||
+5
-1
@@ -792,7 +792,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
|||||||
val CYCLIC_GENERIC_UPPER_BOUND by error<PsiElement>()
|
val CYCLIC_GENERIC_UPPER_BOUND by error<PsiElement>()
|
||||||
|
|
||||||
val FINITE_BOUNDS_VIOLATION by error<PsiElement>()
|
val FINITE_BOUNDS_VIOLATION by error<PsiElement>()
|
||||||
val FINITE_BOUNDS_VIOLATION_IN_JAVA by error<PsiElement> {
|
val FINITE_BOUNDS_VIOLATION_IN_JAVA by warning<PsiElement> {
|
||||||
|
parameter<List<Symbol>>("containingTypes")
|
||||||
|
}
|
||||||
|
val EXPANSIVE_INHERITANCE by error<PsiElement>()
|
||||||
|
val EXPANSIVE_INHERITANCE_IN_JAVA by warning<PsiElement> {
|
||||||
parameter<List<Symbol>>("containingTypes")
|
parameter<List<Symbol>>("containingTypes")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -467,7 +467,9 @@ object FirErrors {
|
|||||||
val ABBREVIATED_NOTHING_PROPERTY_TYPE by error0<PsiElement>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
|
val ABBREVIATED_NOTHING_PROPERTY_TYPE by error0<PsiElement>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
|
||||||
val CYCLIC_GENERIC_UPPER_BOUND by error0<PsiElement>()
|
val CYCLIC_GENERIC_UPPER_BOUND by error0<PsiElement>()
|
||||||
val FINITE_BOUNDS_VIOLATION by error0<PsiElement>()
|
val FINITE_BOUNDS_VIOLATION by error0<PsiElement>()
|
||||||
val FINITE_BOUNDS_VIOLATION_IN_JAVA by error1<PsiElement, List<FirBasedSymbol<*>>>()
|
val FINITE_BOUNDS_VIOLATION_IN_JAVA by warning1<PsiElement, List<FirBasedSymbol<*>>>()
|
||||||
|
val EXPANSIVE_INHERITANCE by error0<PsiElement>()
|
||||||
|
val EXPANSIVE_INHERITANCE_IN_JAVA by warning1<PsiElement, List<FirBasedSymbol<*>>>()
|
||||||
val DEPRECATED_TYPE_PARAMETER_SYNTAX by error0<KtDeclaration>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
|
val DEPRECATED_TYPE_PARAMETER_SYNTAX by error0<KtDeclaration>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
|
||||||
val MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning0<KtTypeParameter>()
|
val MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning0<KtTypeParameter>()
|
||||||
val DYNAMIC_SUPERTYPE by error0<KtTypeReference>()
|
val DYNAMIC_SUPERTYPE by error0<KtTypeReference>()
|
||||||
|
|||||||
+1
-1
@@ -305,7 +305,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set<String> = setOf(
|
|||||||
"IMPLICIT_NOTHING_PROPERTY_TYPE",
|
"IMPLICIT_NOTHING_PROPERTY_TYPE",
|
||||||
"CYCLIC_GENERIC_UPPER_BOUND",
|
"CYCLIC_GENERIC_UPPER_BOUND",
|
||||||
"FINITE_BOUNDS_VIOLATION",
|
"FINITE_BOUNDS_VIOLATION",
|
||||||
"FINITE_BOUNDS_VIOLATION_IN_JAVA",
|
"EXPANSIVE_INHERITANCE",
|
||||||
"DEPRECATED_TYPE_PARAMETER_SYNTAX",
|
"DEPRECATED_TYPE_PARAMETER_SYNTAX",
|
||||||
"DYNAMIC_SUPERTYPE",
|
"DYNAMIC_SUPERTYPE",
|
||||||
"DYNAMIC_UPPER_BOUND",
|
"DYNAMIC_UPPER_BOUND",
|
||||||
|
|||||||
+1
@@ -140,6 +140,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
|||||||
FirDelegateFieldTypeMismatchChecker,
|
FirDelegateFieldTypeMismatchChecker,
|
||||||
FirMultipleDefaultsInheritedFromSupertypesChecker,
|
FirMultipleDefaultsInheritedFromSupertypesChecker,
|
||||||
FirFiniteBoundRestrictionChecker,
|
FirFiniteBoundRestrictionChecker,
|
||||||
|
FirNonExpansiveInheritanceRestrictionChecker,
|
||||||
FirDefaultArgumentsInExpectActualizedByFakeOverrideChecker,
|
FirDefaultArgumentsInExpectActualizedByFakeOverrideChecker,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+175
@@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.diagnostics.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.collectUpperBounds
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.impl.toConeType
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
|
||||||
|
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.utils.DFS
|
||||||
|
import org.jetbrains.kotlin.utils.SmartSet
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.jetbrains.kotlin.resolve.NonExpansiveInheritanceRestrictionChecker
|
||||||
|
*/
|
||||||
|
object FirNonExpansiveInheritanceRestrictionChecker : FirRegularClassChecker() {
|
||||||
|
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
if (declaration.typeParameters.isEmpty()) return
|
||||||
|
|
||||||
|
val graph = buildTypeGraph(declaration, context.session)
|
||||||
|
|
||||||
|
val edgesInCycles = graph.expansiveEdges.filterTo(SmartSet.create()) { graph.isEdgeInCycle(it) }
|
||||||
|
if (edgesInCycles.isEmpty()) return
|
||||||
|
|
||||||
|
val problemNodes = edgesInCycles.flatMapTo(mutableSetOf()) { listOf(it.from, it.to) }
|
||||||
|
|
||||||
|
for (ref in declaration.typeParameters) {
|
||||||
|
if (problemNodes.remove(TypeParameterNode(declaration.symbol, ref.symbol))) {
|
||||||
|
reporter.reportOn(ref.source ?: declaration.source, FirErrors.EXPANSIVE_INHERITANCE, context)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (problemNodes.any { it.typeParameter.source != null }) return
|
||||||
|
|
||||||
|
val containers = problemNodes.map { it.container }
|
||||||
|
reporter.reportOn(declaration.source, FirErrors.EXPANSIVE_INHERITANCE_IN_JAVA, containers, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildTypeGraph(
|
||||||
|
declaration: FirRegularClass,
|
||||||
|
session: FirSession,
|
||||||
|
): Graph<TypeParameterNode> {
|
||||||
|
// K1 treats type parameters inherited within inner classes from outer classes as being
|
||||||
|
// from different classes. However, in K2, the symbol for these type parameters are the
|
||||||
|
// same. So we have to store the pair of class symbol and type parameter symbol, so we do
|
||||||
|
// not report errors on inherited type parameters from outer classes.
|
||||||
|
val graph = Graph<TypeParameterNode>()
|
||||||
|
|
||||||
|
fun addEdges(
|
||||||
|
typeParameters: List<FirTypeParameterSymbol>,
|
||||||
|
constituentTypes: Set<ConeKotlinType>,
|
||||||
|
symbol: FirRegularClassSymbol,
|
||||||
|
constituentTypeSymbol: FirRegularClassSymbol,
|
||||||
|
constituentTypeParameterSymbol: FirTypeParameterSymbol,
|
||||||
|
expansive: Boolean,
|
||||||
|
) {
|
||||||
|
for (typeParameter in typeParameters) {
|
||||||
|
if (typeParameter.toConeType(isNullable = false) in constituentTypes ||
|
||||||
|
typeParameter.toConeType(isNullable = true) in constituentTypes
|
||||||
|
) {
|
||||||
|
graph.addEdge(
|
||||||
|
from = TypeParameterNode(symbol, typeParameter),
|
||||||
|
to = TypeParameterNode(constituentTypeSymbol, constituentTypeParameterSymbol),
|
||||||
|
expansive = expansive,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val visitedSymbols = SmartSet.create<FirClassifierSymbol<*>>()
|
||||||
|
fun visit(symbol: FirRegularClassSymbol) {
|
||||||
|
val typeParameters = symbol.typeParameterSymbols
|
||||||
|
|
||||||
|
// For each type parameter T, let ST be the set of all constituent types of all immediate supertypes of the owner of T.
|
||||||
|
// If T appears as a constituent type of a simple type argument A in a generic type in ST, add an edge from T
|
||||||
|
// to U, where U is the type parameter corresponding to A. The edge is non-expansive if A has the form T or T?,
|
||||||
|
// the edge is expansive otherwise.
|
||||||
|
for (constituentType in symbol.resolvedSuperTypes.flatMap { it.constituentTypes() }) {
|
||||||
|
val constituentTypeSymbol = constituentType.toRegularClassSymbol(session) ?: continue
|
||||||
|
if (visitedSymbols.add(constituentTypeSymbol)) visit(constituentTypeSymbol)
|
||||||
|
if (constituentTypeSymbol.typeParameterSymbols.size != constituentType.typeArguments.size) continue
|
||||||
|
|
||||||
|
for ((i, typeProjection) in constituentType.typeArguments.withIndex()) {
|
||||||
|
val constituentTypeParameterSymbol = constituentTypeSymbol.typeParameterSymbols[i]
|
||||||
|
if (typeProjection.kind == ProjectionKind.INVARIANT) {
|
||||||
|
val constituents = typeProjection.type!!.constituentTypes()
|
||||||
|
|
||||||
|
addEdges(
|
||||||
|
typeParameters = typeParameters,
|
||||||
|
constituentTypes = constituents,
|
||||||
|
symbol = symbol,
|
||||||
|
constituentTypeSymbol = constituentTypeSymbol,
|
||||||
|
constituentTypeParameterSymbol = constituentTypeParameterSymbol,
|
||||||
|
expansive = typeProjection.type!!.unwrapLowerBound() !is ConeTypeParameterType,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Furthermore, if T appears as a constituent type of an element of the B-closure of the set of lower and
|
||||||
|
// upper bounds of a skolem type variable Q in a skolemization of a projected generic type in ST, add an
|
||||||
|
// expanding edge from T to V, where V is the type parameter corresponding to Q.
|
||||||
|
val bounds = SmartSet.create<ConeKotlinType>()
|
||||||
|
constituentTypeParameterSymbol.resolvedBounds.mapTo(bounds) { it.type }
|
||||||
|
typeProjection.type?.let(bounds::add)
|
||||||
|
val boundClosure = bounds.flatMapTo(SmartSet.create()) { it.collectUpperBounds() }
|
||||||
|
|
||||||
|
addEdges(
|
||||||
|
typeParameters = typeParameters,
|
||||||
|
constituentTypes = boundClosure.flatMapTo(SmartSet.create()) { it.constituentTypes() },
|
||||||
|
symbol = symbol,
|
||||||
|
constituentTypeSymbol = constituentTypeSymbol,
|
||||||
|
constituentTypeParameterSymbol = constituentTypeParameterSymbol,
|
||||||
|
expansive = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
visitedSymbols.add(declaration.symbol)
|
||||||
|
visit(declaration.symbol)
|
||||||
|
|
||||||
|
return graph
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class TypeParameterNode(
|
||||||
|
val container: FirRegularClassSymbol,
|
||||||
|
val typeParameter: FirTypeParameterSymbol,
|
||||||
|
)
|
||||||
|
|
||||||
|
private data class ExpansiveEdge<out T>(val from: T, val to: T)
|
||||||
|
|
||||||
|
private class Graph<T> {
|
||||||
|
val expansiveEdges = SmartSet.create<ExpansiveEdge<T>>()
|
||||||
|
private val edgeLists = mutableMapOf<T, MutableSet<T>>()
|
||||||
|
|
||||||
|
fun addEdge(from: T, to: T, expansive: Boolean = false) {
|
||||||
|
edgeLists.getOrPut(from) { SmartSet.create() }.add(to)
|
||||||
|
if (expansive) {
|
||||||
|
expansiveEdges.add(ExpansiveEdge(from, to))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isEdgeInCycle(edge: ExpansiveEdge<T>) = edge.from in collectReachable(edge.to)
|
||||||
|
|
||||||
|
private fun collectReachable(from: T): List<T> {
|
||||||
|
val handler = object : DFS.NodeHandlerWithListResult<T, T>() {
|
||||||
|
override fun afterChildren(current: T?) {
|
||||||
|
result.add(current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val neighbors = DFS.Neighbors<T> { current -> edgeLists[current] ?: emptySet() }
|
||||||
|
|
||||||
|
DFS.dfs(listOf(from), neighbors, handler)
|
||||||
|
|
||||||
|
return handler.result()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ConeKotlinType.constituentTypes(): Set<ConeKotlinType> {
|
||||||
|
val constituentTypes = SmartSet.create<ConeKotlinType>()
|
||||||
|
forEachType { constituentTypes.add(it) }
|
||||||
|
return constituentTypes
|
||||||
|
}
|
||||||
+9
-1
@@ -218,6 +218,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_FROM_JAVA_R
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_IN_CONTRACT_DESCRIPTION
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_IN_CONTRACT_DESCRIPTION
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_SUPPRESSION
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_SUPPRESSION
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPANDED_TYPE_CANNOT_BE_INHERITED
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPANDED_TYPE_CANNOT_BE_INHERITED
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPANSIVE_INHERITANCE
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPANSIVE_INHERITANCE_IN_JAVA
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_CLASS_CONSTRUCTOR_DELEGATION_CALL
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_CLASS_CONSTRUCTOR_DELEGATION_CALL
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_CLASS_CONSTRUCTOR_PROPERTY_PARAMETER
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_CONDITION
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_CONDITION
|
||||||
@@ -1445,7 +1447,13 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
|||||||
map.put(CYCLIC_GENERIC_UPPER_BOUND, "Type parameter has cyclic upper bounds.")
|
map.put(CYCLIC_GENERIC_UPPER_BOUND, "Type parameter has cyclic upper bounds.")
|
||||||
|
|
||||||
map.put(FINITE_BOUNDS_VIOLATION, "This type parameter violates the Finite Bound Restriction.")
|
map.put(FINITE_BOUNDS_VIOLATION, "This type parameter violates the Finite Bound Restriction.")
|
||||||
map.put(FINITE_BOUNDS_VIOLATION_IN_JAVA, "Violation of Finite Bound Restriction for {0}", commaSeparated(DECLARATION_NAME))
|
map.put(FINITE_BOUNDS_VIOLATION_IN_JAVA, "Violation of Finite Bound Restriction for {0}.", commaSeparated(DECLARATION_NAME))
|
||||||
|
map.put(EXPANSIVE_INHERITANCE, "This type parameter violates the Non-Expansive Inheritance Restriction.")
|
||||||
|
map.put(
|
||||||
|
EXPANSIVE_INHERITANCE_IN_JAVA,
|
||||||
|
"Violation of Non-Expansive Inheritance Restriction for {0}.",
|
||||||
|
commaSeparated(DECLARATION_NAME),
|
||||||
|
)
|
||||||
|
|
||||||
map.put(DEPRECATED_TYPE_PARAMETER_SYNTAX, "Type parameters must be placed before function name.")
|
map.put(DEPRECATED_TYPE_PARAMETER_SYNTAX, "Type parameters must be placed before function name.")
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,14 @@ private fun ConeKotlinType.contains(predicate: (ConeKotlinType) -> Boolean, visi
|
|||||||
|
|
||||||
// ----------------------------------- Transformations -----------------------------------
|
// ----------------------------------- Transformations -----------------------------------
|
||||||
|
|
||||||
|
fun ConeKotlinType.unwrapLowerBound(): ConeSimpleKotlinType {
|
||||||
|
return when(this) {
|
||||||
|
is ConeDefinitelyNotNullType -> original.unwrapLowerBound()
|
||||||
|
is ConeFlexibleType -> lowerBound.unwrapLowerBound()
|
||||||
|
is ConeSimpleKotlinType -> this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun ConeKotlinType.upperBoundIfFlexible(): ConeSimpleKotlinType {
|
fun ConeKotlinType.upperBoundIfFlexible(): ConeSimpleKotlinType {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is ConeSimpleKotlinType -> this
|
is ConeSimpleKotlinType -> this
|
||||||
|
|||||||
+6
-3
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
|||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassifierSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeTypeParameterType
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
|
import org.jetbrains.kotlin.utils.addToStdlib.shouldNotBeCalled
|
||||||
@@ -91,6 +91,9 @@ class FirCompositeNestedClassifierScope(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FirTypeParameterRef.toConeType(): ConeKotlinType = symbol.toConeType()
|
fun FirTypeParameterRef.toConeType(): ConeTypeParameterType = symbol.toConeType()
|
||||||
|
|
||||||
fun FirTypeParameterSymbol.toConeType(): ConeKotlinType = ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(this), isNullable = false)
|
fun FirTypeParameterSymbol.toConeType(): ConeTypeParameterType = toConeType(false)
|
||||||
|
|
||||||
|
fun FirTypeParameterSymbol.toConeType(isNullable: Boolean): ConeTypeParameterType =
|
||||||
|
ConeTypeParameterTypeImpl(ConeTypeParameterLookupTag(this), isNullable)
|
||||||
|
|||||||
-14
@@ -1,14 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UPPER_BOUND_VIOLATED
|
|
||||||
|
|
||||||
// FILE: D.java
|
|
||||||
public interface D<W> {}
|
|
||||||
|
|
||||||
// FILE: Q.java
|
|
||||||
public interface Q<Z1, Z2> {}
|
|
||||||
|
|
||||||
// FILE: C.java
|
|
||||||
public interface C<X> extends D<P<X,X>> {}
|
|
||||||
|
|
||||||
// FILE: 1.kt
|
|
||||||
interface P<Y1, Y2> : Q<C<Y1>, C<D<Y2>>>
|
|
||||||
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UPPER_BOUND_VIOLATED
|
// !DIAGNOSTICS: -UPPER_BOUND_VIOLATED
|
||||||
|
|
||||||
// FILE: D.java
|
// FILE: D.java
|
||||||
|
|||||||
-16
@@ -1,16 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UPPER_BOUND_VIOLATED
|
|
||||||
|
|
||||||
// FILE: D.java
|
|
||||||
public interface D<W> {}
|
|
||||||
|
|
||||||
// FILE: Q.java
|
|
||||||
public interface Q<Z1, Z2> {}
|
|
||||||
|
|
||||||
// FILE: C.java
|
|
||||||
public interface C<X> extends D<P<X,X>> {}
|
|
||||||
|
|
||||||
// FILE: P.java
|
|
||||||
public interface P<Y1, Y2> extends Q<C<Y1>, C<D<Y2>>> {}
|
|
||||||
|
|
||||||
// FILE: 1.kt
|
|
||||||
interface P1<YY1, YY2> : P<YY1, YY2>
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UPPER_BOUND_VIOLATED
|
// !DIAGNOSTICS: -UPPER_BOUND_VIOLATED
|
||||||
|
|
||||||
// FILE: D.java
|
// FILE: D.java
|
||||||
|
|||||||
-28
@@ -1,28 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UPPER_BOUND_VIOLATED
|
|
||||||
|
|
||||||
interface A<T>
|
|
||||||
interface B<T> : A<A<*>>
|
|
||||||
|
|
||||||
interface N0<in T>
|
|
||||||
interface C0<X> : N0<N0<C0<C0<X>>>>
|
|
||||||
|
|
||||||
interface N1<in T>
|
|
||||||
interface C1<X> : N1<N1<C1<C1<X?>>>>
|
|
||||||
interface C2<T> : C1<C1<T>>
|
|
||||||
|
|
||||||
interface C<X> : D<P<X, X>>
|
|
||||||
interface P<Y1, Y2> : Q<C<Y1>, C<D<Y2>>>
|
|
||||||
interface Q<Z1, Z2>
|
|
||||||
interface D<W>
|
|
||||||
|
|
||||||
interface E0<T>
|
|
||||||
interface E1<T : E2>
|
|
||||||
interface E2 : E0<E1<out E2>>
|
|
||||||
|
|
||||||
interface F0<T>
|
|
||||||
interface F1<T : F2<*>, U : F2<*>>
|
|
||||||
interface F2<T> : F0<F1<out F2<*>, T>>
|
|
||||||
|
|
||||||
interface G0<T>
|
|
||||||
interface G1<T : U, U : G2<*>>
|
|
||||||
interface G2<T> : G0<G1<out G2<*>, T>>
|
|
||||||
+6
-1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UPPER_BOUND_VIOLATED
|
// !DIAGNOSTICS: -UPPER_BOUND_VIOLATED
|
||||||
|
|
||||||
interface A<T>
|
interface A<T>
|
||||||
@@ -25,4 +26,8 @@ interface F2<T> : F0<F1<out F2<*>, T>>
|
|||||||
|
|
||||||
interface G0<T>
|
interface G0<T>
|
||||||
interface G1<T : U, U : G2<*>>
|
interface G1<T : U, U : G2<*>>
|
||||||
interface G2<T> : G0<G1<out G2<*>, T>>
|
interface G2<T> : G0<G1<out G2<*>, T>>
|
||||||
|
|
||||||
|
abstract class H0<X> {
|
||||||
|
inner abstract class H1<Y> : H0<H1<Y>>() // Outer(X) should not be reported as non-expansive
|
||||||
|
}
|
||||||
|
|||||||
+14
@@ -96,6 +96,20 @@ public interface G2</*0*/ T> : G0<G1<out G2<*>, T>> {
|
|||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract class H0</*0*/ X> {
|
||||||
|
public constructor H0</*0*/ X>()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
|
||||||
|
public abstract inner class H1</*0*/ Y> /*captured type parameters: /*1*/ X*/ : H0<H0<X>.H1<Y>> {
|
||||||
|
public constructor H1</*0*/ Y>()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public interface N0</*0*/ in T> {
|
public interface N0</*0*/ in T> {
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
|||||||
Reference in New Issue
Block a user