[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
|
||||
val typeVariable = coneType.constructor.variable as? ConeTypeParameterBasedTypeVariable
|
||||
val typeParameterSymbol = typeVariable?.typeParameterSymbol ?: throwUnexpectedElementError(coneType)
|
||||
val coneTypeParameterType = (typeParameterSymbol.toConeType() as ConeTypeParameterType)
|
||||
.withNullability(coneType.nullability, rootSession.typeContext)
|
||||
val coneTypeParameterType = typeParameterSymbol.toConeType(coneType.nullability.isNullable)
|
||||
|
||||
KtFirTypeParameterType(coneTypeParameterType, this@KtSymbolByFirBuilder)
|
||||
}
|
||||
|
||||
+15
@@ -2427,6 +2427,21 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
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 ->
|
||||
DeprecatedTypeParameterSyntaxImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
|
||||
+9
@@ -1723,6 +1723,15 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
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> {
|
||||
override val diagnosticClass get() = DeprecatedTypeParameterSyntax::class
|
||||
}
|
||||
|
||||
+11
@@ -2072,6 +2072,17 @@ internal class FiniteBoundsViolationInJavaImpl(
|
||||
token: KtLifetimeToken,
|
||||
) : 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(
|
||||
firDiagnostic: KtPsiDiagnostic,
|
||||
token: KtLifetimeToken,
|
||||
|
||||
+5
-1
@@ -792,7 +792,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val CYCLIC_GENERIC_UPPER_BOUND 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")
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -467,7 +467,9 @@ object FirErrors {
|
||||
val ABBREVIATED_NOTHING_PROPERTY_TYPE by error0<PsiElement>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
|
||||
val CYCLIC_GENERIC_UPPER_BOUND 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 MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning0<KtTypeParameter>()
|
||||
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",
|
||||
"CYCLIC_GENERIC_UPPER_BOUND",
|
||||
"FINITE_BOUNDS_VIOLATION",
|
||||
"FINITE_BOUNDS_VIOLATION_IN_JAVA",
|
||||
"EXPANSIVE_INHERITANCE",
|
||||
"DEPRECATED_TYPE_PARAMETER_SYNTAX",
|
||||
"DYNAMIC_SUPERTYPE",
|
||||
"DYNAMIC_UPPER_BOUND",
|
||||
|
||||
+1
@@ -140,6 +140,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
FirDelegateFieldTypeMismatchChecker,
|
||||
FirMultipleDefaultsInheritedFromSupertypesChecker,
|
||||
FirFiniteBoundRestrictionChecker,
|
||||
FirNonExpansiveInheritanceRestrictionChecker,
|
||||
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_SUPPRESSION
|
||||
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_PROPERTY_PARAMETER
|
||||
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(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.")
|
||||
|
||||
|
||||
@@ -53,6 +53,14 @@ private fun ConeKotlinType.contains(predicate: (ConeKotlinType) -> Boolean, visi
|
||||
|
||||
// ----------------------------------- Transformations -----------------------------------
|
||||
|
||||
fun ConeKotlinType.unwrapLowerBound(): ConeSimpleKotlinType {
|
||||
return when(this) {
|
||||
is ConeDefinitelyNotNullType -> original.unwrapLowerBound()
|
||||
is ConeFlexibleType -> lowerBound.unwrapLowerBound()
|
||||
is ConeSimpleKotlinType -> this
|
||||
}
|
||||
}
|
||||
|
||||
fun ConeKotlinType.upperBoundIfFlexible(): ConeSimpleKotlinType {
|
||||
return when (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.FirRegularClassSymbol
|
||||
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.name.Name
|
||||
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
|
||||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
|
||||
interface A<T>
|
||||
@@ -25,4 +26,8 @@ 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>>
|
||||
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 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 open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
|
||||
Reference in New Issue
Block a user