[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:
Brian Norman
2023-05-19 13:46:47 -05:00
committed by Space Team
parent d82a6f2fa2
commit b2230327df
13 changed files with 163 additions and 93 deletions
@@ -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))
}
}
}
@@ -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))
}
}
}
@@ -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<!>>()
}
@@ -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,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<!>>()
@@ -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><!>>()
@@ -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><!>>()
@@ -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>
@@ -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!>""<!>)
@@ -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?>()<!>
}
@@ -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?>()<!>
}