FIR: Refactor checkUpperBoundViolated

There just should be a different facades for cases
A<T1, T2> and foo<T1, T2>()

Test data has changed for type alias constructors since previously,
it was working by mistake because of assumption that type alias arguments
are linearly mapped to the type parameters of the corresponding constructors

^KT-50703 Open
This commit is contained in:
Denis.Zharkov
2021-12-20 12:55:28 +03:00
committed by teamcity
parent c2f03b4d28
commit b193e708d3
10 changed files with 131 additions and 127 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<<!UPPER_BOUND_VIOLATED!>String<!>>() val test8 = <!UPPER_BOUND_VIOLATED!>NL<String>()<!>
class NumberPhile<T: Number>(x: T) class NumberPhile<T: Number>(x: T)
val np1 = NumberPhile(10) val np1 = NumberPhile(10)
@@ -6,11 +6,12 @@
package org.jetbrains.kotlin.fir.analysis.checkers package org.jetbrains.kotlin.fir.analysis.checkers
import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.diagnostics.reportOn
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
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.FirRegularClassSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
@@ -20,142 +21,112 @@ import org.jetbrains.kotlin.types.AbstractTypeChecker
/** /**
* 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
*/ */
fun checkUpperBoundViolated( fun checkUpperBoundViolated(
typeRef: FirTypeRef?, typeRef: FirTypeRef?,
context: CheckerContext, context: CheckerContext,
reporter: DiagnosticReporter, reporter: DiagnosticReporter,
typeParameters: List<FirTypeParameterSymbol>? = null,
typeArguments: List<Any>? = null,
typeArgumentRefsAndSources: List<FirTypeRefSource?>? = null,
isTypeAlias: Boolean = false,
isIgnoreTypeParameters: Boolean = false isIgnoreTypeParameters: Boolean = false
) { ) {
require(typeArguments == null || typeArgumentRefsAndSources == null) { val notExpandedType = typeRef?.coneTypeSafe<ConeClassLikeType>() ?: return
"Only one of those arguments can be not null"
}
val type = typeRef?.coneTypeSafe<ConeKotlinType>() ?: return // Everything should be reported on the typealias expansion
if (notExpandedType.typeArguments.isEmpty()) return
val typeArgumentsCount = typeArguments?.size ?: type.typeArguments.size val type = notExpandedType.fullyExpandedType(context.session)
if (typeArgumentsCount == 0) { val isAbbreviatedType = notExpandedType !== type
return
}
val typeParameterSymbols = typeParameters val prototypeClassSymbol = type.lookupTag.toSymbol(context.session) as? FirRegularClassSymbol ?: return
?: if (type is ConeClassLikeType) {
val fullyExpandedType = type.fullyExpandedType(context.session)
val prototypeClassSymbol = fullyExpandedType.lookupTag.toSymbol(context.session) as? FirRegularClassSymbol ?: return
if (type != fullyExpandedType) {
// special check for type aliases
checkUpperBoundViolated(
typeRef,
context,
reporter,
prototypeClassSymbol.typeParameterSymbols,
fullyExpandedType.typeArguments.toList(),
null,
isTypeAlias = true,
isIgnoreTypeParameters = isIgnoreTypeParameters
)
return
}
prototypeClassSymbol.typeParameterSymbols val typeParameterSymbols = prototypeClassSymbol.typeParameterSymbols
} else {
listOf()
}
if (typeParameterSymbols.isEmpty()) { if (typeParameterSymbols.isEmpty()) {
return return
} }
val count = minOf(typeParameterSymbols.size, typeArgumentsCount) val count = minOf(typeParameterSymbols.size, type.typeArguments.size)
val substitution = mutableMapOf<FirTypeParameterSymbol, ConeKotlinType>() val substitution = mutableMapOf<FirTypeParameterSymbol, ConeKotlinType>()
for (index in 0 until count) { for (index in 0 until count) {
val typeArgument = typeArguments?.elementAt(index) ?: type.typeArguments[index] val typeArgument = type.typeArguments[index]
val typeParameterSymbol = typeParameterSymbols[index] val typeParameterSymbol = typeParameterSymbols[index]
if (typeArgument is FirTypeProjectionWithVariance) { val typeArgumentType = typeArgument.type
substitution[typeParameterSymbol] = typeArgument.typeRef.coneType if (typeArgumentType != null) {
} else if (typeArgument is ConeKotlinType) { substitution[typeParameterSymbol] = typeArgumentType
substitution[typeParameterSymbol] = typeArgument.type } else {
} else if (typeArgument is ConeTypeProjection) { substitution[typeParameterSymbol] =
val typeArgumentType = typeArgument.type ConeStubTypeForTypeVariableInSubtyping(ConeTypeVariable("", typeParameterSymbol.toLookupTag()), ConeNullability.NOT_NULL)
if (typeArgumentType != null) {
substitution[typeParameterSymbol] = typeArgumentType
} else {
substitution[typeParameterSymbol] =
ConeStubTypeForTypeVariableInSubtyping(ConeTypeVariable("", typeParameterSymbol.toLookupTag()), ConeNullability.NOT_NULL)
}
} }
} }
val substitutor = substitutorByMap(substitution, context.session) val substitutor = substitutorByMap(substitution, context.session)
val typeArgumentsWithSourceInfo = type.typeArguments.withIndex().map { (index, projection) ->
val (argTypeRef, source) =
if (!isAbbreviatedType)
extractArgumentTypeRefAndSource(typeRef, 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,
)
}
class TypeArgumentWithSourceInfo(
val coneTypeProjection: ConeTypeProjection,
val typeRef: FirTypeRef?,
val source: KtSourceElement?,
)
fun checkUpperBoundViolated(
context: CheckerContext,
reporter: DiagnosticReporter,
typeParameters: List<FirTypeParameterSymbol>,
arguments: List<TypeArgumentWithSourceInfo>,
substitutor: ConeSubstitutor,
isAbbreviatedType: Boolean = false,
isIgnoreTypeParameters: Boolean = false
) {
val count = minOf(typeParameters.size, arguments.size)
val typeSystemContext = context.session.typeContext val typeSystemContext = context.session.typeContext
for (index in 0 until count) { for (index in 0 until count) {
var typeArgument: ConeKotlinType? = null val argument = arguments.getOrNull(index) ?: continue
var typeArgumentTypeRef: FirTypeRef? = null val argumentType: ConeKotlinType? = argument.coneTypeProjection.type
var typeArgumentSource: KtSourceElement? = null val argumentTypeRef = argument.typeRef
val argumentSource = argument.source
if (typeArguments != null) { if (argumentType != null && argumentSource != null) {
val localTypeArgument = typeArguments[index] if (!isIgnoreTypeParameters || (argumentType.typeArguments.isEmpty() && argumentType !is ConeTypeParameterType)) {
if (localTypeArgument is FirTypeProjectionWithVariance) {
typeArgumentTypeRef = localTypeArgument.typeRef
typeArgument = typeArgumentTypeRef.coneType
typeArgumentSource = localTypeArgument.source
} else if (localTypeArgument is ConeKotlinType) {
// Typealias case
typeArgument = localTypeArgument
typeArgumentSource = typeRef.source
}
} else {
val localTypeArgument = type.typeArguments[index]
if (localTypeArgument is ConeKotlinType) {
typeArgument = localTypeArgument
} else if (localTypeArgument is ConeKotlinTypeProjection) {
typeArgument = localTypeArgument.type
}
val typeArgumentRefAndSource = typeArgumentRefsAndSources?.elementAtOrNull(index)
if (typeArgumentRefAndSource != null) {
typeArgumentTypeRef = typeArgumentRefAndSource.typeRef
typeArgumentSource = typeArgumentRefAndSource.source
} else {
val extractedTypeArgumentRefAndSource = extractArgumentTypeRefAndSource(typeRef, index)
if (extractedTypeArgumentRefAndSource != null) {
typeArgumentTypeRef = extractedTypeArgumentRefAndSource.typeRef
typeArgumentSource = extractedTypeArgumentRefAndSource.source
}
}
}
if (typeArgument != null && typeArgumentSource != null) {
if (!isIgnoreTypeParameters || (typeArgument.typeArguments.isEmpty() && typeArgument !is ConeTypeParameterType)) {
val intersection = val intersection =
typeSystemContext.intersectTypes(typeParameterSymbols[index].resolvedBounds.map { it.coneType }) as? ConeKotlinType typeSystemContext.intersectTypes(typeParameters[index].resolvedBounds.map { it.coneType }) as? ConeKotlinType
if (intersection != null) { if (intersection != null) {
val upperBound = substitutor.substituteOrSelf(intersection) val upperBound = substitutor.substituteOrSelf(intersection)
if (!AbstractTypeChecker.isSubtypeOf( if (!AbstractTypeChecker.isSubtypeOf(
typeSystemContext, typeSystemContext,
typeArgument.type, argumentType,
upperBound, upperBound,
stubTypesEqualToAnything = true stubTypesEqualToAnything = true
) )
) { ) {
val factory = val factory =
if (isTypeAlias) FirErrors.UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION else FirErrors.UPPER_BOUND_VIOLATED if (isAbbreviatedType) FirErrors.UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION else FirErrors.UPPER_BOUND_VIOLATED
reporter.reportOn(typeArgumentSource, factory, upperBound, typeArgument.type, context) reporter.reportOn(argumentSource, factory, upperBound, argumentType.type, context)
if (isTypeAlias) { if (isAbbreviatedType) {
return return
} }
} }
} }
} }
checkUpperBoundViolated(typeArgumentTypeRef, context, reporter, isIgnoreTypeParameters = isIgnoreTypeParameters) checkUpperBoundViolated(argumentTypeRef, context, reporter, isIgnoreTypeParameters = isIgnoreTypeParameters)
} }
} }
} }
@@ -5,22 +5,23 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.analysis.checkers.FirTypeRefSource import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.checkers.TypeArgumentWithSourceInfo
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.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
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.ConeInapplicableWrongReceiver import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableWrongReceiver
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.isTypeAliasedConstructor import org.jetbrains.kotlin.fir.resolve.isTypeAliasedConstructor
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.types.FirTypeProjection import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.FirTypeProjectionWithVariance
import org.jetbrains.kotlin.fir.types.toSymbol
object FirUpperBoundViolatedExpressionChecker : FirQualifiedAccessExpressionChecker() { object FirUpperBoundViolatedExpressionChecker : FirQualifiedAccessExpressionChecker() {
override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(expression: FirQualifiedAccessExpression, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -39,29 +40,46 @@ object FirUpperBoundViolatedExpressionChecker : FirQualifiedAccessExpressionChec
calleeSymbol = calleReference.candidateSymbol as? FirCallableSymbol<*> calleeSymbol = calleReference.candidateSymbol as? FirCallableSymbol<*>
} }
val typeArguments: List<FirTypeProjection>? val typeArguments: List<TypeArgumentWithSourceInfo>
val typeArgumentRefsAndSources: List<FirTypeRefSource>? val typeParameters: List<FirTypeParameterSymbol>
val typeParameters: List<FirTypeParameterSymbol>?
if (calleeSymbol is FirConstructorSymbol && calleeSymbol.isTypeAliasedConstructor) { if (calleeSymbol is FirConstructorSymbol && calleeSymbol.isTypeAliasedConstructor) {
typeArguments = null val constructedType = expression.typeRef.coneType.fullyExpandedType(context.session)
typeArgumentRefsAndSources = expression.typeArguments.map { typeArguments = constructedType.typeArguments.map {
FirTypeRefSource((it as? FirTypeProjectionWithVariance)?.typeRef, it.source) TypeArgumentWithSourceInfo(it, typeRef = null, expression.source)
} }
typeParameters = null
typeParameters = (constructedType.toSymbol(context.session) as? FirRegularClassSymbol)?.typeParameterSymbols ?: return
} else { } else {
typeArguments = expression.typeArguments typeArguments = expression.typeArguments.map { firTypeProjection ->
typeArgumentRefsAndSources = null TypeArgumentWithSourceInfo(
typeParameters = calleeSymbol?.typeParameterSymbols firTypeProjection.toConeTypeProjection(),
(firTypeProjection as? FirTypeProjectionWithVariance)?.typeRef,
firTypeProjection.source
)
}
typeParameters = calleeSymbol?.typeParameterSymbols ?: return
} }
// Neither common calls nor type alias constructor calls may contain projections
// That should be checked somewhere else
if (typeArguments.any { it.coneTypeProjection !is ConeKotlinType }) {
return
}
if (typeArguments.size != typeParameters.size) return
val substitutor = substitutorByMap(
typeParameters.withIndex().associate { Pair(it.value, typeArguments[it.index].coneTypeProjection as ConeKotlinType) },
context.session,
)
checkUpperBoundViolated( checkUpperBoundViolated(
expression.typeRef,
context, context,
reporter, reporter,
typeParameters, typeParameters,
typeArguments, typeArguments,
typeArgumentRefsAndSources substitutor,
) )
} }
} }
@@ -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<<!UPPER_BOUND_VIOLATED!>String<!>>(<!ARGUMENT_TYPE_MISMATCH!>""<!>) val x2 = <!UPPER_BOUND_VIOLATED!>N<String>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)<!>
val x3 = N2<<!UPPER_BOUND_VIOLATED!>String<!>>(<!ARGUMENT_TYPE_MISMATCH!>""<!>) val x3 = <!UPPER_BOUND_VIOLATED!>N2<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 = TC<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>() val y2 = <!UPPER_BOUND_VIOLATED!>TC<Any, Any>()<!>
val y3 = TC2<Any, <!UPPER_BOUND_VIOLATED!>Any<!>>() val y3 = <!UPPER_BOUND_VIOLATED!>TC2<Any, Any>()<!>
@@ -0,0 +1,16 @@
// !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: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>TC2<Number, 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>>()<!>
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER // !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER
class TColl<T, C : Collection<T>> class TColl<T, C : Collection<T>>
@@ -15,10 +15,10 @@ 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 = NA<<!UPPER_BOUND_VIOLATED!>Any<!>>() val test6 = <!UPPER_BOUND_VIOLATED!>NA<Any>()<!>
val test7 = NL<Int>() val test7 = NL<Int>()
val test8 = MMMM<Int>() val test8 = MMMM<Int>()
val test9dwd = NL<<!UPPER_BOUND_VIOLATED!>Any<!>>() 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>>) {}
@@ -28,4 +28,4 @@ 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, <!UPPER_BOUND_VIOLATED!>List<Any><!>>() val test16 = <!UPPER_BOUND_VIOLATED!>TC<Number, List<Any>>()<!>
@@ -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 = N<<!UPPER_BOUND_VIOLATED!>String<!>>(<!ARGUMENT_TYPE_MISMATCH!>""<!>) val testN1a = <!UPPER_BOUND_VIOLATED!>N<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 = MP<String>(<!ARGUMENT_TYPE_MISMATCH!>""<!>, <!ARGUMENT_TYPE_MISMATCH!>""<!>) val testMP2 = <!UPPER_BOUND_VIOLATED!>MP<String>(<!ARGUMENT_TYPE_MISMATCH!>""<!>, <!ARGUMENT_TYPE_MISMATCH!>""<!>)<!>
@@ -31,7 +31,7 @@ fun main1(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A<Int?><!>) {}
fun main2(x: A2<Int?>) {} fun main2(x: A2<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 = A3<<!UPPER_BOUND_VIOLATED!>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 = A<<!UPPER_BOUND_VIOLATED!>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 y: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!> = A3<<!UPPER_BOUND_VIOLATED!>Int?<!>>() val y: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!> = <!UPPER_BOUND_VIOLATED!>A3<Int?>()<!>
} }
@@ -31,7 +31,7 @@ fun main1(x: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A<Int?><!>) {}
fun main2(x: A2<Int?>) {} fun main2(x: A2<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 = A3<<!UPPER_BOUND_VIOLATED!>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 = A<<!UPPER_BOUND_VIOLATED!>Int?<!>>() val x2 = <!UPPER_BOUND_VIOLATED!>A<Int?>()<!>
val y: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!> = A3<<!UPPER_BOUND_VIOLATED!>Int?<!>>() val y: <!UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION!>A3<Int?><!> = <!UPPER_BOUND_VIOLATED!>A3<Int?>()<!>
} }