[FIR] Implement UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION diagnostics, fix handling of UPPER_BOUND_VIOLATED

This commit is contained in:
Ivan Kochurkin
2021-06-14 16:19:21 +03:00
committed by teamcityserver
parent 5741374883
commit 66e2b44272
20 changed files with 162 additions and 89 deletions
@@ -45,7 +45,7 @@ fun <K, L : K> rest() {
class NumColl<T : Collection<Number>> class NumColl<T : Collection<Number>>
typealias NL<K> = NumColl<List<K>> typealias NL<K> = NumColl<List<K>>
val test7 = NL<Int>()<!UNRESOLVED_REFERENCE!>NumberPhile<!><!SYNTAX!><!> val test7 = NL<Int>()<!UNRESOLVED_REFERENCE!>NumberPhile<!><!SYNTAX!><!>
val test8 = NL<String>() val test8 = NL<<!UPPER_BOUND_VIOLATED!>String<!>>()
class NumberPhile<T: Number>(x: T) class NumberPhile<T: Number>(x: T)
val np1 = NumberPhile(10) val np1 = NumberPhile(10)
@@ -2,7 +2,7 @@
import java.util.EnumMap import java.util.EnumMap
typealias SomeEnumMap = EnumMap<String, String?> typealias SomeEnumMap = EnumMap<<!UPPER_BOUND_VIOLATED!>String<!>, String?>
fun test(map: SomeEnumMap, qualifier: String?) { fun test(map: SomeEnumMap, qualifier: String?) {
val result = map[qualifier] val result = map[qualifier]
@@ -402,7 +402,12 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val INFERENCE_ERROR by error<PsiElement>() val INFERENCE_ERROR by error<PsiElement>()
val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error<PsiElement>() val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error<PsiElement>()
val UPPER_BOUND_VIOLATED by error<PsiElement> { val UPPER_BOUND_VIOLATED by error<PsiElement> {
parameter<ConeKotlinType>("upperBound") parameter<ConeKotlinType>("expectedUpperBound")
parameter<ConeKotlinType>("actualUpperBound")
}
val UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION by error<PsiElement> {
parameter<ConeKotlinType>("expectedUpperBound")
parameter<ConeKotlinType>("actualUpperBound")
} }
val TYPE_ARGUMENTS_NOT_ALLOWED by error<PsiElement>() val TYPE_ARGUMENTS_NOT_ALLOWED by error<PsiElement>()
val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error<PsiElement> { val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error<PsiElement> {
@@ -282,7 +282,8 @@ object FirErrors {
val RECURSION_IN_IMPLICIT_TYPES by error0<PsiElement>() val RECURSION_IN_IMPLICIT_TYPES by error0<PsiElement>()
val INFERENCE_ERROR by error0<PsiElement>() val INFERENCE_ERROR by error0<PsiElement>()
val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error0<PsiElement>() val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error0<PsiElement>()
val UPPER_BOUND_VIOLATED by error1<PsiElement, ConeKotlinType>() val UPPER_BOUND_VIOLATED by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
val UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
val TYPE_ARGUMENTS_NOT_ALLOWED by error0<PsiElement>() val TYPE_ARGUMENTS_NOT_ALLOWED by error0<PsiElement>()
val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error2<PsiElement, Int, FirClassLikeSymbol<*>>() val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error2<PsiElement, Int, FirClassLikeSymbol<*>>()
val NO_TYPE_ARGUMENTS_ON_RHS by error2<PsiElement, Int, FirClassLikeSymbol<*>>() val NO_TYPE_ARGUMENTS_ON_RHS by error2<PsiElement, Int, FirClassLikeSymbol<*>>()
@@ -581,7 +581,7 @@ internal fun checkCondition(condition: FirExpression, context: CheckerContext, r
} }
} }
fun extractTypeRefAndSourceFromTypeArgument(typeRef: FirTypeRef?, index: Int): Pair<FirTypeRef, FirSourceElement?>? { fun extractArgumentTypeRefAndSource(typeRef: FirTypeRef?, index: Int): FirTypeRefSource? {
if (typeRef is FirResolvedTypeRef) { if (typeRef is FirResolvedTypeRef) {
val delegatedTypeRef = typeRef.delegatedTypeRef val delegatedTypeRef = typeRef.delegatedTypeRef
if (delegatedTypeRef is FirUserTypeRef) { if (delegatedTypeRef is FirUserTypeRef) {
@@ -601,20 +601,22 @@ fun extractTypeRefAndSourceFromTypeArgument(typeRef: FirTypeRef?, index: Int): P
val typeArgument = currentTypeArguments?.elementAtOrNull(currentIndex) val typeArgument = currentTypeArguments?.elementAtOrNull(currentIndex)
if (typeArgument is FirTypeProjectionWithVariance) { if (typeArgument is FirTypeProjectionWithVariance) {
return Pair(typeArgument.typeRef, typeArgument.source) return FirTypeRefSource(typeArgument.typeRef, typeArgument.source)
} }
} else if (delegatedTypeRef is FirFunctionTypeRef) { } else if (delegatedTypeRef is FirFunctionTypeRef) {
val valueParameters = delegatedTypeRef.valueParameters val valueParameters = delegatedTypeRef.valueParameters
if (index < valueParameters.size) { if (index < valueParameters.size) {
val valueParamTypeRef = valueParameters.elementAt(index).returnTypeRef val valueParamTypeRef = valueParameters.elementAt(index).returnTypeRef
return Pair(valueParamTypeRef, valueParamTypeRef.source) return FirTypeRefSource(valueParamTypeRef, valueParamTypeRef.source)
} }
if (index == valueParameters.size) { if (index == valueParameters.size) {
val returnTypeRef = delegatedTypeRef.returnTypeRef val returnTypeRef = delegatedTypeRef.returnTypeRef
return Pair(returnTypeRef, returnTypeRef.source) return FirTypeRefSource(returnTypeRef, returnTypeRef.source)
} }
} }
} }
return null return null
} }
data class FirTypeRefSource(val typeRef: FirTypeRef?, val source: FirSourceElement?)
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
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.extractTypeRefAndSourceFromTypeArgument import org.jetbrains.kotlin.fir.analysis.checkers.extractArgumentTypeRefAndSource
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.analysis.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
@@ -155,11 +155,11 @@ object FirClassVarianceChecker : FirClassChecker() {
} }
if (newVariance != null) { if (newVariance != null) {
val subTypeRefAndSource = extractTypeRefAndSourceFromTypeArgument(typeRef, index) val subTypeRefAndSource = extractArgumentTypeRefAndSource(typeRef, index)
checkVarianceConflict( checkVarianceConflict(
typeArgumentType, newVariance, subTypeRefAndSource?.first, containingType, typeArgumentType, newVariance, subTypeRefAndSource?.typeRef, containingType,
context, reporter, subTypeRefAndSource?.first?.source ?: source, context, reporter, subTypeRefAndSource?.typeRef?.source ?: source,
fullyExpandedType != type fullyExpandedType != type
) )
} }
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
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.extractTypeRefAndSourceFromTypeArgument import org.jetbrains.kotlin.fir.analysis.checkers.extractArgumentTypeRefAndSource
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.analysis.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
@@ -77,11 +77,11 @@ object FirProjectionRelationChecker : FirBasicDeclarationChecker() {
ProjectionRelation.None ProjectionRelation.None
} }
val (typeArgTypeRef, typeArgSource) = extractTypeRefAndSourceFromTypeArgument(typeRef, it) ?: continue val argTypeRefSource = extractArgumentTypeRefAndSource(typeRef, it) ?: continue
if (projectionRelation != ProjectionRelation.None && typeRef.source?.kind !is FirFakeSourceElementKind) { if (projectionRelation != ProjectionRelation.None && typeRef.source?.kind !is FirFakeSourceElementKind) {
reporter.reportOn( reporter.reportOn(
typeArgSource ?: typeArgTypeRef.source, argTypeRefSource.source ?: argTypeRefSource.typeRef?.source,
if (projectionRelation == ProjectionRelation.Conflicting) if (projectionRelation == ProjectionRelation.Conflicting)
if (type != fullyExpandedType) FirErrors.CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION else FirErrors.CONFLICTING_PROJECTION if (type != fullyExpandedType) FirErrors.CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION else FirErrors.CONFLICTING_PROJECTION
else else
@@ -91,7 +91,7 @@ object FirProjectionRelationChecker : FirBasicDeclarationChecker() {
) )
} }
checkTypeRef(typeArgTypeRef, context, reporter) argTypeRefSource.typeRef?.let { checkTypeRef(it, context, reporter) }
} }
} }
@@ -5,10 +5,12 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.FirTypeRefSource
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.declaration.FirBasicDeclarationChecker import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.extractTypeRefAndSourceFromTypeArgument import org.jetbrains.kotlin.fir.analysis.checkers.extractArgumentTypeRefAndSource
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.analysis.diagnostics.reportOn import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
@@ -17,7 +19,7 @@ import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.resolve.toSymbol import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
@@ -33,16 +35,20 @@ object FirUpperBoundViolatedClassChecker : FirBasicDeclarationChecker() {
for (typeParameter in declaration.typeParameters) { for (typeParameter in declaration.typeParameters) {
if (typeParameter is FirTypeParameter) { if (typeParameter is FirTypeParameter) {
for (bound in typeParameter.bounds) { for (bound in typeParameter.bounds) {
analyzeTypeParameters(bound, context, reporter) checkUpperBoundViolated(bound, context, reporter)
} }
} }
} }
for (superTypeRef in declaration.superTypeRefs) { for (superTypeRef in declaration.superTypeRefs) {
analyzeTypeParameters(superTypeRef, context, reporter) checkUpperBoundViolated(superTypeRef, context, reporter)
} }
} else if (declaration is FirTypeAlias) {
checkUpperBoundViolated(declaration.expandedTypeRef, context, reporter, isIgnoreTypeParameters = true)
} else if (declaration is FirCallableDeclaration<*>) { } else if (declaration is FirCallableDeclaration<*>) {
analyzeTypeParameters(declaration.returnTypeRef, context, reporter) if (declaration.returnTypeRef.source?.kind !is FirFakeSourceElementKind) {
checkUpperBoundViolated(declaration.returnTypeRef, context, reporter)
}
} }
} }
} }
@@ -67,12 +73,25 @@ object FirUpperBoundViolatedExpressionChecker : FirQualifiedAccessExpressionChec
calleeFir = calleReference.candidateSymbol?.fir.safeAs() calleeFir = calleReference.candidateSymbol?.fir.safeAs()
} }
analyzeTypeParameters( var typeArguments: List<Any>? = null
var typeArgumentRefsAndSources: List<FirTypeRefSource?>? = null
val typeParameters = if (calleeFir is FirConstructor) {
typeArgumentRefsAndSources =
expression.typeArguments.map { FirTypeRefSource((it as? FirTypeProjectionWithVariance)?.typeRef, it.source) }
val prototypeClass = calleeFir.dispatchReceiverType?.toSymbol(context.session)?.fir.safeAs<FirRegularClass>()
prototypeClass?.typeParameters?.map { it.symbol }
} else {
typeArguments = expression.typeArguments
calleeFir?.typeParameters?.map { it.symbol }
}
checkUpperBoundViolated(
expression.typeRef, expression.typeRef,
context, context,
reporter, reporter,
calleeFir?.typeParameters?.map { it.symbol }, typeParameters,
expression.typeArguments typeArguments,
typeArgumentRefsAndSources
) )
} }
} }
@@ -81,12 +100,15 @@ object FirUpperBoundViolatedExpressionChecker : FirQualifiedAccessExpressionChec
* Recursively analyzes type parameters and reports the diagnostic on the given source calculated using typeRef * Recursively analyzes type parameters and reports the diagnostic on the given source calculated using typeRef
* Returns true if an error occurred * Returns true if an error occurred
*/ */
private fun analyzeTypeParameters( private fun checkUpperBoundViolated(
typeRef: FirTypeRef?, typeRef: FirTypeRef?,
context: CheckerContext, context: CheckerContext,
reporter: DiagnosticReporter, reporter: DiagnosticReporter,
typeParameters: List<FirTypeParameterSymbol>? = null, typeParameters: List<FirTypeParameterSymbol>? = null,
typeArguments: List<FirTypeProjection>? = null typeArguments: List<Any>? = null,
typeArgumentRefsAndSources: List<FirTypeRefSource?>? = null,
isTypeAlias: Boolean = false,
isIgnoreTypeParameters: Boolean = false
) { ) {
val type = when (typeRef) { val type = when (typeRef) {
is ConeKotlinType -> typeRef is ConeKotlinType -> typeRef
@@ -101,10 +123,26 @@ private fun analyzeTypeParameters(
val typeParameterSymbols = typeParameters val typeParameterSymbols = typeParameters
?: if (type is ConeClassLikeType) { ?: if (type is ConeClassLikeType) {
val prototypeClass = type.lookupTag.toSymbol(context.session) val fullyExpandedType = type.fullyExpandedType(context.session)
val prototypeClass = fullyExpandedType.lookupTag.toSymbol(context.session)
?.fir.safeAs<FirRegularClass>() ?.fir.safeAs<FirRegularClass>()
?: return ?: return
if (type != fullyExpandedType) {
// special check for type aliases
checkUpperBoundViolated(
typeRef,
context,
reporter,
prototypeClass.typeParameters.map { it.symbol },
fullyExpandedType.typeArguments.toList(),
null,
isTypeAlias = true,
isIgnoreTypeParameters = isIgnoreTypeParameters
)
return
}
prototypeClass.typeParameters.map { it.symbol } prototypeClass.typeParameters.map { it.symbol }
} else { } else {
listOf() listOf()
@@ -142,36 +180,43 @@ private fun analyzeTypeParameters(
typeArgumentTypeRef = localTypeArgument.typeRef typeArgumentTypeRef = localTypeArgument.typeRef
typeArgument = typeArgumentTypeRef.coneType typeArgument = typeArgumentTypeRef.coneType
typeArgumentSource = localTypeArgument.source typeArgumentSource = localTypeArgument.source
} else if (localTypeArgument is ConeKotlinType) {
// Typealias case
typeArgument = localTypeArgument
typeArgumentSource = typeRef.source
} }
} else { } else {
typeArgument = type.typeArguments[index] as? ConeKotlinType typeArgument = type.typeArguments[index] as? ConeKotlinType
val argTypeRefSource = extractTypeRefAndSourceFromTypeArgument(typeRef, index) val typeArgumentRefAndSource = typeArgumentRefsAndSources?.elementAtOrNull(index)
if (argTypeRefSource != null) { if (typeArgumentRefAndSource != null) {
typeArgumentTypeRef = argTypeRefSource.first typeArgumentTypeRef = typeArgumentRefAndSource.typeRef
typeArgumentSource = argTypeRefSource.second typeArgumentSource = typeArgumentRefAndSource.source
} else {
val extractedTypeArgumentRefAndSource = extractArgumentTypeRefAndSource(typeRef, index)
if (extractedTypeArgumentRefAndSource != null) {
typeArgumentTypeRef = extractedTypeArgumentRefAndSource.typeRef
typeArgumentSource = extractedTypeArgumentRefAndSource.source
}
} }
} }
if (typeArgument != null && typeArgumentSource != null) { if (typeArgument != null && typeArgumentSource != null) {
val upperBound = getSubstitutedUpperBound(typeParameterSymbols[index], substitutor, typeSystemContext) if (!isIgnoreTypeParameters || (typeArgument.typeArguments.isEmpty() && typeArgument !is ConeTypeParameterType)) {
if (upperBound != null && !satisfiesBounds(upperBound, typeArgument.type, typeSystemContext)) { val intersection = typeSystemContext.intersectTypes(typeParameterSymbols[index].fir.bounds.map { it.coneType }) as? ConeKotlinType
reporter.reportOn(typeArgumentSource, FirErrors.UPPER_BOUND_VIOLATED, upperBound, context) if (intersection != null) {
val upperBound = substitutor.substituteOrSelf(intersection)
if (!AbstractTypeChecker.isSubtypeOf(typeSystemContext, typeArgument.type, upperBound, stubTypesEqualToAnything = false)) {
val factory =
if (isTypeAlias) FirErrors.UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION else FirErrors.UPPER_BOUND_VIOLATED
reporter.reportOn(typeArgumentSource, factory, upperBound, typeArgument.type, context)
if (isTypeAlias) {
return
}
}
}
} }
analyzeTypeParameters(typeArgumentTypeRef, context, reporter) checkUpperBoundViolated(typeArgumentTypeRef, context, reporter, isIgnoreTypeParameters = isIgnoreTypeParameters)
} }
} }
} }
private fun getSubstitutedUpperBound(
prototypeSymbol: FirTypeParameterSymbol,
substitutor: ConeSubstitutor,
typeSystemContext: ConeTypeContext
): ConeKotlinType? {
val intersection = typeSystemContext.intersectTypes(prototypeSymbol.fir.bounds.map { it.coneType }) as? ConeKotlinType ?: return null
return substitutor.substituteOrSelf(intersection)
}
private fun satisfiesBounds(upperBound: ConeKotlinType, target: ConeKotlinType, typeSystemContext: ConeTypeContext): Boolean {
return AbstractTypeChecker.isSubtypeOf(typeSystemContext, target, upperBound, stubTypesEqualToAnything = false)
}
@@ -340,6 +340,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_FEATU
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNUSED_VARIABLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNUSED_VARIABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_VIOLATED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_VIOLATED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USAGE_IS_NOT_INLINABLE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USAGE_IS_NOT_INLINABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_CAST import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_CAST
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_ELVIS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_ELVIS
@@ -649,7 +650,14 @@ class FirDefaultErrorMessages {
map.put(RECURSION_IN_IMPLICIT_TYPES, "Recursion in implicit types") map.put(RECURSION_IN_IMPLICIT_TYPES, "Recursion in implicit types")
map.put(INFERENCE_ERROR, "Inference error") map.put(INFERENCE_ERROR, "Inference error")
map.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties") map.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties")
map.put(UPPER_BOUND_VIOLATED, "Type argument is not within its bounds: should be subtype of ''{0}''", RENDER_TYPE) map.put(UPPER_BOUND_VIOLATED, "Type argument is not within its bounds: should be subtype of ''{0}''", RENDER_TYPE, RENDER_TYPE)
map.put(
UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION,
"Type argument is not within its bounds: should be subtype of ''{0}''",
RENDER_TYPE,
RENDER_TYPE
)
map.put(TYPE_ARGUMENTS_NOT_ALLOWED, "Type arguments are not allowed for type parameters") // * map.put(TYPE_ARGUMENTS_NOT_ALLOWED, "Type arguments are not allowed for type parameters") // *
map.put( map.put(
WRONG_NUMBER_OF_TYPE_ARGUMENTS, WRONG_NUMBER_OF_TYPE_ARGUMENTS,
@@ -22,6 +22,7 @@ abstract class AbstractConeSubstitutor(private val typeContext: ConeTypeContext)
is ConeStarProjection -> old is ConeStarProjection -> old
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(newType) is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(newType)
is ConeKotlinTypeProjectionOut -> ConeKotlinTypeProjectionOut(newType) is ConeKotlinTypeProjectionOut -> ConeKotlinTypeProjectionOut(newType)
is ConeKotlinTypeConflictingProjection -> ConeKotlinTypeConflictingProjection(newType)
is ConeKotlinType -> newType is ConeKotlinType -> newType
else -> old else -> old
} }
@@ -4,8 +4,8 @@ typealias N<T> = Num<T>
typealias N2<T> = N<T> typealias N2<T> = N<T>
val x1 = Num<<!UPPER_BOUND_VIOLATED!>String<!>>(<!ARGUMENT_TYPE_MISMATCH!>""<!>) val x1 = Num<<!UPPER_BOUND_VIOLATED!>String<!>>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)
val x2 = N<String>("") val x2 = N<<!UPPER_BOUND_VIOLATED!>String<!>>("")
val x3 = N2<String>("") val x3 = N2<<!UPPER_BOUND_VIOLATED!>String<!>>("")
class TColl<T, C : Collection<T>> class TColl<T, C : Collection<T>>
@@ -13,5 +13,5 @@ typealias TC<T, C> = TColl<T, C>
typealias TC2<T, C> = TC<T, C> typealias TC2<T, C> = TC<T, C>
val y1 = TColl<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>() val y1 = TColl<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>()
val y2 = TC<Any, Any>() val y2 = TC<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>()
val y3 = TC2<Any, Any>() val y3 = TC2<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>()
@@ -1,16 +0,0 @@
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
class TColl<T, C : Collection<T>>
typealias TC<T1, T2> = TColl<T1, T2>
typealias TC2<T1, T2> = TC<T1, T2>
fun test1(x: TC2<Number, Collection<Number>>) {}
fun test2(x: TC2<Number, Collection<Int>>) {}
fun test3(x: TC2<Number, List<Int>>) {}
fun test4(x: TC2<Number, List<Any>>) {}
val test5 = TC2<Number, Collection<Number>>()
val test6 = TC2<Number, Collection<Int>>()
val test7 = TC2<Number, List<Int>>()
val test8 = TC2<Number, List<Any>>()
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER // !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
class TColl<T, C : Collection<T>> class TColl<T, C : Collection<T>>
@@ -10,22 +10,22 @@ typealias MMMM<A3> = NL<A3>
typealias TC<T1, T2> = TColl<T1, T2> typealias TC<T1, T2> = TColl<T1, T2>
fun test1(x: NA<Int>) {} fun test1(x: NA<Int>) {}
fun test2(x: NA<Any>) {} fun test2(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>NA<Any><!>) {}
fun test3(x: NL<Int>) {} fun test3(x: NL<Int>) {}
fun test4(x: NL<Any>) {} fun test4(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>NL<Any><!>) {}
val test5 = NA<Int>() val test5 = NA<Int>()
val test6 = NA<Any>() val test6 = NA<<!UPPER_BOUND_VIOLATED!>Any<!>>()
val test7 = NL<Int>() val test7 = NL<Int>()
val test8 = MMMM<Int>() val test8 = MMMM<Int>()
val test9dwd = NL<Any>() val test9dwd = NL<<!UPPER_BOUND_VIOLATED!>Any<!>>()
fun test9(x: TC<Number, Collection<Number>>) {} fun test9(x: TC<Number, Collection<Number>>) {}
fun test10(x: TC<Number, Collection<Int>>) {} fun test10(x: TC<Number, Collection<Int>>) {}
fun test11(x: TC<Number, List<Int>>) {} fun test11(x: TC<Number, List<Int>>) {}
fun test12(x: TC<Number, List<Any>>) {} fun test12(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TC<Number, List<Any>><!>) {}
val test13 = TC<Number, Collection<Number>>() val test13 = TC<Number, Collection<Number>>()
val test14 = TC<Number, Collection<Int>>() val test14 = TC<Number, Collection<Int>>()
val test15 = TC<Number, List<Int>>() val test15 = TC<Number, List<Int>>()
val test16 = TC<Number, List<Any>>() val test16 = TC<Number, <!UPPER_BOUND_VIOLATED!>List<Any><!>>()
@@ -3,18 +3,18 @@
class TC<T, C : Collection<T>> class TC<T, C : Collection<T>>
typealias TCAlias<T, C> = TC<T, C> typealias TCAlias<T, C> = TC<T, C>
typealias TCAliasT<T> = TC<T, Any> typealias TCAliasT<T> = TC<T, <!UPPER_BOUND_VIOLATED!>Any<!>>
typealias TCAliasC<C> = TC<Any, C> typealias TCAliasC<C> = TC<Any, C>
typealias TCAliasT1<T> = TCAlias<T, Any> typealias TCAliasT1<T> = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAlias<T, Any><!>
typealias TCAliasC1<C> = TCAlias<Any, C> typealias TCAliasC1<C> = TCAlias<Any, C>
typealias Test1 = TC<Any, Any> typealias Test1 = TC<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>
typealias Test2 = TC<Any, Collection<Any>> typealias Test2 = TC<Any, Collection<Any>>
typealias Test3 = TCAlias<Any, Any> typealias Test3 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAlias<Any, Any><!>
typealias Test4 = TCAlias<Any, Collection<Any>> typealias Test4 = TCAlias<Any, Collection<Any>>
typealias Test5 = TCAliasT<Any> typealias Test5 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAliasT<Any><!>
typealias Test6 = TCAliasC<Any> typealias Test6 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAliasC<Any><!>
typealias Test7 = TCAliasC<Collection<Any>> typealias Test7 = TCAliasC<Collection<Any>>
typealias Test8 = TCAliasT1<Any> typealias Test8 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAliasT1<Any><!>
typealias Test9 = TCAliasC1<Any> typealias Test9 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAliasC1<Any><!>
typealias Test10 = TCAliasC1<Collection<Any>> typealias Test10 = TCAliasC1<Collection<Any>>
@@ -8,4 +8,4 @@ interface Num<T : Number>
typealias N<T> = Num<T> typealias N<T> = Num<T>
class Test2<T : N<String>> class Test2<T : <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>N<String><!>>
@@ -30,7 +30,7 @@ typealias N<T> = Num<T>
val testN0 = N("") val testN0 = N("")
val testN1 = N<Int>(1) val testN1 = N<Int>(1)
val testN1a = N<String>("") val testN1a = N<<!UPPER_BOUND_VIOLATED!>String<!>>("")
val testN2 = <!INAPPLICABLE_CANDIDATE!>N<!><Int, Int>(1) val testN2 = <!INAPPLICABLE_CANDIDATE!>N<!><Int, Int>(1)
class MyPair<T1 : CharSequence, T2 : Number>(val string: T1, val number: T2) class MyPair<T1 : CharSequence, T2 : Number>(val string: T1, val number: T2)
@@ -1230,6 +1230,15 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
add(FirErrors.UPPER_BOUND_VIOLATED) { firDiagnostic -> add(FirErrors.UPPER_BOUND_VIOLATED) { firDiagnostic ->
UpperBoundViolatedImpl( UpperBoundViolatedImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a), firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION) { firDiagnostic ->
UpperBoundViolatedInTypealiasExpansionImpl(
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.a),
firSymbolBuilder.typeBuilder.buildKtType(firDiagnostic.b),
firDiagnostic as FirPsiDiagnostic, firDiagnostic as FirPsiDiagnostic,
token, token,
) )
@@ -872,7 +872,14 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract class UpperBoundViolated : KtFirDiagnostic<PsiElement>() { abstract class UpperBoundViolated : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = UpperBoundViolated::class override val diagnosticClass get() = UpperBoundViolated::class
abstract val upperBound: KtType abstract val expectedUpperBound: KtType
abstract val actualUpperBound: KtType
}
abstract class UpperBoundViolatedInTypealiasExpansion : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = UpperBoundViolatedInTypealiasExpansion::class
abstract val expectedUpperBound: KtType
abstract val actualUpperBound: KtType
} }
abstract class TypeArgumentsNotAllowed : KtFirDiagnostic<PsiElement>() { abstract class TypeArgumentsNotAllowed : KtFirDiagnostic<PsiElement>() {
@@ -1403,13 +1403,23 @@ internal class ProjectionOnNonClassTypeArgumentImpl(
} }
internal class UpperBoundViolatedImpl( internal class UpperBoundViolatedImpl(
override val upperBound: KtType, override val expectedUpperBound: KtType,
override val actualUpperBound: KtType,
firDiagnostic: FirPsiDiagnostic, firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken, override val token: ValidityToken,
) : KtFirDiagnostic.UpperBoundViolated(), KtAbstractFirDiagnostic<PsiElement> { ) : KtFirDiagnostic.UpperBoundViolated(), KtAbstractFirDiagnostic<PsiElement> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
} }
internal class UpperBoundViolatedInTypealiasExpansionImpl(
override val expectedUpperBound: KtType,
override val actualUpperBound: KtType,
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.UpperBoundViolatedInTypealiasExpansion(), KtAbstractFirDiagnostic<PsiElement> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class TypeArgumentsNotAllowedImpl( internal class TypeArgumentsNotAllowedImpl(
firDiagnostic: FirPsiDiagnostic, firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken, override val token: ValidityToken,