[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, reporter: DiagnosticReporter,
isIgnoreTypeParameters: Boolean = false 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 if (notExpandedType.typeArguments.isEmpty()) return
val type = notExpandedType.fullyExpandedType(context.session) // If we have FirTypeRef information, add KtSourceElement information to each argument of the type and fully expand.
val isAbbreviatedType = notExpandedType !== type 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 val prototypeClassSymbol = type.lookupTag.toSymbol(context.session) as? FirRegularClassSymbol ?: return
@@ -51,29 +66,15 @@ fun checkUpperBoundViolated(
val substitution = typeParameterSymbols.zip(type.typeArguments).toMap() val substitution = typeParameterSymbols.zip(type.typeArguments).toMap()
val substitutor = FE10LikeConeSubstitutor(substitution, context.session) 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( return checkUpperBoundViolated(
context, reporter, typeParameterSymbols, typeArgumentsWithSourceInfo, substitutor, context, reporter, typeParameterSymbols, type.typeArguments.toList(), substitutor,
isAbbreviatedType, isReportExpansionError = true, isIgnoreTypeParameters,
isIgnoreTypeParameters,
) )
} }
private class FE10LikeConeSubstitutor( private class FE10LikeConeSubstitutor(
private val substitution: Map<FirTypeParameterSymbol, ConeTypeProjection>, private val substitution: Map<FirTypeParameterSymbol, ConeTypeProjection>,
private val useSiteSession: FirSession useSiteSession: FirSession
) : AbstractConeSubstitutor(useSiteSession.typeContext) { ) : AbstractConeSubstitutor(useSiteSession.typeContext) {
override fun substituteType(type: ConeKotlinType): ConeKotlinType? { override fun substituteType(type: ConeKotlinType): ConeKotlinType? {
if (type !is ConeTypeParameterType) return null 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>() private val ConeAttributes.originalProjection: OriginalProjectionTypeAttribute? by ConeAttributes.attributeAccessor<OriginalProjectionTypeAttribute>()
class TypeArgumentWithSourceInfo(
val coneTypeProjection: ConeTypeProjection,
val typeRef: FirTypeRef?,
val source: KtSourceElement?,
)
fun checkUpperBoundViolated( fun checkUpperBoundViolated(
context: CheckerContext, context: CheckerContext,
reporter: DiagnosticReporter, reporter: DiagnosticReporter,
typeParameters: List<FirTypeParameterSymbol>, typeParameters: List<FirTypeParameterSymbol>,
arguments: List<TypeArgumentWithSourceInfo>, typeArguments: List<ConeTypeProjection>,
substitutor: ConeSubstitutor, substitutor: ConeSubstitutor,
isAbbreviatedType: Boolean = false, isReportExpansionError: Boolean = false,
isIgnoreTypeParameters: Boolean = false isIgnoreTypeParameters: Boolean = false,
) { ) {
val count = minOf(typeParameters.size, arguments.size) val count = minOf(typeParameters.size, typeArguments.size)
val typeSystemContext = context.session.typeContext val typeSystemContext = context.session.typeContext
for (index in 0 until count) { for (index in 0 until count) {
val argument = arguments.getOrNull(index) ?: continue val argument = typeArguments[index]
val argumentType: ConeKotlinType? = argument.coneTypeProjection.type val argumentType = argument.type
val argumentTypeRef = argument.typeRef val sourceAttribute = argumentType?.attributes?.sourceAttribute
val argumentSource = argument.source val argumentTypeRef = sourceAttribute?.typeRef
val argumentSource = sourceAttribute?.source
if (argumentType != null && argumentSource != null) { if (argumentType != null && argumentSource != null) {
if (!isIgnoreTypeParameters || (argumentType.typeArguments.isEmpty() && argumentType !is ConeTypeParameterType)) { if (!isIgnoreTypeParameters || (argumentType.typeArguments.isEmpty() && argumentType !is ConeTypeParameterType)) {
@@ -172,17 +168,63 @@ fun checkUpperBoundViolated(
stubTypesEqualToAnything = true stubTypesEqualToAnything = true
) )
) { ) {
val factory = val factory = when {
if (isAbbreviatedType) FirErrors.UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION else FirErrors.UPPER_BOUND_VIOLATED isReportExpansionError && argumentTypeRef == null -> FirErrors.UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION
reporter.reportOn(argumentSource, factory, upperBound, argumentType.type, context) else -> FirErrors.UPPER_BOUND_VIOLATED
if (isAbbreviatedType) {
return
} }
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 package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter 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.checkUpperBoundViolated
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.withSource
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference
@@ -39,22 +40,23 @@ object FirUpperBoundViolatedExpressionChecker : FirQualifiedAccessExpressionChec
else -> null else -> null
} }
val typeArguments: List<TypeArgumentWithSourceInfo> val typeArguments: List<ConeTypeProjection>
val typeParameters: List<FirTypeParameterSymbol> val typeParameters: List<FirTypeParameterSymbol>
if (calleeSymbol is FirConstructorSymbol && calleeSymbol.isTypeAliasedConstructor) { if (calleeSymbol is FirConstructorSymbol && calleeSymbol.isTypeAliasedConstructor) {
val constructedType = expression.typeRef.coneType.fullyExpandedType(context.session) 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 { typeArguments = constructedType.typeArguments.map {
TypeArgumentWithSourceInfo(it, typeRef = null, expression.source) it.withSourceRecursive(expression)
} }
typeParameters = (constructedType.toSymbol(context.session) as? FirRegularClassSymbol)?.typeParameterSymbols ?: return typeParameters = (constructedType.toSymbol(context.session) as? FirRegularClassSymbol)?.typeParameterSymbols ?: return
} else { } else {
typeArguments = expression.typeArguments.map { firTypeProjection -> typeArguments = expression.typeArguments.map { firTypeProjection ->
TypeArgumentWithSourceInfo( firTypeProjection.toConeTypeProjection().withSource(
firTypeProjection.toConeTypeProjection(), FirTypeRefSource((firTypeProjection as? FirTypeProjectionWithVariance)?.typeRef, firTypeProjection.source)
(firTypeProjection as? FirTypeProjectionWithVariance)?.typeRef,
firTypeProjection.source
) )
} }
typeParameters = calleeSymbol?.typeParameterSymbols ?: return typeParameters = calleeSymbol?.typeParameterSymbols ?: return
@@ -62,14 +64,14 @@ object FirUpperBoundViolatedExpressionChecker : FirQualifiedAccessExpressionChec
// Neither common calls nor type alias constructor calls may contain projections // Neither common calls nor type alias constructor calls may contain projections
// That should be checked somewhere else // That should be checked somewhere else
if (typeArguments.any { it.coneTypeProjection !is ConeKotlinType }) { if (typeArguments.any { it !is ConeKotlinType }) {
return return
} }
if (typeArguments.size != typeParameters.size) return if (typeArguments.size != typeParameters.size) return
val substitutor = substitutorByMap( 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, context.session,
) )
@@ -81,4 +83,20 @@ object FirUpperBoundViolatedExpressionChecker : FirQualifiedAccessExpressionChec
substitutor, 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 Both<T, K> = TK<T, K>
typealias BothList<T, K> = List<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 O1 : One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>() // compiler error expected
object O2 : <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>Both<Any, Any><!>() object O2 : Both<<!UPPER_BOUND_VIOLATED!>Any<!>, <!UPPER_BOUND_VIOLATED!>Any<!>>()
class A1<T : <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>One<Any><!>> class A1<T : One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>>
class A2<T : <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>One<Any, Any><!>> class A2<T : One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>, Any>>
interface IO1 : OneList<Any> {} interface IO1 : OneList<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>> {}
interface IO2 : BothList<Any, Any> {} interface IO2 : BothList<<!UPPER_BOUND_VIOLATED!>Any<!>, <!UPPER_BOUND_VIOLATED!>Any<!>> {}
fun foo1(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>One<Any><!>) {} fun foo1(x: One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>) {}
fun foo2(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>Both<Any, Any><!>) {} fun foo2(x: Both<<!UPPER_BOUND_VIOLATED!>Any<!>, <!UPPER_BOUND_VIOLATED!>Any<!>>) {}
fun main() { fun main() {
<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>One<Any>()<!> One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>()
<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Both<Any, 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 Both<T, K> = TK<T, K>
typealias BothList<T, K> = List<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 O1 : One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>() // compiler error expected
object O2 : <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>Both<Any, Any><!>() object O2 : Both<<!UPPER_BOUND_VIOLATED!>Any<!>, <!UPPER_BOUND_VIOLATED!>Any<!>>()
class A1<T : <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>One<Any><!>> class A1<T : One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>>
class A2<T : <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>One<Any, Any><!>> class A2<T : One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>, Any>>
interface IO1 : OneList<Any> {} interface IO1 : OneList<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>> {}
interface IO2 : BothList<Any, Any> {} interface IO2 : BothList<<!UPPER_BOUND_VIOLATED!>Any<!>, <!UPPER_BOUND_VIOLATED!>Any<!>> {}
fun foo1(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>One<Any><!>) {} fun foo1(x: One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>) {}
fun foo2(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>Both<Any, Any><!>) {} fun foo2(x: Both<<!UPPER_BOUND_VIOLATED!>Any<!>, <!UPPER_BOUND_VIOLATED!>Any<!>>) {}
fun main() { fun main() {
<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>One<Any>()<!> One<<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Any<!>>()
<!UPPER_BOUND_VIOLATED, UPPER_BOUND_VIOLATED!>Both<Any, Any>()<!> Both<<!UPPER_BOUND_VIOLATED!>Any<!>, <!UPPER_BOUND_VIOLATED!>Any<!>>()
} }
@@ -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 = <!UPPER_BOUND_VIOLATED!>N<String>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)<!> val x2 = N<<!UPPER_BOUND_VIOLATED!>String<!>>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)
val x3 = <!UPPER_BOUND_VIOLATED!>N2<String>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)<!> val x3 = N2<<!UPPER_BOUND_VIOLATED!>String<!>>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)
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 = <!UPPER_BOUND_VIOLATED!>TC<Any, Any>()<!> val y2 = TC<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>()
val y3 = <!UPPER_BOUND_VIOLATED!>TC2<Any, 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 test1(x: TC2<Number, Collection<Number>>) {}
fun test2(x: TC2<Number, Collection<Int>>) {} fun test2(x: TC2<Number, Collection<Int>>) {}
fun test3(x: TC2<Number, List<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 test5 = TC2<Number, Collection<Number>>()
val test6 = TC2<Number, Collection<Int>>() val test6 = TC2<Number, Collection<Int>>()
val test7 = TC2<Number, List<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> typealias TC<T1, T2> = TColl<T1, T2>
fun test1(x: NA<Int>) {} 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 test3(x: NL<Int>) {}
fun test4(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>NL<Any><!>) {} fun test4(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>NL<Any><!>) {}
val test5 = NA<Int>() val test5 = NA<Int>()
val test6 = <!UPPER_BOUND_VIOLATED!>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 = <!UPPER_BOUND_VIOLATED!>NL<Any>()<!> 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 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: <!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 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 = <!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 TCAlias<T, C> = TC<T, C>
typealias TCAliasT<T> = TC<T, <!UPPER_BOUND_VIOLATED!>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> = <!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 TCAliasC1<C> = TCAlias<Any, C>
typealias Test1 = TC<Any, <!UPPER_BOUND_VIOLATED!>Any<!>> typealias Test1 = TC<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>
typealias Test2 = TC<Any, Collection<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 Test4 = TCAlias<Any, Collection<Any>>
typealias Test5 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAliasT<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 Test7 = TCAliasC<Collection<Any>>
typealias Test8 = <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TCAliasT1<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>> 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> interface Order<T>
typealias Ord<T> = Order<T> typealias Ord<T> = Order<T>
@@ -30,7 +30,7 @@ typealias N<T> = Num<T>
val testN0 = N(<!ARGUMENT_TYPE_MISMATCH!>""<!>) val testN0 = N(<!ARGUMENT_TYPE_MISMATCH!>""<!>)
val testN1 = N<Int>(1) 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) 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)
@@ -38,4 +38,4 @@ typealias MP<T1> = MyPair<String, T1>
val testMP0 = MP<Int>("", 1) val testMP0 = MP<Int>("", 1)
val testMP1 = MP(<!ARGUMENT_TYPE_MISMATCH!>1<!>, <!ARGUMENT_TYPE_MISMATCH!>""<!>) 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 A2<B> = Foo<MapLike<B, Int>>
typealias A3<C> = ListLike<List<C>> typealias A3<C> = ListLike<List<C>>
fun main1(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A<Int?><!>) {} fun main1(x: A<<!UPPER_BOUND_VIOLATED!>Int?<!>>) {}
fun main2(x: A2<Int?>) {} fun main2(x: A2<<!UPPER_BOUND_VIOLATED!>Int?<!>>) {}
fun main3(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!>) {} fun main3(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!>) {}
fun main3() { fun main3() {
val x = <!UPPER_BOUND_VIOLATED!>A3<Int?>()<!> // TODO: support reporting errors on typealias constructor calls 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?>()<!> 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 A2<B> = Foo<MapLike<B, Int>>
typealias A3<C> = ListLike<List<C>> typealias A3<C> = ListLike<List<C>>
fun main1(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A<Int?><!>) {} fun main1(x: A<<!UPPER_BOUND_VIOLATED!>Int?<!>>) {}
fun main2(x: A2<Int?>) {} fun main2(x: A2<<!UPPER_BOUND_VIOLATED!>Int?<!>>) {}
fun main3(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!>) {} fun main3(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!>) {}
fun main3() { fun main3() {
val x = <!UPPER_BOUND_VIOLATED!>A3<Int?>()<!> 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?>()<!> val y: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!> = <!UPPER_BOUND_VIOLATED!>A3<Int?>()<!>
} }