[FIR] Refactor upper bound validation with better source element info
Attach source information to each argument of the type before expanding to preserve information during validation. This allows errors to be reported on the original argument during nested type alias expansion. ^KT-50798 Fixed ^KT-50703 Fixed
This commit is contained in:
+83
-41
@@ -32,13 +32,28 @@ fun checkUpperBoundViolated(
|
||||
reporter: DiagnosticReporter,
|
||||
isIgnoreTypeParameters: Boolean = false
|
||||
) {
|
||||
val notExpandedType = typeRef?.coneTypeSafe<ConeClassLikeType>() ?: return
|
||||
val type = typeRef?.coneTypeSafe<ConeClassLikeType>() ?: return
|
||||
checkUpperBoundViolated(typeRef, type, context, reporter, isIgnoreTypeParameters)
|
||||
}
|
||||
|
||||
// Everything should be reported on the typealias expansion
|
||||
private fun checkUpperBoundViolated(
|
||||
typeRef: FirTypeRef?,
|
||||
notExpandedType: ConeClassLikeType,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter,
|
||||
isIgnoreTypeParameters: Boolean = false,
|
||||
) {
|
||||
if (notExpandedType.typeArguments.isEmpty()) return
|
||||
|
||||
val type = notExpandedType.fullyExpandedType(context.session)
|
||||
val isAbbreviatedType = notExpandedType !== type
|
||||
// If we have FirTypeRef information, add KtSourceElement information to each argument of the type and fully expand.
|
||||
val type = if (typeRef != null) {
|
||||
notExpandedType.fullyExpandedTypeWithSource(typeRef, context.session)
|
||||
// Add fallback source information to arguments of the expanded type.
|
||||
?.withArguments { it.withSource(FirTypeRefSource(null, typeRef.source)) }
|
||||
?: return
|
||||
} else {
|
||||
notExpandedType
|
||||
}
|
||||
|
||||
val prototypeClassSymbol = type.lookupTag.toSymbol(context.session) as? FirRegularClassSymbol ?: return
|
||||
|
||||
@@ -51,29 +66,15 @@ fun checkUpperBoundViolated(
|
||||
val substitution = typeParameterSymbols.zip(type.typeArguments).toMap()
|
||||
val substitutor = FE10LikeConeSubstitutor(substitution, context.session)
|
||||
|
||||
val typeRefAndSourcesForArguments = extractArgumentsTypeRefAndSource(typeRef) ?: return
|
||||
val typeArgumentsWithSourceInfo = type.typeArguments.withIndex().map { (index, projection) ->
|
||||
val (argTypeRef, source) =
|
||||
if (!isAbbreviatedType) {
|
||||
typeRefAndSourcesForArguments.getOrNull(index) ?: return
|
||||
} else {
|
||||
// For abbreviated arguments we use the whole typeRef as a place to report
|
||||
FirTypeRefSource(null, typeRef.source)
|
||||
}
|
||||
|
||||
TypeArgumentWithSourceInfo(projection, argTypeRef, source)
|
||||
}
|
||||
|
||||
return checkUpperBoundViolated(
|
||||
context, reporter, typeParameterSymbols, typeArgumentsWithSourceInfo, substitutor,
|
||||
isAbbreviatedType,
|
||||
isIgnoreTypeParameters,
|
||||
context, reporter, typeParameterSymbols, type.typeArguments.toList(), substitutor,
|
||||
isReportExpansionError = true, isIgnoreTypeParameters,
|
||||
)
|
||||
}
|
||||
|
||||
private class FE10LikeConeSubstitutor(
|
||||
private val substitution: Map<FirTypeParameterSymbol, ConeTypeProjection>,
|
||||
private val useSiteSession: FirSession
|
||||
useSiteSession: FirSession
|
||||
) : AbstractConeSubstitutor(useSiteSession.typeContext) {
|
||||
override fun substituteType(type: ConeKotlinType): ConeKotlinType? {
|
||||
if (type !is ConeTypeParameterType) return null
|
||||
@@ -135,29 +136,24 @@ private class OriginalProjectionTypeAttribute(val data: ConeTypeProjection) : Co
|
||||
|
||||
private val ConeAttributes.originalProjection: OriginalProjectionTypeAttribute? by ConeAttributes.attributeAccessor<OriginalProjectionTypeAttribute>()
|
||||
|
||||
class TypeArgumentWithSourceInfo(
|
||||
val coneTypeProjection: ConeTypeProjection,
|
||||
val typeRef: FirTypeRef?,
|
||||
val source: KtSourceElement?,
|
||||
)
|
||||
|
||||
fun checkUpperBoundViolated(
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter,
|
||||
typeParameters: List<FirTypeParameterSymbol>,
|
||||
arguments: List<TypeArgumentWithSourceInfo>,
|
||||
typeArguments: List<ConeTypeProjection>,
|
||||
substitutor: ConeSubstitutor,
|
||||
isAbbreviatedType: Boolean = false,
|
||||
isIgnoreTypeParameters: Boolean = false
|
||||
isReportExpansionError: Boolean = false,
|
||||
isIgnoreTypeParameters: Boolean = false,
|
||||
) {
|
||||
val count = minOf(typeParameters.size, arguments.size)
|
||||
val count = minOf(typeParameters.size, typeArguments.size)
|
||||
val typeSystemContext = context.session.typeContext
|
||||
|
||||
for (index in 0 until count) {
|
||||
val argument = arguments.getOrNull(index) ?: continue
|
||||
val argumentType: ConeKotlinType? = argument.coneTypeProjection.type
|
||||
val argumentTypeRef = argument.typeRef
|
||||
val argumentSource = argument.source
|
||||
val argument = typeArguments[index]
|
||||
val argumentType = argument.type
|
||||
val sourceAttribute = argumentType?.attributes?.sourceAttribute
|
||||
val argumentTypeRef = sourceAttribute?.typeRef
|
||||
val argumentSource = sourceAttribute?.source
|
||||
|
||||
if (argumentType != null && argumentSource != null) {
|
||||
if (!isIgnoreTypeParameters || (argumentType.typeArguments.isEmpty() && argumentType !is ConeTypeParameterType)) {
|
||||
@@ -172,17 +168,63 @@ fun checkUpperBoundViolated(
|
||||
stubTypesEqualToAnything = true
|
||||
)
|
||||
) {
|
||||
val factory =
|
||||
if (isAbbreviatedType) FirErrors.UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION else FirErrors.UPPER_BOUND_VIOLATED
|
||||
reporter.reportOn(argumentSource, factory, upperBound, argumentType.type, context)
|
||||
if (isAbbreviatedType) {
|
||||
return
|
||||
val factory = when {
|
||||
isReportExpansionError && argumentTypeRef == null -> FirErrors.UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION
|
||||
else -> FirErrors.UPPER_BOUND_VIOLATED
|
||||
}
|
||||
reporter.reportOn(argumentSource, factory, upperBound, argumentType.type, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkUpperBoundViolated(argumentTypeRef, context, reporter, isIgnoreTypeParameters = isIgnoreTypeParameters)
|
||||
if (argumentType is ConeClassLikeType) {
|
||||
checkUpperBoundViolated(argumentTypeRef, argumentType, context, reporter, isIgnoreTypeParameters)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun ConeClassLikeType.fullyExpandedTypeWithSource(
|
||||
typeRef: FirTypeRef,
|
||||
useSiteSession: FirSession,
|
||||
): ConeClassLikeType? {
|
||||
val typeRefAndSourcesForArguments = extractArgumentsTypeRefAndSource(typeRef) ?: return null
|
||||
// Avoid issues with nested type aliases and context receivers on function types as source information isn't returned.
|
||||
if (typeRefAndSourcesForArguments.size != typeArguments.size) return null
|
||||
|
||||
// Add source information to arguments of non-expanded type, which is preserved during expansion.
|
||||
val typeArguments =
|
||||
typeArguments.zip(typeRefAndSourcesForArguments) { projection, source -> projection.withSource(source) }
|
||||
.toTypedArray()
|
||||
|
||||
return withArguments(typeArguments).fullyExpandedType(useSiteSession)
|
||||
}
|
||||
|
||||
private class SourceAttribute(private val data: FirTypeRefSource) : ConeAttribute<SourceAttribute>() {
|
||||
val source: KtSourceElement? get() = data.source
|
||||
val typeRef: FirTypeRef? get() = data.typeRef
|
||||
|
||||
override fun union(other: SourceAttribute?): SourceAttribute = other ?: this
|
||||
override fun intersect(other: SourceAttribute?): SourceAttribute = other ?: this
|
||||
override fun add(other: SourceAttribute?): SourceAttribute = other ?: this
|
||||
|
||||
override fun isSubtypeOf(other: SourceAttribute?): Boolean = true
|
||||
|
||||
override fun toString() = "SourceAttribute: $data"
|
||||
|
||||
override val key: KClass<out SourceAttribute>
|
||||
get() = SourceAttribute::class
|
||||
}
|
||||
|
||||
private val ConeAttributes.sourceAttribute: SourceAttribute? by ConeAttributes.attributeAccessor<SourceAttribute>()
|
||||
|
||||
fun ConeTypeProjection.withSource(source: FirTypeRefSource?): ConeTypeProjection {
|
||||
return when {
|
||||
source == null || this !is ConeKotlinTypeProjection -> this
|
||||
else -> {
|
||||
// Prefer existing source information.
|
||||
val attributes = ConeAttributes.create(listOf(SourceAttribute(source))).add(type.attributes)
|
||||
replaceType(type.withAttributes(attributes))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+27
-9
@@ -6,9 +6,10 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.TypeArgumentWithSourceInfo
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.FirTypeRefSource
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.checkUpperBoundViolated
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.withSource
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
|
||||
@@ -39,22 +40,23 @@ object FirUpperBoundViolatedExpressionChecker : FirQualifiedAccessExpressionChec
|
||||
else -> null
|
||||
}
|
||||
|
||||
val typeArguments: List<TypeArgumentWithSourceInfo>
|
||||
val typeArguments: List<ConeTypeProjection>
|
||||
val typeParameters: List<FirTypeParameterSymbol>
|
||||
|
||||
if (calleeSymbol is FirConstructorSymbol && calleeSymbol.isTypeAliasedConstructor) {
|
||||
val constructedType = expression.typeRef.coneType.fullyExpandedType(context.session)
|
||||
// Updating arguments with source information after expanding the type seems extremely brittle as it relies on identity equality
|
||||
// of the expression type arguments and the expanded type arguments. This cannot be applied before expanding the type because it
|
||||
// seems like the type is already expended.
|
||||
typeArguments = constructedType.typeArguments.map {
|
||||
TypeArgumentWithSourceInfo(it, typeRef = null, expression.source)
|
||||
it.withSourceRecursive(expression)
|
||||
}
|
||||
|
||||
typeParameters = (constructedType.toSymbol(context.session) as? FirRegularClassSymbol)?.typeParameterSymbols ?: return
|
||||
} else {
|
||||
typeArguments = expression.typeArguments.map { firTypeProjection ->
|
||||
TypeArgumentWithSourceInfo(
|
||||
firTypeProjection.toConeTypeProjection(),
|
||||
(firTypeProjection as? FirTypeProjectionWithVariance)?.typeRef,
|
||||
firTypeProjection.source
|
||||
firTypeProjection.toConeTypeProjection().withSource(
|
||||
FirTypeRefSource((firTypeProjection as? FirTypeProjectionWithVariance)?.typeRef, firTypeProjection.source)
|
||||
)
|
||||
}
|
||||
typeParameters = calleeSymbol?.typeParameterSymbols ?: return
|
||||
@@ -62,14 +64,14 @@ object FirUpperBoundViolatedExpressionChecker : FirQualifiedAccessExpressionChec
|
||||
|
||||
// Neither common calls nor type alias constructor calls may contain projections
|
||||
// That should be checked somewhere else
|
||||
if (typeArguments.any { it.coneTypeProjection !is ConeKotlinType }) {
|
||||
if (typeArguments.any { it !is ConeKotlinType }) {
|
||||
return
|
||||
}
|
||||
|
||||
if (typeArguments.size != typeParameters.size) return
|
||||
|
||||
val substitutor = substitutorByMap(
|
||||
typeParameters.withIndex().associate { Pair(it.value, typeArguments[it.index].coneTypeProjection as ConeKotlinType) },
|
||||
typeParameters.withIndex().associate { Pair(it.value, typeArguments[it.index] as ConeKotlinType) },
|
||||
context.session,
|
||||
)
|
||||
|
||||
@@ -81,4 +83,20 @@ object FirUpperBoundViolatedExpressionChecker : FirQualifiedAccessExpressionChec
|
||||
substitutor,
|
||||
)
|
||||
}
|
||||
|
||||
private fun ConeTypeProjection.withSourceRecursive(expression: FirQualifiedAccessExpression): ConeTypeProjection {
|
||||
// Recursively apply source to any arguments of this type.
|
||||
val type = when {
|
||||
this is ConeClassLikeType && typeArguments.isNotEmpty() -> withArguments { it.withSourceRecursive(expression) }
|
||||
else -> this
|
||||
}
|
||||
|
||||
// Try to match the expanded type arguments back to the original expression type arguments.
|
||||
return when (val argument = expression.typeArguments.find { it.toConeTypeProjection() === this }) {
|
||||
// Unable to find a matching argument, fall back to marking the entire expression.
|
||||
null -> type.withSource(FirTypeRefSource(null, expression.source))
|
||||
// Found the original argument!
|
||||
else -> type.withSource(FirTypeRefSource((argument as? FirTypeProjectionWithVariance)?.typeRef, argument.source))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -9,19 +9,19 @@ typealias OneList<X> = List<TK<X, X>>
|
||||
typealias Both<T, K> = TK<T, K>
|
||||
typealias BothList<T, K> = List<TK<T, K>>
|
||||
|
||||
object O1 : <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>One<Any><!>() // compiler error expected
|
||||
object O2 : <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>Both<Any, Any><!>()
|
||||
object O1 : One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>() // compiler error expected
|
||||
object O2 : Both<<!UPPER_BOUND_VIOLATED!>Any<!>, <!UPPER_BOUND_VIOLATED!>Any<!>>()
|
||||
|
||||
class A1<T : <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>One<Any><!>>
|
||||
class A2<T : <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>One<Any, Any><!>>
|
||||
class A1<T : One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>>
|
||||
class A2<T : One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>, Any>>
|
||||
|
||||
interface IO1 : OneList<Any> {}
|
||||
interface IO2 : BothList<Any, Any> {}
|
||||
interface IO1 : OneList<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>> {}
|
||||
interface IO2 : BothList<<!UPPER_BOUND_VIOLATED!>Any<!>, <!UPPER_BOUND_VIOLATED!>Any<!>> {}
|
||||
|
||||
fun foo1(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>One<Any><!>) {}
|
||||
fun foo2(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>Both<Any, Any><!>) {}
|
||||
fun foo1(x: One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>) {}
|
||||
fun foo2(x: Both<<!UPPER_BOUND_VIOLATED!>Any<!>, <!UPPER_BOUND_VIOLATED!>Any<!>>) {}
|
||||
|
||||
fun main() {
|
||||
<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>One<Any>()<!>
|
||||
<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Both<Any, Any>()<!>
|
||||
One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>()
|
||||
Both<<!UPPER_BOUND_VIOLATED!>Any<!>, <!UPPER_BOUND_VIOLATED!>Any<!>>()
|
||||
}
|
||||
|
||||
+10
-10
@@ -9,19 +9,19 @@ typealias OneList<X> = List<TK<X, X>>
|
||||
typealias Both<T, K> = TK<T, K>
|
||||
typealias BothList<T, K> = List<TK<T, K>>
|
||||
|
||||
object O1 : <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>One<Any><!>() // compiler error expected
|
||||
object O2 : <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>Both<Any, Any><!>()
|
||||
object O1 : One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>() // compiler error expected
|
||||
object O2 : Both<<!UPPER_BOUND_VIOLATED!>Any<!>, <!UPPER_BOUND_VIOLATED!>Any<!>>()
|
||||
|
||||
class A1<T : <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>One<Any><!>>
|
||||
class A2<T : <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>One<Any, Any><!>>
|
||||
class A1<T : One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>>
|
||||
class A2<T : One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>, Any>>
|
||||
|
||||
interface IO1 : OneList<Any> {}
|
||||
interface IO2 : BothList<Any, Any> {}
|
||||
interface IO1 : OneList<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>> {}
|
||||
interface IO2 : BothList<<!UPPER_BOUND_VIOLATED!>Any<!>, <!UPPER_BOUND_VIOLATED!>Any<!>> {}
|
||||
|
||||
fun foo1(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>One<Any><!>) {}
|
||||
fun foo2(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>Both<Any, Any><!>) {}
|
||||
fun foo1(x: One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>) {}
|
||||
fun foo2(x: Both<<!UPPER_BOUND_VIOLATED!>Any<!>, <!UPPER_BOUND_VIOLATED!>Any<!>>) {}
|
||||
|
||||
fun main() {
|
||||
<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>One<Any>()<!>
|
||||
<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Both<Any, Any>()<!>
|
||||
One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>()
|
||||
Both<<!UPPER_BOUND_VIOLATED!>Any<!>, <!UPPER_BOUND_VIOLATED!>Any<!>>()
|
||||
}
|
||||
|
||||
+4
-4
@@ -4,8 +4,8 @@ typealias N<T> = Num<T>
|
||||
typealias N2<T> = N<T>
|
||||
|
||||
val x1 = Num<<!UPPER_BOUND_VIOLATED!>String<!>>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)
|
||||
val x2 = <!UPPER_BOUND_VIOLATED!>N<String>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)<!>
|
||||
val x3 = <!UPPER_BOUND_VIOLATED!>N2<String>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)<!>
|
||||
val x2 = N<<!UPPER_BOUND_VIOLATED!>String<!>>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)
|
||||
val x3 = N2<<!UPPER_BOUND_VIOLATED!>String<!>>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)
|
||||
|
||||
class TColl<T, C : Collection<T>>
|
||||
|
||||
@@ -13,5 +13,5 @@ typealias TC<T, C> = TColl<T, C>
|
||||
typealias TC2<T, C> = TC<T, C>
|
||||
|
||||
val y1 = TColl<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>()
|
||||
val y2 = <!UPPER_BOUND_VIOLATED!>TC<Any, Any>()<!>
|
||||
val y3 = <!UPPER_BOUND_VIOLATED!>TC2<Any, Any>()<!>
|
||||
val y2 = TC<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>()
|
||||
val y3 = TC2<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>()
|
||||
|
||||
Vendored
+2
-2
@@ -8,9 +8,9 @@ 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: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TC2<Number, List<Any>><!>) {}
|
||||
fun test4(x: TC2<Number, <!UPPER_BOUND_VIOLATED!>List<Any><!>>) {}
|
||||
|
||||
val test5 = TC2<Number, Collection<Number>>()
|
||||
val test6 = TC2<Number, Collection<Int>>()
|
||||
val test7 = TC2<Number, List<Int>>()
|
||||
val test8 = <!UPPER_BOUND_VIOLATED!>TC2<Number, List<Any>>()<!>
|
||||
val test8 = TC2<Number, <!UPPER_BOUND_VIOLATED!>List<Any><!>>()
|
||||
|
||||
+4
-4
@@ -10,12 +10,12 @@ typealias MMMM<A3> = NL<A3>
|
||||
typealias TC<T1, T2> = TColl<T1, T2>
|
||||
|
||||
fun test1(x: NA<Int>) {}
|
||||
fun test2(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>NA<Any><!>) {}
|
||||
fun test2(x: NA<<!UPPER_BOUND_VIOLATED!>Any<!>>) {}
|
||||
fun test3(x: NL<Int>) {}
|
||||
fun test4(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>NL<Any><!>) {}
|
||||
|
||||
val test5 = NA<Int>()
|
||||
val test6 = <!UPPER_BOUND_VIOLATED!>NA<Any>()<!>
|
||||
val test6 = NA<<!UPPER_BOUND_VIOLATED!>Any<!>>()
|
||||
val test7 = NL<Int>()
|
||||
val test8 = MMMM<Int>()
|
||||
val test9dwd = <!UPPER_BOUND_VIOLATED!>NL<Any>()<!>
|
||||
@@ -23,9 +23,9 @@ val test9dwd = <!UPPER_BOUND_VIOLATED!>NL<Any>()<!>
|
||||
fun test9(x: TC<Number, Collection<Number>>) {}
|
||||
fun test10(x: TC<Number, Collection<Int>>) {}
|
||||
fun test11(x: TC<Number, List<Int>>) {}
|
||||
fun test12(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TC<Number, List<Any>><!>) {}
|
||||
fun test12(x: TC<Number, <!UPPER_BOUND_VIOLATED!>List<Any><!>>) {}
|
||||
|
||||
val test13 = TC<Number, Collection<Number>>()
|
||||
val test14 = TC<Number, Collection<Int>>()
|
||||
val test15 = TC<Number, List<Int>>()
|
||||
val test16 = <!UPPER_BOUND_VIOLATED!>TC<Number, List<Any>>()<!>
|
||||
val test16 = TC<Number, <!UPPER_BOUND_VIOLATED!>List<Any><!>>()
|
||||
|
||||
+4
-4
@@ -5,16 +5,16 @@ class TC<T, C : Collection<T>>
|
||||
typealias TCAlias<T, C> = TC<T, C>
|
||||
typealias TCAliasT<T> = TC<T, <!UPPER_BOUND_VIOLATED!>Any<!>>
|
||||
typealias TCAliasC<C> = TC<Any, C>
|
||||
typealias TCAliasT1<T> = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAlias<T, Any><!>
|
||||
typealias TCAliasT1<T> = TCAlias<T, <!UPPER_BOUND_VIOLATED!>Any<!>>
|
||||
typealias TCAliasC1<C> = TCAlias<Any, C>
|
||||
|
||||
typealias Test1 = TC<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>
|
||||
typealias Test2 = TC<Any, Collection<Any>>
|
||||
typealias Test3 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAlias<Any, Any><!>
|
||||
typealias Test3 = TCAlias<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>
|
||||
typealias Test4 = TCAlias<Any, Collection<Any>>
|
||||
typealias Test5 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAliasT<Any><!>
|
||||
typealias Test6 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAliasC<Any><!>
|
||||
typealias Test6 = TCAliasC<<!UPPER_BOUND_VIOLATED!>Any<!>>
|
||||
typealias Test7 = TCAliasC<Collection<Any>>
|
||||
typealias Test8 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAliasT1<Any><!>
|
||||
typealias Test9 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAliasC1<Any><!>
|
||||
typealias Test9 = TCAliasC1<<!UPPER_BOUND_VIOLATED!>Any<!>>
|
||||
typealias Test10 = TCAliasC1<Collection<Any>>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
interface Order<T>
|
||||
|
||||
typealias Ord<T> = Order<T>
|
||||
|
||||
class Test1<T1 : Ord<T1>>
|
||||
|
||||
interface Num<T : Number>
|
||||
|
||||
typealias N<T> = Num<T>
|
||||
|
||||
class Test2<T : N<<!UPPER_BOUND_VIOLATED!>String<!>>>
|
||||
@@ -1,4 +1,3 @@
|
||||
// FIR_IDENTICAL
|
||||
interface Order<T>
|
||||
|
||||
typealias Ord<T> = Order<T>
|
||||
|
||||
Vendored
+2
-2
@@ -30,7 +30,7 @@ typealias N<T> = Num<T>
|
||||
|
||||
val testN0 = N(<!ARGUMENT_TYPE_MISMATCH!>""<!>)
|
||||
val testN1 = N<Int>(1)
|
||||
val testN1a = <!UPPER_BOUND_VIOLATED!>N<String>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)<!>
|
||||
val testN1a = N<<!UPPER_BOUND_VIOLATED!>String<!>>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)
|
||||
val testN2 = <!INAPPLICABLE_CANDIDATE!>N<!><Int, Int>(1)
|
||||
|
||||
class MyPair<T1 : CharSequence, T2 : Number>(val string: T1, val number: T2)
|
||||
@@ -38,4 +38,4 @@ typealias MP<T1> = MyPair<String, T1>
|
||||
|
||||
val testMP0 = MP<Int>("", 1)
|
||||
val testMP1 = MP(<!ARGUMENT_TYPE_MISMATCH!>1<!>, <!ARGUMENT_TYPE_MISMATCH!>""<!>)
|
||||
val testMP2 = <!UPPER_BOUND_VIOLATED!>MP<String>(<!ARGUMENT_TYPE_MISMATCH!>""<!>, <!ARGUMENT_TYPE_MISMATCH!>""<!>)<!>
|
||||
val testMP2 = MP<<!UPPER_BOUND_VIOLATED!>String<!>>(<!ARGUMENT_TYPE_MISMATCH!>""<!>, <!ARGUMENT_TYPE_MISMATCH!>""<!>)
|
||||
|
||||
+3
-3
@@ -27,11 +27,11 @@ typealias A<A> = MapLike<A, Int>
|
||||
typealias A2<B> = Foo<MapLike<B, Int>>
|
||||
typealias A3<C> = ListLike<List<C>>
|
||||
|
||||
fun main1(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A<Int?><!>) {}
|
||||
fun main2(x: A2<Int?>) {}
|
||||
fun main1(x: A<<!UPPER_BOUND_VIOLATED!>Int?<!>>) {}
|
||||
fun main2(x: A2<<!UPPER_BOUND_VIOLATED!>Int?<!>>) {}
|
||||
fun main3(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!>) {}
|
||||
fun main3() {
|
||||
val x = <!UPPER_BOUND_VIOLATED!>A3<Int?>()<!> // TODO: support reporting errors on typealias constructor calls
|
||||
val x2 = <!UPPER_BOUND_VIOLATED!>A<Int?>()<!> // TODO: support reporting errors on typealias constructor calls
|
||||
val x2 = A<<!UPPER_BOUND_VIOLATED!>Int?<!>>() // TODO: support reporting errors on typealias constructor calls
|
||||
val y: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!> = <!UPPER_BOUND_VIOLATED!>A3<Int?>()<!>
|
||||
}
|
||||
|
||||
+3
-3
@@ -27,11 +27,11 @@ typealias A<A> = MapLike<A, Int>
|
||||
typealias A2<B> = Foo<MapLike<B, Int>>
|
||||
typealias A3<C> = ListLike<List<C>>
|
||||
|
||||
fun main1(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A<Int?><!>) {}
|
||||
fun main2(x: A2<Int?>) {}
|
||||
fun main1(x: A<<!UPPER_BOUND_VIOLATED!>Int?<!>>) {}
|
||||
fun main2(x: A2<<!UPPER_BOUND_VIOLATED!>Int?<!>>) {}
|
||||
fun main3(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!>) {}
|
||||
fun main3() {
|
||||
val x = <!UPPER_BOUND_VIOLATED!>A3<Int?>()<!>
|
||||
val x2 = <!UPPER_BOUND_VIOLATED!>A<Int?>()<!>
|
||||
val x2 = A<<!UPPER_BOUND_VIOLATED!>Int?<!>>()
|
||||
val y: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!> = <!UPPER_BOUND_VIOLATED!>A3<Int?>()<!>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user